[Grace-core] reified generics -- good news / bad news
James Noble
kjx at ecs.vuw.ac.nz
Thu Oct 6 04:06:41 PDT 2011
Hi all
so thinking about "new" & reified generics
- the question from the minutes about "what does Factory<Types>.new(args) mean"
well based on the current spec - explaining classes by expanding out to objects:
the basic expansion currently in the spec is:
def CatFactory = object { // the cat factory
method new(aColour: Colour, aName: String) -> Cat {
return object { // the cat herself
def colour : Colour := aColour
def name : String := aName
var miceEaten := 0
}
}
}
we could make it generic (in "Colour" for some odd reason) just like this -
the trick here is the "new" method is generic, so you'd have to write
CatFactory.new<Colour>(Green, "mimi"):
def CatFactory = object { // the cat factory
var instanceCount := 0
method new<T>(aColour: T, aName: String) -> Cat[T]
where T <: Colour
{instanceCount := instanceCount + 1
return object { // the cat herself, now generic
def colour : T := aColour
def name : String := aName
var miceEaten := 0
}
}
}
this all seems straightforward, instanceCount would count
instances irrespective of their generic types.
But we'd have to write "CatFactory.new<Colour>(Green, "mimi")"
to make new objects.
we can get around that problem to write CatFactory<Colour>.new(Green, "mimi")
by making the CatFactory generic like this**:
def catFactoryMap = Map<Type, CatFactory<Dynamic>> // somewhat evil that Dynamic in there...
method CatFactory<T> -> CatFactoryType<T>
where T <: Colour
{return // probably need a type assertion of some kind in here, but would never fail.
catFactoryMap at(T) ifAbsentPut {
object { // generic cat factories :-)
var instanceCount := 0
method new(aColour: T, aName: String) -> Cat[T] {
instanceCount := instanceCount + 1
return object { // the cat herself
def colour : T := aColour
def name : String := aName
var miceEaten := 0
}}
}
}
}
except I'm not quite sure this does what we want. Certainly the "T"
generic parameter should be captured properly.
The first problem is that if we're not careful, every *invocation* of CatFactory<T>
would return a *new* CatFactory object. (The instanceCount of
almost every factory will only ever be 1). To fix that,
I build a map from actual T values to objects (that's
the catFactoryMap and what at()ifAbsentPut does)
effectively lazily creating the type-specific factories.
This would also mean that the instanceCount variable
in each type-specific factory would mean something useful -
the map would assure there was only one
So I think we can make this work too. That's the Good News -
we can do this at least two ways. What's the bad news:
well, that especially the second case, but with a bit of thought, more generally
*when any program actually relies on reified generics - the program's
behaviour would be changed if the types were erased or all set to dynamic*
Basically two of our principles "reified generics" and "operational semantics
independent of types" doesn't seem to work. Or at least, they don't work
if your computation can ever depend on the value of the reified generics.
But if they can't, what's the value of reification? As John B put it last week -
we're back to Erasure. oops.
=======
*assuming type declarations like this:
type Cat[T] = {
colour -> T
name -> String
miceEaten -> Number
miceEaten:= (_:Number) -> None
}
type CatFactoryType = {
new<T>(_:T,_:String) -> Cat[T]
}
**assuming type declarations like this:
type Cat[T] = { // same as above
colour -> T
name -> String
miceEaten -> Number
miceEaten:= (_:Number) -> None
}
type CatFactoryType[T] = { // different, now generic too
new(_:T,_:String) -> Cat[T]
}
More information about the Grace-core
mailing list