[Grace-core] Match and generics

Kim Bruce kim at cs.pomona.edu
Fri Jun 10 00:43:24 PDT 2011


We're starting to think about implementing match, so I wanted to get the syntax correct and think through some of the decisions.  It made sense to try it out with the Option types, as that is likely to be the most likely use of match, as we avoid the use of null pointers.  Of course Option uses type parameters (the type parameter indicates the type of the value if it is different from the object None), so that has a few complicating factors..

Writing this out raised a number of questions about the design, embedded as comments below.  Please let me know what you think.

type Option<T> comprises Some<T>, None<T> {
   isNone: -> Boolean
   getOrElse: (T) -> T // argument is default value to return if receiver is None, 
                                     // otherwise returns value in the option (see code below)
}

// The result of this declaration indicates that Some and None are the 
// only classes that can implement Option<T>.  I don't know whether this
// should imply that Option<T> has no subtypes.  Otherwise we might
// accidentally define an type U that happens to extend Option<T> 
// and some classes that implement U.  
// If we used nominal typing then it would be easier to block any 
// type extending Option.  Semantically we could model the type as a bounded 
// existential to block extensions (whether in a nominal or structural regime)

object None<T> implements Option<T>{
   method isNone -> Boolean {return true}
   method getOrElse(default: T) -> T { return default }
   // we could make parameter to getOrElse have type of block instead, but not sure needed
}

// Note that this design gives a different None object for each type.
// Puzzle -- should this be written as a class since there are more than
// one??  It seems like it should because we will have an instance 
// variable representing the type T.  However, I'll leave it an object
// for now.

// To avoid having different None's we'd have to make Option covariant 
// in T and let None implement Option<Nothing> where Nothing is the "bottom" 
// type.  That way it implements Option<T> for all T.
// I lean toward defining it as above so we don't have to worry about 
// covariance annotations, but could be convinced otherwise.

class Some<T> {x:T ->
    const val = x
    method isNone -> Boolean { return false}
    method extract -> T { return val }
}

Let y: Option<Number>.  Then we can use it with match as follows:

match(y) {
    case { Some<Number>(n) -> ...n... }
    case { None<Number> -> ... }
}

// The spec doesn't indicate there should be curly braces around all the 
// case statements, but that seems necessary to delimit the scope of match,
// at least from a human reader's point of view.  The spec also uses "=>" 
// instead of "->", but I believe that was a typo.  (Though I wouldn't mind
// using "=>".)

// Note that a match based on the type of None<T>, which is Option<T>,
// does not seem as useful as the match based on the classes themselves.  
// While Some<T> has a type extending Option<T> 
// (it has the extra extract method), the test on classes seems 
// more appropriate.  In particular if you test for None's type before 
// Some's type then both kinds of objects will match None's type, really 
// confusing students.

Comments on the code and design?

Kim





More information about the Grace-core mailing list