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

I appreciate you thinking of an example, but I guess I find it a bit convoluted.

Couldn't you also refactor that by changing the constructor of your temperature class so it converts things to Kelvins, rather than converting it every time you call the getter?




Sure, but every field access like

    Temperature temp = Temperature.fromCelsius(13);
    ...
    System.out.println(temp.celsius);
would have to be changed to

    System.out.println(temp.getCelsius());
when the internal representation is changed.


I get what you're saying, but at the same time I don't understand how you'd implement the class and why.

    class Temperature {   
        public final double celcius, kelvins;

        Temperature(int celcius, int kelvins) {
            this.celcius = celcius;
            this.kelvins = kelvins;
        }
        
        public static Temperature fromCelcius(int c) {
            return new Celcius(c, c - 273.15);            
        }
    }
What's wrong with that approach, and how would you do it?


Why would you have two separate temperature values?

Just have one in Kelvin that can't go below zero, and have getters and setters that translate to C/F when specified.


What you propose wouldn't be using "getters" to me. They just sound like normal methods.


This only works if your class is immutable. If a client sets either of those fields, they will now be out of sync.


Why have a mutable class to represent temperature - a simple value class with two fields? Why not just construct a new Temperature? I mean if performance was an issue, you'd just use plain doubles instead, right?

I'm open to the idea that setters do have a use case, but I'm not seeing one here.


How about a class that stores temperature and the current state of the satellite? It's easy to come up with circumstances where requirements change.


Then I would implement it as a "real" class, not a data one.

    class Satellite {
        Coordinates coordinates;
        double celcius;

        /*** constructors, etc ***/

        public double Celcius() { ... }
        public double Kelvins() { ... }    
        public void Move(...) { /* modifies state */ }
    }
Note how none of the methods make any mention of low level operations like setting/getting internal fields.

You could make the argument that I do have a getter there, Celcius. But at the risk of pedantry I'd argue it isn't so. The name doesn't imply that it's retrieving the value of a field - ie the internal representation could easily change to Kelvin or Fahrenheit - where as "getCelcius" definitely tells me there's a field there called Celcius.

Hmm, after writing that I wonder what the definition of a setter actually is. I have no problem with a method that just returns a field, as long as it doesn't go out of its way to tell me that's exactly what it's doing. Maybe the distinction I am making is too subtle.


Celcius is definitely a getter. The name absolutely implies that it's retrieving a value because it's name is not a verb or action.

Properties in C#, for example, really just remove the ambiguity in this exact situation. Is it object.Celcius or object.Celcius()? A good C# programmer would use the former. A method would be object.RaiseTemp().


It looks like I have a really different definition of "getter" than some people here. I would only call something a getter if it explicitly makes reference and effectively exposes an internal field. Just giving a method a noun name is not enough to make it a getter, in my mind. It's the "get" prefix that says 'hey there is definitely a field in here called Foo that we think we're encapsulating but we're really not'.


Your definition of getter and setter are way too narrow. You exclude all getXX() and setXX() methods that don't directly manipulate a field and all C# property get/set the same way.

The getter or setter is part of the public interface of the object. The public interface makes no guarantees about implementation -- encapsulation is one of the fundamental principles of OOP. It is only supposed to appear from outside that you are getting/setting some internal property of the object. And that is the simplest implementation. However, the value of encapsulation is that it really doesn't have to implemented that way. Or the implementation could change entirely as long that public interface works the same way.

> I would only call something a getter if it explicitly makes reference and effectively exposes an internal field.

I think you're original question is "Why would anyone use a getter/setter if they could just a public field?" But your definition excludes all the reasons why someone would do it! If getters/setters just exposed internal fields and never anything else then they really serve no purpose.


I think you're not understanding what I'm saying. Luckily this person explained it better than I could.

https://news.ycombinator.com/item?id=15607598


I think I already addressed that point adequately here:

https://news.ycombinator.com/item?id=15607812

There simply isn't a better domain method term for moving data from one place to another than get/set. You could invent alternatives but they're just more confusing.

And even that linked comment addresses modification not retrieval. Sometimes you just want a value out of an object -- a getter.

I think understand the point that you're trying to make; the idea that an object just accepts messages that alter it's internal state but otherwise keep it completely hidden is a pervasive one. Exposing internal state can lead to coupling or violate the single responsibility principle. But that model is too simple, plenty of objects are just containers. And not dumb containers that are just bundles of simple fields but smart containers with data that isn't entirely internal.


The scenario being discussed was a class which changed its internal representation without breaking it's public api.

A getter can then by definition not simply refer to only a field anymore as that field is gone. It might have done so in the first version of the class where Fahrenhet() simply returned your fahrenheit field(a getter) but now we've removed that field and replaced it with a celcius field. That means Fahrenheit() doesn't just return a plain field anymore, there is some transformation going on. It's still considered a getter.


The concept of getters & setters exist in languages where it's not conventional to write them as methods named getX() or setX(y).

Writing the that example in C#, you'd likely have

    public double Kelvins {get; set;};
    public double Celsius {
        get { ... }; 
        set { ... };
    }
and [modern] Javascript could have

    let kelvins;
    get celsius()  { ... };
    set celsius(c) { ... };
And you'd set both of them with [eg] s.celsius = 5. This is how getters/setter look when a language supports them.

Writing and using methods named 'getX' and 'setX' is conventional in Java because support for this feature doesn't exist at the language level, but is essentially implemented by the common IDEs. Probably not the ideal situation, but that's where Java is at.


what if the constructor's not the only place you can set the value?


This is a bit abstract to me. I don't tend to write mutable classes. And if I do mutate fields, it's for a "reason" (and I'll name the method after that reason).

If you feel like it, write out how you'd implement the class and why. I posted a fairly strong opinion, but I'm happy to have my mind changed.


sure, ok, if you only write immutable classes, by definition you never need setters, right?

i won't defend mutable classes (i won't decry them either), because i haven't personally thought tons about the benefits of immutability. i mean, i can see a lot of reasons why it's a good thing to shoot for, and i think it's a thing i often try to shoot for. but people often write mutable classes, or must maintain mutable classes written by their predecessors. in which case, setters can be nice.

or they can be annoying boiler plate. seems like a case by case thing to me. i think the getter/setter thing does often feel needlessly verbose, and so i upvoted your original parent comment. but "setters are always bad and i don't understand why anyone would ever use them" seems like a needlessly hard-line sentiment, IMO.


If you have a mutable class, and you're modifying its fields, you're doing it for a reason, right? Often it's part of a larger operation. So why not name the method that mutates the field after that reason. I got away from thinking about "I am altering the internal representation of this struct + vtable" to "I am sending a message to this opaque thing and I don't really care how it's done when I'm outside the black box".

> but "setters are always bad and i don't understand why anyone would ever use them" seems like a needlessly hard-line sentiment, IMO.

I have a strong opinion because I read some compelling arguments, thought about a lot, stopped using setters, and the quality of my code improved. I don't see a need to moderate my opinions on programming, especially when that's what I really think. Again, happy to be shown a great counter example and admit I was wrong.


> If you have a mutable class, and you're modifying its fields, you're doing it for a reason, right? Often it's part of a larger operation. So why not name the method that mutates the field after that reason. I got away from thinking about "I am altering the internal representation of this struct + vtable" to "I am sending a message to this opaque thing and I don't really care how it's done when I'm outside the black box".

> > but "setters are always bad and i don't understand why anyone would ever use them" seems like a needlessly hard-line sentiment, IMO.

> I have a strong opinion because I read some compelling arguments, thought about a lot, stopped using setters, and the quality of my code improved. I don't see a need to moderate my opinions on programming, especially when that's what I really think. Again, happy to be shown a great counter example and admit I was wrong.

that's all fair. i think we might actually agree more than disagree. all your arguments are compelling, and i could see myself holding a similar opinion after giving the matter more thought.


This seems to deny the fact that a lot of data exists to just be stored and displayed. Probably 85% of all software in the world has a "FirstName" field/property/column in it somewhere. What name you propose giving a method that changes that value?


I guess I'd call it "changeLastName". That's closer to the domain, we don't go to the Department of Births, Deaths and Marriage and tell the clerk we want to "set" our last name. But that is being too pedantic, even for me.

I'll concede defeat. That is a pretty good example. At the end of the day, "customer details" class is actually a big bag of fields that needs some access control and validation.


If you get married, you might "changeLastName" or maybe even "rename" yourself but if you're just moving that name from one place to another you'd "set" it.

You could probably come up with lots of different names but none of them will be more clear than "set" in this case.


If moving requires a name to be set you are at constructor time, no need for permanently available setters.


Two things with that, you're assuming immutability but even a simple database entity object wouldn't be immutable. And secondly, anything over a handful of values and setting them via a constructor isn't pretty.


if it's just used for display, use a new value.

if there's more to the domain context, i'd call it rename(~). i think from the outside, it's better to articulate what you want in domain semantics, rather than implementation semantics.


i think from the outside, it's better to articulate what you want in domain semantics, rather than implementation semantics.

You've articulated here what I've actually been trying to communicate. I have no problem if a method does nothing but get/set a variable. I just think they should be named with domain semantics.


Sure, for a simple class like this I would make it immutable too.

But the example is just a demonstration of the concept - you should be able to change the implementation without changing the exposed interface. When you first write a class, it may look like a simple bag of fields. But when that inevitably changes, getters and setters allow you to do it without breaking the clients.

Even if we keep this immutable, your implementation is different in that it uses twice as much memory. Maybe it's irrelevant, or maybe it's worth the tradeoff to use more memory and have faster access to the kelvin representation.

But maybe not. If you had getters and setters, you could seamlessly try the other implementation without changing all of the client code.


But the example is just a demonstration of the concept - you should be able to change the implementation without changing the exposed interface.

My argument is that having getters and setters exposes your implementation. If you have "getFoo" and "setFoo" it exposes that your class contains a value called Foo. My argument is that you should either give your methods better names, or get rid of the pretense of encapsulation altogether and just make them public. Get/Set is just an awkward middle ground.

Even if we keep this immutable, your implementation is different in that it uses twice as much memory.

How can my implementation be different? No one else has written one (:

But maybe not. If you had getters and setters, you could seamlessly try the other implementation without changing all of the client code.

And if you had actual methods with names that didn't break encapsulation, you could do the same and divorce all your calling code from the burden of knowing about the internal structure. Again, the middling approach is the worst of both worlds to me.


> My argument is that having getters and setters exposes your implementation. If you have "getFoo" and "setFoo" it exposes that your class contains a value called Foo. My argument is that you should either give your methods better names, or get rid of the pretense of encapsulation altogether and just make them public. Get/Set is just an awkward middle ground.

this phrasing/perspective definitely brings me around more to your point.




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

Search: