> Identity comparisons are more useful for mutable objects, but even an immutable object can use one as an alternative to a unique ID.
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.
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.