Hacker News new | ask | show | jobs
by dragly 3006 days ago
Thanks for clarifying! I really don't think you're shifting the goalpost. What you're saying is basically that the getText/setText methods are part of the API of the visual TextField, like a moveLeft method would be part of the API of a robot controller. A dumb struct with mutable members, such as a Point with public x, y, z members, is on the other hand both the API and the data in the same object.

It seems to be important to separate data from logic, and API from implementation in discussions like these. Sure, I can make a nice API for a visual Rectangle object with dynamic width and height, and add a check to my setWidth method to make sure the width is never negative and the changes trigger a repaint. But if I need a Rectangle struct to store data in the implementation of my library, it can be way simpler to just make the Rectangle have a public final/const width member, and set and check the width in the constructor.

Sometimes you need the smart Rectangle, and sometimes you need a dumb struct with width and height.

1 comments

Why wouldn't you want to keep the constraints as close to the data as possible? That way you avoid the issue that the Rectangle struct is reused somewhere else, but without the correct constraints.
IMO the constraints should be as close to the thing that needs the data, as possible. Your object is an expression of data that may be valid in some contexts and invalid in others, and trying to pick any one of them is difficult (and leads to things like complex inheritance trees to express all the different flavors of constraints.)

I think this is the essence of the "composition over inheritance" idea that seems to be the most violated piece of sound OO advice out there.

These constraints should ideality be in the type system, or other statically checked constraints.

Most OO languages have type systems not fitting for such checks, though. Thus runtime checks, often a part of a setter.