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

Re: Multiple values, revised proposal

Consider for a moment a language Dylan++ :-) that had the following

(1) #f is the only false falue

(2) #t is the only true value

(3) #none is returned by when, unless, and cond on the failure path.

(4) unspecified keyword parameters with no default value are
    assigned #none.

(5) If #none is passed as the value of a keyword parameter, and that
    parameter specifies a default value, then the default value is used.

(5) A new form, "apply-values" that looks like

	(apply-values function v1 v2 ... vk <form returning multiple values>)

    In common lisp, apply-values could be defined as:

	(apply function v1 v2 ... vk
	       (multiple-value-list <form returning multiple values>))

(6) A new form, "ensure-values" that looks like

	(ensure-values min max <form>)

    The "max" value can be given as #none to indicate no limit.
    In common lisp, with NIL used instead of #none, ensure-values
    could be defined as:

        (let* ((args (multiple-value-list <form>))
               (nargs (length args)))
	    ((< nargs min)
	     (apply #'values
		    (append args (make-sequence 'list (- min nargs)))))
	    ((and max (< max nargs))
	     (apply #'values (subseq args 0 max)))
	     (apply #'values args))))

Now, we can rewrite bind in terms of method application:

    (bind ((<parameter specification> <form>)) <stuff>)


    (apply-values (method (<parameter specification>) <stuff>)
      (ensure-values <number of required parameters>
		     <number of required parameters or #none
		      if #rest or #key is given>

This definition has the standard Dylan semantics as far as missing and
extra return values are concerned.  It also has the following nice

(1) Keword arguments can be used for both argument and return values.

(2) The "bind" form can now be treated as a macro.  Its semantics are
completely specified in terms of "method", "apply-values", and

(3) The defaulting and ignoring of return values is pushed into the
"syntactic sugar" of the language and is kept out of the core.

My personal preference would be eliminate the defaulting and ignoring
of return values.  The construct that David Moon mentioned in his
article could then be written using keyword result values:

  (bind ((frobby #key path-to-frobby (find-frobby name)))
    (if frobby
      ;; There is one
      (do-something-with name frobby path-to-frobby)
      ;; No frobby with that name exists
      (do-something-else name)))

  ;; Returns a value and an optional keyword result value
  ;;  The frobby with that name, or #f if there isn't one
  ;;  The path by which that frobby was found
  (define find-frobby (method (name)
    (bind ((x ..la de dah..))
      (when (umpty ump...)
        (when (something something something...)
          (bind ((frobby (do dah ...)))
            (unless (no-good? frobby)
              (values frobby path-to-frobby: (foo fah)))))))))

I find this quite clear and easy to write.

It could be argued that efficiency concerns prohibit using keyword
result values this way.  I'm not sure that I agree with that, but if
it was a concern I wonder if it doesn't apply to function call as
well.  For example, if Dylan really wants to support optional return
values, perhaps optional arguments should be put back in the language.
In that case, the example could be written as:

  (bind ((frobby #optional path-to-frobby (find-frobby name)))
    (if frobby
      ;; There is one
      (do-something-with name frobby path-to-frobby)
      ;; No frobby with that name exists
      (do-something-else name)))

which seems very clean to me.

-- Jim Mayer
                                        Phone: (716) 422-9407
Webster Research Center                 Intelnet phone: 8*222-9407
Xerox Corporation                       Internet Email: mayer@wrc.xerox.com
800 Phillips Road, 0128-29E             XNS Email: James L Mayer:Wbst128:xerox
Webster, New York 14580                 Facsimile: (716) 265-7133