First Draft: Static Single Assignment

Peter C peterc at gmail.com
Sat Nov 29 01:14:26 UTC 2025


On Friday, 28 November 2025 at 00:40:06 UTC, Meta wrote:
>
> The compiler can already guarantee that, because the reference 
> to c is passed by value. To pass it by reference and introduce 
> such a side effect, the function would have to accept a ref 
> Data.

As I understand it, the scope of guarantee for 'final' (or fixed 
as I prefer to call it) is only inside the callee's scope.

So, if you pass a 'final' variable into a function, the callee 
(the function) only sees the value/reference.

The fact that the caller's variable is 'final' doesn’t constrain 
the callee in any way whatsoever.

So there are only two options to ensure the constraint of the 
callee remains:

void performCheck(final Data obj) // The parameter becomes  a 
local variable holding a copy of the reference.
{
     obj = new Data(); // Error (SAA): Cannot reassign a 'final' 
variable.
     obj.value = 1;
}
// Guarantee: Inside the function, all mutations apply to the 
same object the caller passed in.


void performCheck(final ref Data obj) // The parameter is an 
alias for the caller’s variable itself.
{
     obj = new Data(); // Error (SAA): Cannot reassign a 'final' 
variable.
     obj.value = 1;
}
// Guarantee: The caller's binding is formally protected, not 
just incidentally safe.

Practically: Both forms ensure that mutations inside the function 
apply to the same object as c, thus ensuring the constraint of 
the callee.

So.. back in main():

// We do indeed have a guarantee that here, 'c' will still refer 
to the same object it was initialized with: writeln("\nValue: ", 
c.value);

Actually, now that I think about it, this example makes the case 
for transitivity of 'final's binding guarantee (i.e. like C#'s 
readonly).

Otherwise, it's a pretty loose guarantee, and it becomes more 
about style and clarity than about strong enforcement across the 
call graph.

A developer reading the code can’t be sure whether the “single 
assignment” promise holds everywhere or just in one scope!

In my opinion, for it to be valuable, the compiler would need to 
enforce a "no rebinding anywhere" rule, which I think is outside 
the scope of this DIP?

With transitivity, it becomes a strong, system-wide contract, 
much like C#'s readonly.


More information about the dip.development mailing list