vityok wrote:I would like to ask whether it is possible to pass parameters to functions by reference?
As far as I understand, function call parameters (even vectors, sequences, etc.) are passed by value (the form is evaluated, yielding the vector, sequence, etc. and the value is passed as a function parameter).
It seems to me, that by passing vectors and sequences by reference, it would be possible to reduce cons'ing and memory usage.
The best way to think about this is that
all Lisp objects are allocated in the heap when they are created (even integers and characters), and they are always referenced by a pointer. The pointer is always passed to each function, so there isn't any copying involved (except for perhaps the pointer onto a stack, etc.). Now, putting everything into the heap creates garbage needlessly and is inefficient for some small data types (notably integers). Thus, most implementations actually fuse the small data types with the pointer for the sake of efficiency. A few of the low-order bits (called tag bits) are typically used to determine whether the pointer value is really a pointer value to something on the heap or a small immediate value. When Ramarren says that there are two types of objects, that's what he's referring to.
Now, because objects are always passed by reference, if you're working with a larger, aggregate object (list, vector, CLOS object, etc.), you can actually modify that larger object using mutable functions. Thus, it's quite common to pass vectors into functions where the data values in the vector are written with new values. With lists, because there is a lot of underlying structure there (linked cons cells), you have to be a little more careful about modifying them than with vectors. If you change the head of the list for any reason, the reference that the calling function had passed in is no longer valid and so you typically have to return a reference to the new list. Look at NCONC, for instance. It destructively joins the two lists, but it returns a reference to the new list.
Code: Select all
(setf foo '(a b c))
(setf bar '(d e f))
(nconc foo bar) ; <= error!!! The new head of the list may not be FOO
This code might work sometimes, on some implementations, but the right way to use this is:
Code: Select all
(setf foo '(a b c))
(setf bar '(d e f))
(setf foo (nconc foo bar)) ; <= correct
What are the general approaches to reducing memory usage by Lisp applications?
Generally, you can reduce memory consumption in similar ways as you would any GC'd language such as Java--by reusing data structures and destructively modifying them. You'll find a lot of duality in the Lisp library, where there are both pure functional library functions that create new lists (e.g. APPEND) as well as a destructive versions of the same operation (e.g. NCONC). As Ramarren said, though, you'd be better off not succumbing to premature optimization. Garbage does take time to collect, but depending on what your program is doing, that may or may not be very significant. Don't try to program Lisp like you would C, for instance. You'll end up creating a lot of bugs for yourself (accidentally modify something that you shouldn't) and it might not bring as much benefit as you'd like.
The SBCL implementation of Common Lisp has a good compiler, a good optimizer, and a generational GC. I would write your implementation in the most natural style and then use the profiler to figure out where the slow parts are after you have determined that the natural implementation style doesn't meet your performance goals.