Hacker News new | past | comments | ask | show | jobs | submit login

State transition cannot be checked by constructor because it doesn’t know previous state.



Ah, I see what you mean. It's not about that proposal, but about the fact that record constructors cannot be private (at least not for a public record). That's because records are meant as product types, or nominal tuples, which don't break encapsulation but exist to represent the notion of an unencapsulated tuple. That's their job: to be unencapsulated data with everything that enables.

Now, you may ask why they don't also do other things, and I guess its possible that in the future we'll allow private record constructors, but there's less need for that, because Java already has a construct for encapsulated state -- ordinary classes.


Regardless of what records were meant to be, they are designed in a way where they do offer encapsulation (which by definition means not only the state, but also the behavior of an object, and it does not mean that we always hide the state - only that we control the interface to it). Records can have business methods and can have non-trivial constructors, so they are basically a syntax sugar for special form of classes, not tuple structures. If you can use them to encapsulate certain forms of behavior, e.g. by declaring methods for state transitions, then with{} block will be a change in their interface. Do I expect that new version of language will change interfaces of my data structures? Hell, no! This feature must be designed as opt-in solution, following the example of Iterable and foreach loop and requiring explicit declaration of wither interface. What kind of declaration could that be?

Imagine uniform declaration of intent for records and classes like in this example:

    public record Point with (int x, int y) {}
    
    public class Order {
       public Order() with (OrderStatus status, Instant timestamp) { … }
       public @(OrderStatus status, Instant timestamp) { … }
    }
Here we explicitly say that Point generally supports „with“ block for all fields and Order supports deconstruction to status and timestamp and construction of a new object with the same fields. This way existing code retains the interface but can be easily modified to support the new syntax.


> they are designed in a way where they do offer encapsulation

They are very intentionally designed to represent unencapsulated data. Records can have non-trivial constructors, but they all have a public canonical constructor, and while you can do strange things in your constructor and accessors (we needed that for technical reasons), the JEP/Javadoc/tutorials warn you against doing so, and that the reasonable assumption is that you don't.

The invariant is that if you have a record and deconstruct it using a deconstructing pattern, then you can also reconstruct it to get an object that's equal to the first by using the public canonical constructor. You can break that invariant, but libraries are allowed to assume that you don't.

> If you can use them to encapsulate certain forms of behavior, e.g. by declaring methods for state transitions, then with{} block will be a change in their interface.

But you can't and so it won't. All (public) records have a public canonical constructor that you can use regardless of "state transition" methods, with or without withers. The relevant point, again, is not the "with" feature, but the publicness of the canonical constructor. You cannot limit the construction of a record to a state transition method even today, because you can't hide the canonical constructor.

There are certainly classes that do need private constructors, but if they do, then those classes are not records (we may expand the role of records in the future, but so far they're specifically designed to not allow that so that the reconstruction invariant is maintained).

> Imagine uniform declaration of intent for records and classes ...

There's no need to do that for records, because they have a public canonical constructor, and that is the constructor that's used by the feature.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: