<p>I'm a big fan of Algol 68's treatment of variables. &quot;Variables&quot; are just constant references that point to memory allocated on the stack or on the heap. When you refer to a variable or a component of one, the result is of type &quot;reference to T&quot; instead of T directly; but values of type &quot;reference to T&quot; will be coerced into values of type T automatically. There is no need for an &quot;address of&quot; operator. In assignment and parameter passing, objects are copied (but a copy of a reference points to the same object as the original). Variable bindings always have dynamic extent (no closures); objects have indefinite or dynamic extent depending on whether they are heap- or stack-allocated. See the bottom of the post for more details about Algol 68.</p>
<p>I'm also a big fan of variables in Lisp and most dynamic languages. It's sometimes called &quot;pass-by-sharing&quot; or &quot;pass-by-identity&quot;. Assignment and binding cause variables to hold the same object, instead of a copy. This essentially necessitates working with references to objects instead of objects directly. Bindings and objects have indefinite extent.</p>
<p>In my language, I have Lisp-style variables. Recently I've been contemplating adding references in order to increase its expressive power (e.g., the assignment operator can be described using the language itself<sup>*</sup>, since I have user-defined operators). However, I would want references to behave as in Algol 68 (or C++), with automatic dereferencing. But with Lisp-style variables, every binding has an implicit additional level of indirection, and the two ideas don't seem overly compatible.</p>
<p>Should I work the Lisp-variable-ness into the coercion process along with dereferencing? (Thereby adding one more level of indirection to Algol-style variables.) Is there prior art for that? Or an alternative to references that generalizes lvalues and expressions and allows the assignment operator to be defined.</p>
<p>I'm also not positive about how references interact with indefinite extent bindings and closures. Like, can a local variable escape its scope by assigning a reference to it to an outer variable? Should bindings have dynamic extent unless captured in a closure?</p>
<hr />
<p>* A procedure to implement the operator would require support from the runtime/compiler, but its type can be expressed and lvalues can be consistently defined if the language has references.</p>
<hr />
<p>Algol 68 is decently obscure these days, so here's some more information about how it deals with variables. Note that actual Algol 68 terminology is idiosyncratic and I'm &quot;translating&quot; it here to be more widely understood.</p>
<p>The simplest kind of declaration in Algol 68 is the &quot;identity declaration&quot;, which corresponds roughly to a constant in other languages:</p>
<pre>
<b>int</b> i = 1;
</pre>
<p>This means that <code>i</code> is synonymous with the value of 1. More complicated example:</p>
<pre>
<b>real</b> circumference = 2 × 3.14 × r;
</pre>
<p>The right hand side of the <code>=</code> is evaluated and &quot;ascribed&quot; to the identifier on the left, so that they are equivalent in expressions. The computation of the value may involve side effects and need not be possible at compile time.</p>
<p>When an identifier has been introduced in an identity-declaration, it is conceptually replaced by its meaning every time it is applied. Re-declaring the same identifier creates a new binding.</p>
<p>To construct an object of a given type in Algol 68, you use a &quot;generator&quot;, which looks like <code><b>loc</b> ⟨type⟩</code> or <code><b>heap</b> ⟨type⟩</code>. Where the object is allocated is determined by whether you write &quot;<code><b>loc</b></code>&quot; (value is on the stack with dynamic extent) or &quot;<code><b>heap</b></code>&quot; (value is in heap with indefinite extent). The result of a generator is a value of type &quot;reference-to-⟨type⟩&quot;, which is conceptually just a pointer to some part of the machine's memory. To express a reference type in Algol 68, write &quot;<code><b>ref</b> ⟨type⟩</code>&quot;.</p>
<p>Operations like array subscripting yields a reference, because it denotes a location in memory. Thus if you have an array <code>A</code> holding <code><b>int</b></code>, then <code>A[2]</code> would yield a value of type reference-to-<code><b>int</b></code>.</p>
<p>Algol 68's assignment operation is defined to operate on values of type &quot;reference-to-t&quot;. For example,</p>
<pre>
(<b>heap</b> <b>int</b>) := 5
</pre>
<p>is like</p>
<pre class="lang-c prettyprint-override"><code>*(malloc(sizeof(int))) = 5
</code></pre>
<p>in C; in both languages, it allocates space for an integer in the heap, stores 5 there, and promptly forgets about it.</p>
<p>Algol 68 assignment always copies the value.</p>
<p>As a consequence, you can get an <b>int</b> &quot;variable&quot; by writing</p>
<pre>
<b>ref</b> <b>int</b> i = <b>loc</b> <b>int</b>;
i := 5
</pre>
<p>This means &quot;declare <code>i</code> as constantly holding the value resulting from evaluating <code><b>loc</b> <b>int</b></code>, which will be of type reference-to-<b>int</b>; then store the value 5 in the memory location just ascribed to <code>i</code>. The value (a pointer) ascribed to <code>i</code> will not change as long as it is in scope; but the value <code>i</code> points to may vary. The assignment construct <em>evaluates</em> the left-hand-side to obtain a reference; there is no special case for when the destination of an assignment is an identifier.</p>
<p>Such notation is common enough that there's syntactic sugar (the initializer <code>:= 5</code> is optional):</p>
<pre>
<b>loc</b> <b>int</b> i := 5;
<b>heap</b> <b>int</b> j := 5;
</pre>
<p>In fact, the <code><b>loc</b></code> or <code><b>heap</b></code> may be omitted, in order to make code look more like Algol 60.</p>
<p>All this is fine, but we still don't really have an &quot;<code><b>int</b></code> variable&quot;. We have a constant reference-to-<code><b>int</b></code>. Theoretically, that means you'd have to dereference <code>i</code> anytime you don't want to assign to it (which is probably the more common case). Instead, Algol 68 defines a coercion from any type reference-to-⟨type⟩ to ⟨type⟩, which gets applied whenever necessary. In other words, dereferencing is automatic; in fact there is no way to dereference a value explicitly. Note that there is also no address-of operator, since anything we could meaningfully take the address of (variable names, array slices, fields of structures, etc.) already happens to yield a reference.</p>
<p>As a consequence of this system, classic problems are easily accounted for:</p>
<pre>
<b>if</b> p(x) <b>then</b> a <b>else</b> b <b>fi</b> := 10;

