[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Multiple values in Dylan



    From: moon@cambridge.apple.com (David A. Moon)
    Date: Mon, 26 Oct 92 13:46:59 EDT

    ... I think it's incumbent on anyone proposing significant language
    changes to give examples of how common usages would change under
    the proposal ...

OK.  My basic point was that we could make the language simpler, 
more elegant, and compiler-friendlier by cleaning up multiple values.  
Specifics: 

1. Ditch the part of BIND that allows extra values and fills in missing 
values with #f.  Allow BIND to take #key and #next.  Specify that 
VALUES must produce exactly the number and types of values that BIND 
is prepared to receive; VALUES and BIND must agree, just as APPLY 
and METHOD do.  Then there's only one protocol in the language for 
passing arguments. 

2. For the cases where you want to ignore extra values, we would 
add a macro or special form, e.g., (VAL1 expression), that takes 
an expression that produces at least one value, and returns the first 
value.  Something with this sort of effect (but done more efficiently): 

    (define-macro val1 (expression)
      (bind ((vals (gensym)))
        `(bind ((#rest ,vals ,expression))
           (first ,vals))))

Then you can write (* y (val1 (ceiling/ x y))), and you don't need 
to add "floor1", "ceiling1", "init-value1", etc. 

3. I don't think that VALUES would need to be a special form.  The 
compiler could be at least as smart about VALUES as it is about APPLY, 
which isn't a special form, either.  If, as the book suggests, 
DEFINE-GENERIC-FUNCTION had a standard option for specifying the 
number and types of return-values, the compiler could do a really 
good job of checking for errors, avoiding the allocation of #REST-sequences, 
etc. 


Comment: Careful readers of the manual may have noticed that the 
only built-in functions that return multiple values, besides VALUES 
itself, are INIT-VALUE, FLOOR, FLOOR/, CEILING, CEILING/, ROUND, 
ROUND/, TRUNCATE, and TRUNCATE/ (did I miss any?), so they might 
argue that this is a lot of fuss over an obscure feature of the language.  
But I've found them to be quite useful; they make the language more 
"functional", and they are certainly to be preferred over passing 
"VAR OUT" parameters. I've seen a lot of bad Lisp code where people 
cheated by adding extra return-values to encode obscure state-information, 
often not even documenting them in the "white pages", so that "normal 
users" would think there was only one value; this led to errors.  
Cleaning up multiple values would prevent that sort of problem. 

I've also programmed in languages where, in order to get the effect 
of multiple values, you defined a record-type that held exactly the 
right number and types of slots.  This is clean and works well, but 
it requires more verbose code, and it can waste storage allocation: 
in the typical case, the values are extracted from the record, immediately 
upon return, and bound to other variables.  Multiple values could 
simplify this usage as well. 

--Jim