GIGO: words unreadable aloud
Mishrogo Weedapeval
 

 

  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   comment/     


Click here to visit the Radio UserLand website. Click to see the XML version of this web page. © Copyright 2007 Doug Landauer .
Last update: 07/2/6; 12:37:00 .
Click here to send an email to the editor of this weblog.

February 2004
Sun Mon Tue Wed Thu Fri Sat
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29            
Jan   Mar

Previous/Next