Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

This misses the main problem with get/set methods.

In OO othodoxy, you aren't supposed to make state public, because it violates encapsulation. If you want to modify your Point object to use polar coordinates instead of cartesian, then if you expose your cartesian state (x and y), then all the code that relies on x and y is now broken.

So what getX() and setX() do is allow your x and y fields to be encapsulated. Problem solved! Except that once you change to polar coordinates you have your choice of problems:

1) Find all the getX() and getY() uses, and rewrite the affected code to use getR() and getTheta(), since you are now using polar coordinates. In other words, you have violated encapsulation by having getX() and getY() methods, and your get/set methodology hasn't achieved anything.

2) Re-implement getX() and getY() in terms of polar coordinates. That's doable. But do you also now have getR() and getTheta()? Why?

Having getFoo() and setFoo() methods for each field foo is this dumb idea that began, I think, with JavaBeans. It has nothing to do with OO as I understand it. The idea behind OO encapsulation is to separate your object's behavior (the methods) from private state. You can change state at will as long as you maintain behavior. Mechanically adding behavior (get/set methods) to track your private state has always been a stupid idea that has nothing to do with OO except to violate encapsulation.



> Mechanically adding behavior (get/set methods) to track your private state has always been a stupid idea that has nothing to do with OO except to violate encapsulation.

What should be private state is a matter of debate.

If you have a point, it's not too ridiculous to ask "where is it?" Cartesian coordinates may or may not be how the Point object represents where it is, and that internal detail should be hidden from callers.

> But do you also now have getR() and getTheta()? Why?

It seems like a Point class should hold its internally state in the "best" implementation for how it is usually used, and provide its state out to callers in all of the convenient forms that would be used more than occasionally.

Of course, one should avoid purely exposing internal details. And sometimes you might encapsulate more to encourage callers to use the pointA.getDistanceAndBearing(pointB) call. (But I don't think this makes sense for points; knowing their location is too fundamental).


They enable your option 2 and allow the implementation to change behind the public API. Should theta/R have getters is entirely up to your API decisions.

The point of getters and setters is they're the bare minimum of encapsulation. The advice is to ensure even reading a field should be abstracted so implementation details do not cause large reactors of downstream code.

How this is conflated with 'every field should have getters and setters' like it is in this discussion I do not know but that is not the intention.


OO design is ultimately API design.

Unfortunately, it's often taught with toy noun examples that have obvious/actual internal fields and data structures.

It'd be better taught solely using abstract nouns, to better nudge learners into explicitly thinking about external/API design vs internal state.

Or, in other words, getters and setters are subcases where the external/API exposed is 1:1 with internal state.


> Should theta/R have getters is entirely up to your API decisions

But it often isn't. The blog post starts out talking about how that field -> getter/setter pattern is very widespread, and tools (JavaBeans tools for example), make that pattern unavoidable sometimes. Yes, it should be an API decision, but for a variety of reasons -- tools, patterns, coding standards, cargo cult programming -- it isn't.


What's the point of this article if those are unavoidable and unaddressed?


Or:

3) implement getX() and getY() alongside getR() and getTheta() and allow user code to decide which to use. Double the functionality without having to expose internal state.

4) implement a PolarPoint class with a way to convert between that and Point. This is more applicable if the concepts are not orthogonal but also not as strongly correlated as coordinate systems.

The two ways of handling you describe are not how I would actually handle any of this in real situations.

Getters and setters meanwhile allow you to do things like recalculate internal state whenever you call setX() or setR() to amortize computational costs or do any other kind of change tracking without having to rely on some more language-specific feature to do so. Plus getters and setters work across network boundaries unlike modifying state directly.


Point 2) feels very weak. You could easily have getR and getTheta, but critically you could also always have had them - if they make sense as APIs, and your state is encapsulated, you can expose them at any time.

The benefit of having getters is that API consumers don’t privilege public state above any other API component, because they don’t know what’s actually the real state and what’s just under contract.


Given your Coord example, can you come up with a better OO version than the article's advice of "can I make it immutable"?

The immutable version would let you have all four fields. A setter on any of the 4 items (should you desire it) will return a new object whose four fields remain consistent with one another.


...and how precise do the switches between coordinate systems have to be? depending on your format for floats, you will land on areas that are only expressible with perfect precision in one or the other coordinate system. I can imagine a fixed point that moves around by being repeatedly queried in one or the other system.


Point object could be either, since the coordinate systems are truly interchangeable, e.g. the class could just store everything as Cartesian internally and convert to/from polar as needed. In a class with more mutually exclusive properties I can see how this wouldn’t work so well.


To answer a few sibling responses:

The point is that mechanically maintaining get/set methods for each field is completely at odds with encapsulation. To continue the example, sure, go ahead, have any or all of get/setX, get/setY, get/setR, get/setTheta if they make sense for your application. But writing them just because you've created a field, and the coding standards say they should be there is dumb. The coding standards that say this (like JavaBeans) may have their reasons, but OO ain't it.




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

Search: