2

I'm starting to realise that there is little distinction between value types and reference types if both are immutable. To test this, I wanted to see how a true lover of immutability like Clojure handles it. Unfortunately, I'm an ignorant C# programmer who speaks neither Java nor Clojure so my Googles have been unhelpful.

In C#, we have a distinction between value types and reference types. This is just the classic "pass-by-value" and "pass-by-reference" distinction. Does any analogous distinction exist in Clojure? I'm certain that it does in Java, although the terminology might not be the same. If it does exist in Clojure, does it only exist because of what it directly inherits from Java (e.g. by importing Java libraries?)?

J. Mini
  • 1,868
  • 1
  • 9
  • 38
  • The first paragraph on *value types vs reference types* and the second paragraph *pass-by-value vs pass-by-reference* are slightly different discussions although they are related. Regarding the first paragraph, do you know about [Valhalla](https://openjdk.org/projects/valhalla/design-notes/state-of-valhalla/02-object-model)? How equality works may be particularly interesting. As for the second paragraph, Java (and Clojure) is always pass-by-value as elaborated by [this answer](https://stackoverflow.com/a/40523/1008794). – Rulle Apr 14 '23 at 06:59
  • @Rulle All of that is news to me. – J. Mini Apr 14 '23 at 18:44

2 Answers2

4

Even in Java, the distinction doesn't really exist. Sometimes it is convenient to think of objects being passed by reference, in that I can pass an object to a method, the method can mutate the object, and I can see that mutation in the parent method. But really we've just passed the method a pointer to our object, by value, and it dereferences that pointer to modify it.

This may seem like splitting hairs: isn't an implicit pointer the same as a reference? No, because the method we call can't reassign the pointer for us, the same way that C# could with a ref parameter. For example, if I have an immutable type:

final class IntPair {
  final int x;
  final int y;
  IntPair(int x, int y) { this.x = x; this.y = y; }
}

and I pass such an IntPair to a method, I know its x and y fields will be unchanged. The type provides no way to mutate itself, and the language provides no way to replace the object with another.

Clojure inherits all of these semantics.

amalloy
  • 89,153
  • 8
  • 140
  • 205
1

Adding to the previous answer: in Java a "value type", is just a regular object that is final and allows no mutation. This provides the same semantics as a Clojure map, vector, etc. These "immutible objects" gained prominence in the realm of multi-threading since they avoided race conditions.

Background: When Java was first introduced, the "marketing" people made a big deal about Java having "no pointers", just "references" (unlike C/C++). Well kids, a Java "reference" is just a pointer on which you cannot call free or delete, etc. Note that this is not identical to a subroutine using "pass by reference" in C++ (or many older langs).

To reiterate, a "variable" in Java is a reference (aka pointer) to an object. If that object is an instance of an immutable class, it is called a "value object" or an instance of a "value type".

P.S. The above ignores primitive types like long. However, boxed objects like Long are the OG of immutable or "value" types.

P.P.S. If you truly want to "pass by reference" in Clojure with the goal of allowing a subroutine to mutate the value (eg "5"), then you will wrap the value in a Clojure atom like(atom 5), and pass that reference to the subroutine. The reference to the atom is immutable, but the contents of the atom can be mutated:

(ns tst.demo.core
  (:use tupelo.test))

(defn increment-arg
  [atom-ref] ; immutable reference to an `atom` holding a value
  (swap! atom-ref inc)) ; increment by +1 the contents of the atom

(verify
  (let [aref (atom 5)] ; reference to an atom holding the immutable value 5
    (increment-arg aref) ; call increment function on the atom reference
    (is= 6 (deref aref)) ;  extract current value from the atom
    ))

Example built using my favorite template project.

P.P.P.S. You can find more fine-grained details here.

Alan Thompson
  • 29,276
  • 6
  • 41
  • 48