<b>proc</b> swap integers(<b>ref</b> <b>int</b> a, b) <b>void</b>:
  (<b>loc</b> <b>int</b> t := a; a := b; b := t);

<b>loc</b> <b>int</b> i := 1, j := 2;
swap integers(i, j)
</pre>
<p>The first line is like <code>*(p(x) ? &amp;a : &amp;b)</code> in C.</p>
<p>A &quot;pointer to a variable&quot;, rather than to a memory location created by a generator, is of type reference-to-reference-to-⟨type⟩. Another way to think about this is as &quot;non-constant references&quot;.</p>
<pre>
<b>loc</b> <b>int</b> v := 10, w := 11;
<b>loc</b> <b>ref</b> <b>int</b> p;
p := v;
print(p);
p := w;
print(p)
</pre>
<p>The assignments to <code>p</code> copy the references ascribed to <code>v</code> and <code>w</code>. Note that the declaration of <code>p</code> is equivalent to</p>
<pre>
<b>ref</b> <b>ref</b> <b>int</b> p = <b>loc</b> <b>ref</b> <b>int</b>;
</pre>

<language-design><semantics><references>
References in a language where everything is a reference?
CC BY-SA 4.0
2024-12-27T13:23:26.573Z
The explanation of binding semantics in Algol 68 seems sufficiently long to warrant a separate Q&A pair. (Something like a self-answered “How do identifier bindings work in Algol 68 and do how they compare to modern languages?”, probably.)
user3840170
<h2>Disentangling variable semantics from calling conventions</h2>
<p>First off, I want to caution against confusing the semantics <em>of variables and types</em> with semantics <em>of parameter passing</em>. In Lisp (and Python, and for most types in Java, and for selected types in C#), variables have <em>reference semantics</em>, i.e. the rule that &quot;variables hold references and assignment copies the reference&quot;. <strong>Reference semantics are particularly common in dynamically typed languages</strong>, simply because the assigned value might use a different amount of memory than the original value for its underlying representation; since indirection is generally required anyway, it may as well be used to avoid unnecessary copying.</p>
<p>So-called <strong>&quot;pass-by-sharing&quot; or &quot;pass-by-identity&quot; is really pass by value</strong> in a context where the passed value has reference semantics. In an earlier era, people thought the terminology &quot;pass by value&quot; was confusing for such languages; but as originally defined, it's a perfect fit. Another more modern term is &quot;pass by assignment&quot; - meaning that passing an argument to a parameter works the same way as assigning a value to a variable.</p>
<h2>Evaluating reference types in C++</h2>
<p>As for the main question: true pass by reference is quite rare in contemporary languages, and the C++ implementation is <em>weird</em> and arguably not quite the same thing. (I'm not familiar with Algol 68, but I'm inferring from your description that it works substantially the same way as in C++). Conceptually, &quot;pass by reference&quot; should be a <em>parameter passing convention</em>, <strong>but C++ models this by making &quot;references&quot; into a separate <em>type category</em></strong> (and further confuses things by adding this to a language that <em>already</em> has &quot;pointers&quot;, which in generic computer science discussion would be considered a form of &quot;reference&quot;).</p>
<p>This approach accomplishes the goal of enabling &quot;operator overloading&quot; for assignment. Perhaps a more classic test - which can be applied in a more language-agnostic way - is that this scheme allows for writing <strong>a &quot;swap&quot;</strong> function that swaps the values of two of the caller's variables. This <strong>can't happen with pass-by-value, even when the values have reference semantics</strong>, because the function is given different references. But C++ causes assignments to the reference, to affect the referred-to original value, rather than changing the referent (&quot;re-seating&quot; the reference, in the terminology of the C++ FAQ Lite).</p>
<p>And that causes all manner of problems when one tries to develop a proper mental model. C++ references <strong>can <em>to some extent</em> be treated like <code>const</code> pointers, except</strong> that they can't legally be NULL or dangling, and attempting to use them inserts indirection into the code that isn't actually there, and you can write an assignment even though it's <code>const</code> because it actually assigns to the indirected target. But on the other hand, <em>there might not actually be a value there at all</em> after even the most basic compiler optimizations. <em>Unless</em> the reference is a member of a data structure somewhere, in which case it might have to exist just to take up space and have an address (which must be distinct from the addresses of other members).</p>
<p>It's really a quite complex idea. And that's without even touching on the issue of &quot;bindings and closures&quot;, as you mention it - i.e., the lifetime of the referent vs. its references. This is especially complex without garbage collection, but I expect it would still be a massive headache in a garbage-collected language that implemented references this way. C++ ends up needing special rules like <a href="https://stackoverflow.com/questions/1565600">this one</a> and <a href="https://stackoverflow.com/questions/7657682">that one</a>. I'm afraid I can't tell you anything useful about how to implement that sort of thing.</p>
<h2>Discussion and alternatives</h2>
<p>Personally, I don't think that contemporary languages with reference-semantics variables benefit much, if at all, from support for pass by reference. Users can always just wrap the value in a container, which is passed by value and modified by the function; or the calling code can assign back whatever returned value. Being able to <em>modify</em> the passed-in object is generally sufficient for typical programming idioms; things that can't work this way often have separate support (for example, Python has a multiple assignment idiom that makes a theoretical <code>swap</code> function sound clunky and useless).</p>
<p>I suspect that <strong>a major reason why true pass-by-reference has become so rare is</strong> because it can make programs very difficult to reason about, by <strong>breaking the encapsulation</strong> of functions. It's already considered poor practice to have &quot;mutable shared state&quot; without well-defined boundaries - for example, to have functions that communicate by modifying a global variable. Re-assigning a variable from an enclosing lexical scope (rather than, say, an attribute of an object, within the code for a method) is already a major source of bugs. <strong>True pass by reference entails</strong> something like the dynamically scoped equivalent of that - <strong>modifying a variable from</strong> the caller, i.e., <strong>an enclosing dynamic scope</strong>. It effectively introduces a dynamic scoping concept into an otherwise lexically scoped language. Dynamic scoping is <em>also</em> an increasingly rare language feature, so this could easily be counted as another strike against pass by reference.</p>
<p>That said, if you really want the kind of flexibility and semantics that you describe, I would strongly encourage you to <strong>instead consider how C# implements pass-by-reference</strong>. C# allows for types that have value semantics as well as those with reference semantics - called &quot;value types&quot; and &quot;reference types&quot;, respectively, in documentation. (I couldn't use these terms before, since &quot;reference type&quot; means something fundamentally different in C++.)</p>
<p>More importantly for the current discussion, it also allows for passing either by reference or by value, as well as supporting &quot;out parameters&quot; (functionally pass by reference, except that the passed-in value may not be used and thus is not required to be initialized). To avoid surprises (and perhaps ease compilation - I don't know any relevant implementation details), <strong>the calling convention must be marked on both the function and the caller</strong>.</p>
<p>And, crucially, pass by reference is treated as a <strong>true calling convention, and not a property of types</strong>. You can pass the same value by value or by reference to different functions, and you can do this with both value types and reference types. It's especially useful for value types, since it allows for <em>modifying</em> the passed-in value <em>as well as</em> replacing it. (Passing a reference type by value allows for modification, but not replacement. But keep in mind that such modifications can be &quot;seen&quot; by other potential referers, too, whereas replacement would not be.)</p>

CC BY-SA 4.0
2024-05-22T01:30:38.817Z
2024-12-27T23:23:48.027Z
2024-12-27T23:23:48.027Z
Karl Knechtel
CC BY-SA 4.0
2024-05-22T20:44:13.047Z
Algol 68 references are similar to C++'s but they're more consistent because the language was designed around them (think BLISS or MDL, except they require explicit dereferencing), whereas in C++, as you point out, references were just shoved into a language that already had pointers. In Algol 68, references are tightly integrated into the type system.
texdr.aft
CC BY-SA 4.0
2024-05-22T21:19:38.493Z
If they require explicit dereferencing, then aren't they basically just "safe" (restricted) pointers? In that case, if added to a system where variables have reference semantics, they would essentially just function as syntactic sugar around the "wrap in an object/length-1 container" tricks. I think languages like Python have resisted adding that kind of functionality for the reasons I vaguely pointed at - it doesn't come up often enough, and is powerful/dangerous enough that they don't want to make it easier.
Karl Knechtel
CC BY-SA 4.0
2024-05-22T21:51:12.567Z
Sorry, I was unclear. I meant that in BLISS and MDL dereferencing is required. I've added some more information about Algol 68 to my question for additional context.
texdr.aft
CC BY-SA 4.0
2024-12-28T08:53:12.447Z
After meditating a while on the Algol binding semantics explained in the question, perhaps parameter passing and variable semantics don’t actually need to be “disentangled” after all – you just need to pay attention to *what it is* that is being passed by reference and distinguish between passing a reference to a *variable* and passing a reference to an *object*. The former is what is commonly called “pass-by-reference”, while the latter is what is found in “pass-references-by-value” languages.
user3840170
# References in a language where everything is a reference?
Posted by: username_0 on 2024-05-21
I'm a big fan of Algol 68's treatment of variables. "Variables" are just constant references that point to memory allocated on the stack or on the heap. When you refer to a variable or a component of one, the result is of type "reference to T" instead of T directly; but values of type "reference to T" will be coerced into values of type T automatically. There is no need for an "address of" operator. In assignment and parameter passing, objects are copied (but a copy of a reference points to the same object as the original). Variable bindings always have dynamic extent (no closures); objects have indefinite or dynamic extent depending on whether they are heap- or stack-allocated. See the bottom of the post for more details about Algol 68.
I'm also a big fan of variables in Lisp and most dynamic languages. It's sometimes called "pass-by-sharing" or "pass-by-identity". Assignment and binding cause variables to hold the same object, instead of a copy. This essentially necessitates working with references to objects instead of objects directly. Bindings and objects have indefinite extent.
In my language, I have Lisp-style variables. Recently I've been contemplating adding references in order to increase its expressive power (e.g., the assignment operator can be described using the language itself*, since I have user-defined operators). However, I would want references to behave as in Algol 68 (or C++), with automatic dereferencing. But with Lisp-style variables, every binding has an implicit additional level of indirection, and the two ideas don't seem overly compatible.
Should I work the Lisp-variable-ness into the coercion process along with dereferencing? (Thereby adding one more level of indirection to Algol-style variables.) Is there prior art for that? Or an alternative to references that generalizes lvalues and expressions and allows the assignment operator to be defined.
I'm also not positive about how references interact with indefinite extent bindings and closures. Like, can a local variable escape its scope by assigning a reference to it to an outer variable? Should bindings have dynamic extent unless captured in a closure?

* A procedure to implement the operator would require support from the runtime/compiler, but its type can be expressed and lvalues can be consistently defined if the language has references.

Algol 68 is decently obscure these days, so here's some more information about how it deals with variables. Note that actual Algol 68 terminology is idiosyncratic and I'm "translating" it here to be more widely understood.
The simplest kind of declaration in Algol 68 is the "identity declaration", which corresponds roughly to a constant in other languages:

int i = 1;

This means that i is synonymous with the value of 1. More complicated example:

real circumference = 2 × 3.14 × r;

The right hand side of the = is evaluated and "ascribed" to the identifier on the left, so that they are equivalent in expressions. The computation of the value may involve side effects and need not be possible at compile time.
When an identifier has been introduced in an identity-declaration, it is conceptually replaced by its meaning every time it is applied. Re-declaring the same identifier creates a new binding.
To construct an object of a given type in Algol 68, you use a "generator", which looks like loc ⟨type⟩ or heap ⟨type⟩. Where the object is allocated is determined by whether you write "loc" (value is on the stack with dynamic extent) or "heap" (value is in heap with indefinite extent). The result of a generator is a value of type "reference-to-⟨type⟩", which is conceptually just a pointer to some part of the machine's memory. To express a reference type in Algol 68, write "ref ⟨type⟩".
Operations like array subscripting yields a reference, because it denotes a location in memory. Thus if you have an array A holding int, then A[2] would yield a value of type reference-to-int.
Algol 68's assignment operation is defined to operate on values of type "reference-to-t". For example,

(heap int) := 5

is like
*(malloc(sizeof(int))) = 5

in C; in both languages, it allocates space for an integer in the heap, stores 5 there, and promptly forgets about it.
Algol 68 assignment always copies the value.
As a consequence, you can get an int "variable" by writing

ref int i = loc int;
i := 5

This means "declare i as constantly holding the value resulting from evaluating loc int, which will be of type reference-to-int; then store the value 5 in the memory location just ascribed to i. The value (a pointer) ascribed to i will not change as long as it is in scope; but the value i points to may vary. The assignment construct evaluates the left-hand-side to obtain a reference; there is no special case for when the destination of an assignment is an identifier.
Such notation is common enough that there's syntactic sugar (the initializer := 5 is optional):

loc int i := 5;
heap int j := 5;

In fact, the loc or heap may be omitted, in order to make code look more like Algol 60.
All this is fine, but we still don't really have an "int variable". We have a constant reference-to-int. Theoretically, that means you'd have to dereference i anytime you don't want to assign to it (which is probably the more common case). Instead, Algol 68 defines a coercion from any type reference-to-⟨type⟩ to ⟨type⟩, which gets applied whenever necessary. In other words, dereferencing is automatic; in fact there is no way to dereference a value explicitly. Note that there is also no address-of operator, since anything we could meaningfully take the address of (variable names, array slices, fields of structures, etc.) already happens to yield a reference.
As a consequence of this system, classic problems are easily accounted for:

if p(x) then a else b fi := 10;

proc swap integers(ref int a, b) void:
  (loc int t := a; a := b; b := t);

loc int i := 1, j := 2;
swap integers(i, j)

The first line is like *(p(x) ? &a : &b) in C.
A "pointer to a variable", rather than to a memory location created by a generator, is of type reference-to-reference-to-⟨type⟩. Another way to think about this is as "non-constant references".

loc int v := 10, w := 11;
loc ref int p;
p := v;
print(p);
p := w;
print(p)

The assignments to p copy the references ascribed to v and w. Note that the declaration of p is equivalent to

ref ref int p = loc ref int;
**Tags:** language-design semantics references
> **Comments:**
> **username_1**: The explanation of binding semantics in Algol 68 seems sufficiently long to warrant a separate Q&A pair. (Something like a self-answered “How do identifier bindings work in Algol 68 and do how they compare to modern languages?”, probably.)  
---
## 1 answers
### Answer by username_2 on 2024-05-22. Score: 3
## Disentangling variable semantics from calling conventions

First off, I want to caution against confusing the semantics *of variables and types* with semantics *of parameter passing*. In Lisp (and Python, and for most types in Java, and for selected types in C#), variables have *reference semantics*, i.e. the rule that "variables hold references and assignment copies the reference". **Reference semantics are particularly common in dynamically typed languages**, simply because the assigned value might use a different amount of memory than the original value for its underlying representation; since indirection is generally required anyway, it may as well be used to avoid unnecessary copying.

So-called **"pass-by-sharing" or "pass-by-identity" is really pass by value** in a context where the passed value has reference semantics. In an earlier era, people thought the terminology "pass by value" was confusing for such languages; but as originally defined, it's a perfect fit. Another more modern term is "pass by assignment" - meaning that passing an argument to a parameter works the same way as assigning a value to a variable.

## Evaluating reference types in C++

As for the main question: true pass by reference is quite rare in contemporary languages, and the C++ implementation is *weird* and arguably not quite the same thing. (I'm not familiar with Algol 68, but I'm inferring from your description that it works substantially the same way as in C++). Conceptually, "pass by reference" should be a *parameter passing convention*, **but C++ models this by making "references" into a separate *type category*** (and further confuses things by adding this to a language that *already* has "pointers", which in generic computer science discussion would be considered a form of "reference").

This approach accomplishes the goal of enabling "operator overloading" for assignment. Perhaps a more classic test - which can be applied in a more language-agnostic way - is that this scheme allows for writing **a "swap"** function that swaps the values of two of the caller's variables. This **can't happen with pass-by-value, even when the values have reference semantics**, because the function is given different references. But C++ causes assignments to the reference, to affect the referred-to original value, rather than changing the referent ("re-seating" the reference, in the terminology of the C++ FAQ Lite).

And that causes all manner of problems when one tries to develop a proper mental model. C++ references **can *to some extent* be treated like `const` pointers, except** that they can't legally be NULL or dangling, and attempting to use them inserts indirection into the code that isn't actually there, and you can write an assignment even though it's `const` because it actually assigns to the indirected target. But on the other hand, *there might not actually be a value there at all* after even the most basic compiler optimizations. *Unless* the reference is a member of a data structure somewhere, in which case it might have to exist just to take up space and have an address (which must be distinct from the addresses of other members).

It's really a quite complex idea. And that's without even touching on the issue of "bindings and closures", as you mention it - i.e., the lifetime of the referent vs. its references. This is especially complex without garbage collection, but I expect it would still be a massive headache in a garbage-collected language that implemented references this way. C++ ends up needing special rules like [this one](https://stackoverflow.com/questions/1565600) and [that one](https://stackoverflow.com/questions/7657682). I'm afraid I can't tell you anything useful about how to implement that sort of thing.

## Discussion and alternatives

Personally, I don't think that contemporary languages with reference-semantics variables benefit much, if at all, from support for pass by reference. Users can always just wrap the value in a container, which is passed by value and modified by the function; or the calling code can assign back whatever returned value. Being able to *modify* the passed-in object is generally sufficient for typical programming idioms; things that can't work this way often have separate support (for example, Python has a multiple assignment idiom that makes a theoretical `swap` function sound clunky and useless).

I suspect that **a major reason why true pass-by-reference has become so rare is** because it can make programs very difficult to reason about, by **breaking the encapsulation** of functions. It's already considered poor practice to have "mutable shared state" without well-defined boundaries - for example, to have functions that communicate by modifying a global variable. Re-assigning a variable from an enclosing lexical scope (rather than, say, an attribute of an object, within the code for a method) is already a major source of bugs. **True pass by reference entails** something like the dynamically scoped equivalent of that - **modifying a variable from** the caller, i.e., **an enclosing dynamic scope**. It effectively introduces a dynamic scoping concept into an otherwise lexically scoped language. Dynamic scoping is *also* an increasingly rare language feature, so this could easily be counted as another strike against pass by reference.

That said, if you really want the kind of flexibility and semantics that you describe, I would strongly encourage you to **instead consider how C# implements pass-by-reference**. C# allows for types that have value semantics as well as those with reference semantics - called "value types" and "reference types", respectively, in documentation. (I couldn't use these terms before, since "reference type" means something fundamentally different in C++.)

More importantly for the current discussion, it also allows for passing either by reference or by value, as well as supporting "out parameters" (functionally pass by reference, except that the passed-in value may not be used and thus is not required to be initialized). To avoid surprises (and perhaps ease compilation - I don't know any relevant implementation details), **the calling convention must be marked on both the function and the caller**.

And, crucially, pass by reference is treated as a **true calling convention, and not a property of types**. You can pass the same value by value or by reference to different functions, and you can do this with both value types and reference types. It's especially useful for value types, since it allows for *modifying* the passed-in value *as well as* replacing it. (Passing a reference type by value allows for modification, but not replacement. But keep in mind that such modifications can be "seen" by other potential referers, too, whereas replacement would not be.)
> **Comments:**
> **username_0** (2024-05-22): Algol 68 references are similar to C++'s but they're more consistent because the language was designed around them (think BLISS or MDL, except they require explicit dereferencing), whereas in C++, as you point out, references were just shoved into a language that already had pointers. In Algol 68, references are tightly integrated into the type system.  
> **username_2** (2024-05-22): If they require explicit dereferencing, then aren't they basically just "safe" (restricted) pointers? In that case, if added to a system where variables have reference semantics, they would essentially just function as syntactic sugar around the "wrap in an object/length-1 container" tricks. I think languages like Python have resisted adding that kind of functionality for the reasons I vaguely pointed at - it doesn't come up often enough, and is powerful/dangerous enough that they don't want to make it easier.  
> **username_0** (2024-05-22): Sorry, I was unclear. I meant that in BLISS and MDL dereferencing is required. I've added some more information about Algol 68 to my question for additional context.  
> **username_1** (2024-12-28): After meditating a while on the Algol binding semantics explained in the question, perhaps parameter passing and variable semantics don’t actually need to be “disentangled” after all – you just need to pay attention to *what it is* that is being passed by reference and distinguish between passing a reference to a *variable* and passing a reference to an *object*. The former is what is commonly called “pass-by-reference”, while the latter is what is found in “pass-references-by-value” languages.  
---
