简体   繁体   中英

Common Lisp: pass by value vs pass by reference

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?

For some operations the usual style is this:

(let ((obj (list "a" "b")))
  (setf obj (nbar obj))  ; nbar is destructively modifying the list argument
  (foo obj))

Above uses SETF to use the return value to change the binding of obj , since the function nbar itself can't do it.

Since NBAR has no access to the lexical variable obj and thus can't change it, one is supposed to return the object from NBAR and then one sets the variable to the result value - overwriting the previous binding.

Examples, where this rule is applicable: calls to sort , nreverse , ...

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 (eg 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM