[Grace-core] Class syntax and type parameters

James Noble kjx at ecs.vuw.ac.nz
Tue Nov 18 22:51:25 PST 2014


Hi all 

a summary & some more comments on the "square bracket" proposal:
 - brief intro
 - some precedents next, cos Kim asked for three know uses :-)
 - the details below, just copied out of a more restricted discussion to grace-core



Intro:
===

The idea is - for both generic types & classes - we'd write:
   Foo - for a nongeneric type, or a generic instiantiated all at Unknown
   Foo[Bar] - for an instantiated generic type 
likewise
  foo.new - to instantiate a nongeneric class, or a generic instiantiated all at Unknown (the name "new" is not special)
  foo[Bar].new - to instantiated a generic class at Bar

in both cases, the operational semantics are that Foo/foo denote an object, and [] is the "indexing request"

This would mean most students would *not* have to write generic _requests_ or _methods_  (as Marco has suggested)
This would require that we kept the [] indexing request in the language


Precedents:  ("three known uses") 
=======

* Omega, a statically-typed language based on Self by Gunther Blaschek used just this design
     although restricted to a single parameter:
      Array -- array of anything
      Array{Integer} -- array of integers
     (see http://www.ssw.uni-linz.ac.at/Teaching/Lectures/POPL/OOPwPT.pdf, in Background Papers)

* Beta and gbeta use generic instantiation is inheritance;
     at this level the designs work in the same way, modulo syntax.  
      SortedList -- a list you can put anything in 
      SortedList(# T::Integer #); -- a list of integers 

* Dylan  "<array>"  -- is an array that can hold anything, while
        "limited(<array> of: <single-float>)" -- can only hold single flotas


Actual Details:
=========

Square Brackets for Types
================

From: Michael Homer <Michael.Homer at ecs.vuw.ac.nz>
Subject: [Grace-core] [] for types' type parameters (with possible application to classes)
Date: 14 November 2014 12:31:11 pm NZDT

Instead, we could have (reified) types consistently be objects,
generally bound to names. Providing them with generic parameters would
use an ordinary method call. A plausible method to use is the existing
postcircumfix [] operator from the specification.

In this case we would fully abandon the use of <> for generic type
parameters on types. <> would be reserved for declaring and requesting
methods only. Types would always use []. Static typing would be
exactly the same as it has been, with just the syntax different.

Given a type currently written:
  type List<T> = type { first -> T ... }
there is be an object in existence representing the type. That object
is bound to the name "List". It is, itself, a pattern, matching
List<Unknown> (that is, all lists).

In this design the object would also have a method [], which would
specialise the type according to the provided parameters. It would
return an object representing the newly-instantiated type. The
implementation of [] would be internal, and memoise the results. So:
  def ListOfStrings = List[String]
will create an alias for the instantiated type, while
  def MyList = List
will alias the uninstantiated type - these are always genuine object
references. In both cases, the same object will always be returned.
Importantly, the "MyList" alias can be specialised in exactly the same
way, because it is a real object alias.

All occurrences of parameterised types would use the same syntax:
  var x : List[String] := ...
  method lengths<T <: Measurable>(l : List[T]) -> List[Number] { ... }
  type Listable[T] = type { asList -> List[String] }
But to request the "lengths" method, you would still use <>:
  lengths<String>(x)
In this way types and methods are clearly separated, and types are
always first-class.

This also raises some possibilities of higher-kinded types, because
objects can be passed around and have methods requested of them in the
ordinary way. That might be useful in some cases. It's unclear whether
it should be possible to re-specialise the type:
  def ListOfStringNumbers = ListOfString[Number]
If it is possible to do, the types should probably be &ed together.

It is possible that this same approach could be applied to classes, if
instantiating generic parameters on the class itself is considered
useful. The class would be an object, able to be specialised by
requesting its [] method, or instantiated with its constructor method.
This complicates the encoding, but retains the class as a first-class
object.




Square Brackets for Classes
=================

(this expands on the last para of MIchael's email above)

From: James Noble <kjx at ecs.vuw.ac.nz>
Subject: Re: [Grace-core] Class syntax and type parameters
Date: 14 November 2014 9:37:29 pm NZDT

the code is below: basically one writes

box.new(i)                      to get a Box (aka Box[Unknown] initialised to i
box[Number].new(23)     to get a Box[Number}

so this syntax lines up quite well with the postcircumfix type syntax.

This does provide a reason for keeping dotted classes
(Michael's arguments this morning at least half reconvinced me to
head back to undotted classes-as-methods)
and the "class macro syntax" would get a bit odder...

class box[T].new(init} {
  var value : T := init 
  method get -> T {value}
  method set(newValue : T) -> Done {value:=newValue}
} 

could expand to something like:

def box = object {
  method new(init) typed(T) {
      object {
          var value : T := init 
          method get -> T {value}
          method set(newValue : T) -> Done {value:=newValue}
      }
  }

  method new(i) {new(i) typed(Unknown)} 
  method [](t) {
        object {
            method new(i) {outer.new(i) typed(t)}
        }
  }
}

def b1 = box.new("hello") //new Unknown box

def b2 = box[Number].new(23) //new box of Numbers


More information about the Grace-core mailing list