Subject: Re: reference parameter
From: Erik Naggum <erik@naggum.no>
Date: 1999/10/21
Newsgroups: comp.lang.lisp
Message-ID: <3149455958819483@naggum.no>

* Arseny Slobodjuck
| I am a novice in Lisp, can somebody help me with such a question?
| I need a function, which will modify given parameter(s).  In C++ i has
| wrote: int func(int &param), can i do this in Lisp or "i still thinking
| procedurally"?  I using xlisp 2.1.

  as with any "I have X in language L1, so I need X in language L2" request
  you will succeed only at random in getting what you only think you want.
  rather than this first-level approach to comparisons, try "I solve some
  problem A with X in language L1 -- is A solved with X in L2, or some
  other way?"  you don't need to do the introspection part that actually
  answers what A is, obviously, but you need to be aware of the different
  level of the question you're asking just so you are able to appreciate
  the answers you get that don't match with the first question.

  references in C++ are used to return non-primary values from a function.
  C++ needs this because it has no better mechanism of dealing with more
  than one return value from a function.  a reference is fundamentally a
  mechanism used to send a lexical variable to an inferior function so that
  it can be modified in a different lexical scope than binds it.  now, this
  has a number of interesting ramifications for control flow analysis and
  program design in general, but C++ programmers aren't aware of these.  in
  less immature languages with the same desire, they have opted for naming
  the variables "in", "in out", or "out" according as the direction of
  their value flows across the function call boundary.  this is obviously a
  very useful thing to know about variable bindings that you give away for
  others to mess with that C++ also completely lacks,  unsurprisingly.

  in Common Lisp, you can obtain this behavior with closures, but we need
  to know whether the binding is going to be used for incoming, outgoing or
  both.

(defun foo (in out in-out)
  (... in ...)				;use value of IN
  (funcall out ...)			;set value of OUT
  (... (funcall in-out) ...)		;use value of IN-OUT
  (funcall in-out ...))			;set value of IN-OUT

  as you can probably guess, there are good reasons why Common Lisp
  programmers don't do this (but you might see Scheme aficionados argue
  that it's a great idea in Scheme because they don't need the FUNCALL :).

  instead, Common Lisp programmers approach the problem from the
  perspective where _control_ over the binding remains confined to its
  lexical scope, and it's none of the callee's business to know that a
  particular variable is to be reused with a new value.  so instead of
  focusing on what FOO would do, let's look at what BAR, which calls FOO
  would do, first in the above sense, and then in the normal Common Lisp
  sense:

(defun bar ()
  (let ((a b c))
    (foo a
	 (lambda (new) (setf b new))
	 (lambda (&optional (new nil set-p)) (if set-p (setf c new) c)))))

  this is clearly in need of some macrologic wrappers to make sense to work
  with at all, but it's also inefficient (although it could be made fast),
  so instead we have opted for a much simpler mental model of dealing with
  such mutable bindings:

(defun bar ()
  (let (a b c)
    (setf (values b c)
      (foo a c))))

  FOO would now be defined simpler, too:

(defun foo (in in-out)
  (... in ...)				;use value of IN
  (... in-out ...)			;use value of IN-OUT
  (values out in-out))			;return values for OUT and IN-OUT

  in the more common case, you have a much simpler way to specify which
  bindings are to apply:

(defun bar ()
  (multiple-value-bind (b c) (foo <value-of-a> <value-of-c>)
    ...))

  and skip the variable thing altogether.

  the morale of this story is that if it's a good idea in C++, it's very
  likely to be a bad idea somewhere (if not everywhere) else, because they
  have voluntarily decided against good design at the core language level,
  and therefore have to solve problems by riveting on layer upon layer with
  special features and magic that people think are The Solution, when in
  fact C++ is only really good at creating new problems that confuse people
  when they come to better-designed languages.

  of course, once you realize what multiple values are and how C++ sucks,
  you'll have a hard time working within the stultifying C++ environment
  again, so if your goal is really to continue writing C++ programs, you
  might want to stop working with Common Lisp right away...  of course,
  XLisp is not Common Lisp, so you might not have to give up C++ just yet.

#:Erik