But also, you pay a big complexity tax when the new concept is
    almost like but can't quite fully meet up with the old concept; it
    again means that refactoring from record <--> carrier comes with a
    significant sharp edge, and this is a big warning signal.  So we
    would need a much stronger reason than "hmm, kind of like it
    better this way" to choose this divergent path.  So far I'm not
    seeing it?


There is a big sharp edge between a record and a class which is due to mutability, this is true inside the class but also outside, the user code when something is mutable or not is quite different .So refactoring from a mutable class to to an unmodifiable record is a not battle we should be interested in.

Just because carrier class state _can_ be mutable, doesn't mean it _must_ be.  So you're skipping over the interesting case, which is:

    record R(int x, ...) { }

and

    final class R(int x, ...) { private final component int x; ... }  // not equivalent to above!

In your model, the class version of R is painful to write, because you have to write equals, hashCode, and toString that delegate to each of the components.  But that's not even the main point; it is that while there is no theoretical distinction between a record and a final class all of whose components are backed by final component fields, there is a big and hard-to-explain discontinuity when you start from either of those and try to refactor to the other.

But you are still not justifying your preference; WHY is identity-based equality the *obviously right* choice for carriers? Be semantic please!  Tell me what you think a carrier *means*.

Reply via email to