I understand the rationale for value classes, but the implementation is flawed.
What will this code print:
Point a = new Point(10, 10);
Point b = a;
a.x = 100;
System.out.println(b.x);
Until now the answer was obvious. Now with the addition of value classes, the answer depends on whether Point is a value class or a reference class. So readability suffers with this design.
This is a violation of the principle of uniformity. In The Psychology of Computer Programming, Weinberg explains that uniformity is a psychological principle which says that users/programmers expect that things that look similar should do similar things, and conversely that things that look different should do different things.
If a programming language lets two constructs look nearly identical at the use site while having meaningfully different semantics, it increases the cognitive burden on the reader. Programmers must inspect the type declaration or rely on tooling to understand whether assignment, equality, identity, and mutation behave like ordinary reference objects or like values. That can make code harder to reason about and maintain.
This could have been fixed by requiring the use of the "value" keyword not just at declaration time but also at use time like this:
value Point a = new Point(10, 10);
Point b = a;
a.x = 100;
System.out.println(b.x);
If that's true then it is a significant improvement over structs in C#.
But the distinction still matters. Value-vs-reference semantics affect equality, identity, nullability, arrays, collections, boxing, and performance.
So this is not just an implementation detail. If a language hides that distinction at the use site, it increases the burden on the reader and makes code harder to reason about.
I don’t see how it’s an improvement over C# structs. C# structs are value types so they are copied when assigned to a variable like primitives. There is no ambiguity because it’s a struct.
To avoid copying you have to explicitly declare a ref variable/parameter.
You can get the same immutability as value classes by using ‘readonly struct’s or ‘readonly record struct’s.
Java value classes are stranger because they are heap allocated by default and are only flattened/scalarized/stack-allocated when certain conditions are met. It’s the same as a class, but with extra restrictions, so that the JVM can possibly optimize memory layout at runtime.
C# has Properties that make setters look like fields anyway. There's no ambiguity between value and object in C# because there is no promise that that syntax only sets a field. Love it or hate it, you just need to know what you're calling.
based on the goals from JEP 401 [1], this is not possible, as value classes are meant to "Allow developers to opt in to a programming model for immutable data(...)"
What will this code print:
Until now the answer was obvious. Now with the addition of value classes, the answer depends on whether Point is a value class or a reference class. So readability suffers with this design.This is a violation of the principle of uniformity. In The Psychology of Computer Programming, Weinberg explains that uniformity is a psychological principle which says that users/programmers expect that things that look similar should do similar things, and conversely that things that look different should do different things.
If a programming language lets two constructs look nearly identical at the use site while having meaningfully different semantics, it increases the cognitive burden on the reader. Programmers must inspect the type declaration or rely on tooling to understand whether assignment, equality, identity, and mutation behave like ordinary reference objects or like values. That can make code harder to reason about and maintain.
This could have been fixed by requiring the use of the "value" keyword not just at declaration time but also at use time like this: