But there're some language features in Scala I didn't expect and didn't think about before. The perfect example IMHO is covariant and contravariant subtyping I discovered for myself just a couple of days before.
Think about this example, if we have class B that inherits class A then we can use objects of type B whenever we need objects of type A. So far so good. But what if we have template class X with A and B as parameter types? C++ tells us X<A> and X<B> are unrelated:
class A {};
class B: public A {};
templateclass X {};
int main()
{
B *t1 = new B;
A *t2 = t1; //ok because B inherits A
X<B> *x1 = new X<B>;
//error!!! because C++ has non-variant subtyping
// so X<B> and X<A> are different types
X<A> *x2 = x1;
}
Contrary to that, in Scala you can declare that X[B] inherits X[A] and have covariant subtyping or even declare that X[B] inherits X[A] and have contravariant subtyping:
class A {}
class B {}
class X[+Type] {} // +Type means "covariant"
val t1 = new B
val t2 = t1 // ok, B inherits A
val x1 = new X[B]
val x2 = x1 // ok too because X[B] inherits X[A]
return
Not that some elements of covariance and contravariance of types didn't exist before in familiar languages like C++ and Java. Contrary to that they did, but most likely I woulnd't have learned about them if I didn't start learning Scala which directly exposes those things as language features. Cool language Scala is... I must say, very cool ;)

5 comments:
So, what happens if you do this:
vector<B*> *b = new vector<B*>();
vector<A*> *a = b;
a->push_back(new A);
b[0]->call_some_method_only_in_B()
Kaboom!
"Cool language Scala is... I must say, very cool ;)"
Master Yoda style? Nice.
mixb, that's a good example. Not all classes are covariant in their type parameter.
The Scala type checker will not let you mark a class covariant unless it is sure to be safe. If you attempted to encode that vector class in Scala, you would either have to leave out push_back, or you'd have to omit saying that vector is covariant with its type parameter.
Both choices are reasonable, and in fact the Scala collections library offers different collections making different choices here. Class List is covariant, but does not have any methods like push_back. Class ArrayBuffer is invariant, but does include methods like push_back.
-Lex Spoon
(I saw this post via Google blog search, and just thought I'd put in two cents.)
> Master Yoda style? Nice.
Hehe, I'm just an apprentice yet ;)
> So, what happens if you do this:
Indeed, as Lex pointed out that problem doesn't exist in Scala because typechecker is smart and restrictive... Now I'd like to know how it is done, but that requires reading something else than "Scala by Example" ;)
Btw, any suggestions on type theory book for mere mortals?
It seems a bit strange to me that you have to define in the template class itself if it is co- or contra-variant. In Java, you can handle any generic class co- and contravariant, with "wildcards", defined on the type of your variables.
class A {}
class B extends A {}
class X<T> {}
X<A> xa = new X<A>();
X<B> xb = new X<B>();
X<? extends A> myCovariant = xb;
X<? super B> myContraVariant = xa;
For example, it makes sense to handle a List both co- and contravariant.
From a List<? extends A> all elements you retrieve are subtypes of A (but you cannot add elements)
To a List<? super B> you can add any subtype of B (but you know nothing of the type of elements you retrieve)
Post a Comment