[Grace-core] Tuples - Re: [Minigrace] In praise of consistency

James Noble kjx at ecs.vuw.ac.nz
Tue May 29 17:45:55 PDT 2012


> Tuple-passing was in the spec at one point, but it gets very
> confusing. In particular, it seemed that Tuple had to be the top type
> or else single arguments wouldn't behave properly. There's no type
> information to disambiguate

So I'm trying to remember the issues around tuples.
I think there are two problems - consistency / ambiguity in the behaviour,
and efficiency of the calling conventions.   For now I'll ignore efficiency.

I think the problems relate to the interactions between varargs, type Dynamic,
and noples/oneples (as well as actual tuples) 

In general, we don't want types to affect the behaviour of a Grace program.
That means we can't use any information about types or parse code
(see other discussion) - and we can't use information about types to 
call other code *(OK, if we are in a VM or compile whole programs, we can.
A fast Grace system would need to do one or both of these things -
the question is how slow should a slow Grace system be).

What that means is that we have to have a single convention for "requesting"
any method, and however that is requested, a single interpretation for what
argument types mean.   Grace doesn't even have the distinction that Smalltalk
does between "print" (no arguments) and "print:" (one argument) because 
a single varargs "method print (*args)" declaration can respond to either request.

I'll elide questions of typing by making all formal parameter declarations type dynamic.
Given types shouldn't affect execution, the semantics - in this case, the actual object bound to 
the formal parameter in the method activation should be the same; types can only cause
a program to fail with a dynamic check. 

I'll also elide questions of syntax for now by using the "delimited argument" rule:
arguments must be in parens, quotes, or curly brackets.  Multiple arguments in
parens, separated by commas, but I'll write tuple instances in square brackets. 


Making this concrete, there seem to be three requesting cases - zero, one, and "many" (written 2) actual arguments

* R0  print 
* R1  print "hello"
* R2  print("hello",  234)    

For method definitions, there are again a bunch of cases:
 * M0 no parameters  - method print  {... }
 * M1 one parameter - method print(a) {...}      
 * M2 many (2) parameters - method print(a1,a2) 
 * Mv  varargs parameter - method print(*v) {..}

that gives us *12* cases (seems like a lot)  most but not all of which are OK.
Here are the combinations - organising this by method declaration seems to make more sense:

no parameter methods:
M0-R0 OK; 
M0-R1, error
M0-R2, error     // looks easy so far!

M1-R0 error      // still looks easy, but see *3 below
M1-R1 OK, formal a bound directly to object supplied as argument "Hello"  (but see *2 below)
M1-R2 error     // but *1 below for alternative "tupling" interpretation

M2-R0 error
M2-R1 error // *4 an odd? case
M2-R2 OK, formals a1 and a2 bound to objects supplied as argument "hello" and 234

Mv-R0 OK, formal v bound to empty list / nople []
Mv-R1 OK, formal v bound to singleton list / oneple  ["hello"]
Mv-R2 OK, formal v bound to two element list / tuple ["hello", 234]

That's what happens now, as I understand it.   Where does tupling come in? 
Well I guess the varargs methods _all already tuple_.  I think in the "forthcoming"
version of minigrace, with the "new AST"   all calls will be compiled tupled -
Michael is that right? 

Then the other cases seem to be the M1-R2 and M1-R1 case

*1 M1-R2 is a "method print(a)" called with two arguments --- or in tupling land, with one argument that is a tuple.   So what this says is if you have a method with a single argument of type dynamic,
it should receive that tuple.  So tupling would say that should work OK, that argument should be bound to the tuple - as in the variadic case.   That seems OK so far, but then...

*2 M1-R1 now we have an inconsistency.  An M1 declaration like  "method print(a)" 
 - call it with a single argument and the formal is bound to that argument
 - call it with more than one argument and the formal is bound to a tuple

is this really what we want?

*3 we could push this on further and say if you call print with no arguments, a single argument version could be called with the argument bound to a nople []. That's consistent, but it also seems like magic.

*4 if we tupled, then probably things like M2-R1   (method foo(a,b) requested as foo(z))
_would_ be OK provided the "z" evaluated to a tuple :-) 

Anyway: that's the design the problem I see with marrying single arguments + tupling with varargs and dynamic.  It's interesting that varargs works correctly but normal single arguments are inconsistent.  I don't know what Fortress or gBETA do - both of which tuple - but we could look.  gBETA doesn't have type dynamic, of course. 

On the implementation side, I think because any call can be variadic - with no special syntax on the calling side - that under the "new AST" the "calling convention" (requesting convention?) 
tuples up everything anyway - including single arguments into a oneple.  But i'm happy to be corrected!   This makes interoperability with almost anything harder.  

Smalltalk of course avoids these problems, with a hard distinction between zeroary and unary methods, and with varargs being done by explicitly passing a literal heterogenous array (effectively a tuple).  Other languages (Ruby?) effectivewly pass optional / keyword arguments as a literal map.

James




More information about the Grace-core mailing list