Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Common Lisp: pass by value vs pass by reference [duplicate]

I want to write a function in Common Lisp, which destructively modifies its argument. In C or Rust I would use a pointer/reference to an object, which can be dereferenced inside the body of the function. In CL I write:

(defun foo (lst)
  (setf lst NIL))

But after evaluating this form:

(let ((obj (list "a" "b")))
  (foo obj)
  obj) => ("a" "b")

one sees that the function foo has no effect. I can explain that by pass by value semantic, where we modify a local copy of the argument pushed onto the function stack. If we define another function:

(defun bar (lst)
  (setf (car lst) NIL))

and evaluate a similar form

(let ((obj (list "a" "b")))
  (bar obj)
  obj) => (NIL "b")

we will clearly see that the lst was modified as if we would use the pass by reference semantic. So, (setf lst NIL) did not worked but (setf (car lst) NIL) did. Could you please explain why?

like image 939
IgSokolov Avatar asked May 21 '26 23:05

IgSokolov


1 Answers

Common Lisp passes arguments by value, but in most cases (other than primitive value types like fixnums or floats) the value is a reference. This is the same way that most managed languages work (e.g. Java, Python, JS).

In the LET-form, the value of the variable OBJ is a reference to a list, not the list itself. That reference is passed by value, so that inside the functions, the value of the parameter LST is another reference to the same list.

In FOO, the reference value is replaced with NIL, but the list that was previously referred to is not touched at all. In BAR, the list is retrieved from the heap and its CAR is replaced with NIL. Since OBJ holds a reference to the same list, the modification affects it as well.

like image 197
jkiiski Avatar answered May 24 '26 19:05

jkiiski



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!