From: David C. <dc...@us...> - 2009-07-07 00:46:31
|
> Yes, tagged unions are orthogonal. > > The proposal is really saying that if we focus on permitting inlined T > only when T's fields are all val then there is no difference with the > primitives proposal. But that is just a side comment, it doesnt change > the proposal. There are some remaining differences, nothing to do with tagged unions: * The programmer has to decide in advance if a class is ever to be inlined, and define it as a primitive instead of as a class. As such, one cannot just inline a 3rd-party library class if they feel like it. * We will find it easier to omit vtable pointers in the first iteration (and therefore will not need to special-case int for November). > The main additional point in the 1:36 pm message is that in fact we can > support struct T for those T which are not final as long as we insist > that all the struct T types are exact. (I believe Olivier and Nate knew > this/proposed this as well.) This makes it easier to support classes > which are generic on either classes or structs. Yes, this is pretty obvious I think. If you followed that discipline when programming C++ then you would get this behaviour. I think there is only one thing that has been proposed, that is not supported directly by C++ in some way. This is why most of what has been proposed has compiled down to C++ very easily. The one thing I can think of: We want to support the omission of vtable pointers from inlined instances of classes. C++ doesn't need this because in C++ the programmer can define classes that do not have any virtual functions, thus have no vtables. In X10 this would not be possible since every class has at least the virtual functions inheritted from Object. You could argue C++ has something like the primitives proposal, but it is a lot more powerful since its primitives can have mutable fields, and support inheritance. If we are *not* getting rid of the vtable pointer from inlined instances of classes, and inlineable classes must be immutable (this I believe is the proposal for November), then there is nothing in that proposal that is not supported directly by C++. C++ is more powerful, however, since it supports inlining of mutable classes. There are other C++ features that these proposals could potentially support but I don't think they would give a big boost to expressive power. > The main thing you need to watch out for as an X10 programmer is that if > you write a generic class such as: > > typedef Pair[X,Y](x:X,y:Y)= Pair[X,Y]{self.x==x, self.y==y}; > class Pair[X,Y] (x:X,y:Y){ > def this(x:X, y:Y): Pair[X,Y](x,y) { > property(x,y); > } > def x()=x; > def y()=y; > } > > which has fields defined at generic types, then the behavior of the > class instantiated on structs is going to be slightly different from the > behavior of the class instantiated on classes. e.g. > > typedef a = struct A; > val a:A = ...; > val b:B = ...; // assume B extends A > val ab1 = new Pair[A,A](b,b); // ok > val ab2 = new Pair[A,A](a,a); // ok > val ab3 = new Pair[a,a](b, b); // not ok. > val ab4 = new Pair[a,a](a,a); // ok > This is identical behaviour to C++ except the ab3 version is allowed in C++ (it slices). So C++ is a superset of X10. Arguably the slicing is not very useful, so I would be in favour of disallowing it as a type error. If the programmer actually wants to slice, they can fill in the fields manually. I think the loss of mutable fields in inlined instances is a much more significant difference between C++ and X10. For curiosity, here is the C++ version of the above code: template<class X, class Y> class Pair { public: X x; Y y; Pair (X x_, Y y_) : x(x_), y(y_) { } X getX() { return x; } Y getY() { return y; } }; class A { int f; }; class B : public A { int g; }; int main(void) { A *a = new A(); B *b = new B(); Pair<A*,A*> *ab1 = new Pair<A*,A*>(b,b); // ok Pair<A*,A*> *ab2 = new Pair<A*,A*>(a,a); // ok Pair<A,A> *ab3 = new Pair<A,A>(*b,*b); // not ok. (works in c++, discards g field) Pair<A,A> *ab4 = new Pair<A,A>(*a,*a); // ok } |