It sounds rather like value objects are strictly superior than immutable data structures, based on this statement. I'd love to hear an expansion of this rationale.
It sounds rather like value objects are strictly superior than immutable data structures, based on this statement. I'd love to hear an expansion of this rationale.
So, languages should stop thinking in terms of "this is a reference type" and "this is a value type", and start thinking about "this references something mutable" vs "this references something immutable". For the latter, the implementation can then use by-value semantics for perf reasons, where appropriate.
On the other hand, mutable objects with value semantics can provide the ergonomic advantage that mutation has in some cases (e.g. 'point.y += 10' rather than 'point = Point(point.x, point.y + 10)' as well as more predictable performance, while avoiding bugs caused by accidental aliasing.
How is that having value semantics? Or are you just referring to equality testing? Even then you're playing a dangerous game if you have multiple threads (one mutating, one running an equality check) and aren't using locks.
I think that's part of a problem. Object identity should not be used for unique IDs - when you need a unique ID, use a UniqueIdGenerator or something like that.
Java and C# and others have got this so very wrong, when they did things like, "okay, all objects have identity, let's just reuse it for other stuff", and made it possible to e.g. synchronize on arbitrary objects - synchronize(x) in Java, lock(x) in C#. Now they can't get rid of object identity, because it's part of the language semantics - even if you never synchronize on objects of your class, something else might, and making them identity-less will break that.
At the very least, let's make it explicit. When you define a class, it should be stated upfront whether it has identity or not. If it doesn't have identity, it should be immutable. If it does have identity, it still can be immutable if you want (if you need that identity for something, like your event example). But this state of affairs - immutable with identity - definitely shouldn't be normal. If it's needed, it should be requested explicitly.
I guess the real point here is that object identity has a heavier cost than it would seem from the first glance, and so it should be opt-in rather than opt-out (and it should definitely be possible to opt out).
As for `point.x += 10`, it doesn't preclude point from being immutable. It just means that the language has to desugar it into `point = Point(point.x, point.y + 10)` for you. That way, there's no accidental aliasing (since objects are still immutable - it's the reference that is mutating - so no alias can observe the change). And then the code generator, knowing that there's no aliasing, can replace it with actual in-place field update, when and where it makes sense.