From ... From: Erik Naggum Subject: Re: reference parameter Date: 1999/10/21 Message-ID: <3149455958819483@naggum.no>#1/1 X-Deja-AN: 538640044 References: <380d6fbd@news.vtc.ru> mail-copies-to: never X-Complaints-To: newsmaster@eunet.no X-Trace: oslo-nntp.eunet.no 940467159 15184 195.0.192.66 (21 Oct 1999 00:52:39 GMT) Organization: Naggum Software; +47 8800 8879; +1 510 435 8604; http://www.naggum.no NNTP-Posting-Date: 21 Oct 1999 00:52:39 GMT Newsgroups: comp.lang.lisp * 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 ¶m), 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 ) ...)) 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