|
|
Wednesday 4 February 2004
|
Scala as a LotY
Here's most of a posting I sent to the pragprog list tonight.
I hope I didn't butcher it too badly in converting it to
Radio UserLand's "HTML-lite".
The front page of the scala site, http://scala.epfl.ch/ ,
has a pretty nice intro to various aspects of the language, broken
into short, mostly easy-to-digest pages. In particular, the pages
about generics are well-written and pretty clearly motivated. They
are these:
- Generics, http://scala.epfl.ch/intro/generics.html
Scala's syntax for generic types looks somewhat like Eiffel's
generics: Stack[T] in the definition, and Stack[Int] in the use.
By default, subtyping of generics is invariant (with respect to the
type parameter), but that can be overridden. (I.e., even though
Char is a subtype of Int, Stack[Char] is not a subtype (nor a
supertype) of Stack[Int]. Can be overridden by variance
annotations on the definition (not the use, as in Java 1.5).)
- Upper type bounds, http://scala.epfl.ch/intro/upbounds.html
In generic types, an upper bound on a type parameter looks like
class Stack[ T <: U ] { ... }
and just means that the type parameter T for this generic Stack
class must be a subtype of U.
However, upper and lower type bounds can also be used in the
declarations of abstract types in traits, and it looks to me like
they'll yield a very rich set of combinations among traits,
constrainable abstract types, and generics (including generic
traits). I haven't yet thought through the possibilities here.
- Lower type bounds, http://scala.epfl.ch/intro/lowbounds.html
Lower type bounds, as in
class Foo[ U >: T ] { ... }
mean that the type parameter U for this generic Foo class must
be a supertype of T. I suspect that it won't be used in that sort
of position much. Here's the motivating example from the
lowbounds.html page:
case class ListNode[+T](h: T, t: ListNode[T]) {
def head = h; def tail = t;
def prepend[T](elem: T): ListNode[T] = ListNode(elem, this);
}
Suppose we'd like to make ListNode[T] covariant in T
(i.e., ListNode[T] would be a subtype of ListNode[U] if
T is a subtype of U). The "+T" annotation on ListNode's
parameter expresses this desire. But we can't do that,
because the type of prepend's parameter T is used in a position
that is not a "covariant position". Replacing prepend with:
def prepend[U >: T](elem: U): ListNode[U] = ListNode(elem, this);
solves this problem. I still have to ponder exactly what are
"covariant positions", though.
- Variance annotations, http://scala.epfl.ch/intro/variances.html
If the definition of Stack[T] said Stack[+T], it would mean that
a Stack[P] is a subtype of a Stack[Q] if P is a subtype of Q.
That's a covariant annotation. There's a contravariant version
as well ("-" instead of "+"). I haven't yet thought up any
reasonable places where I'd want to use that one.
10:34:48 PM
|
|
|
|
© Copyright
2007
Doug Landauer
.
Last update:
07/2/6; 12:37:00
. |
|
|
|
|