loading...

Avoid getters and setters whenever possible

scottshipp profile image scottshipp ・7 min read

Don't generate getters and setters!
Noooo!!! Don't click that generate getters and setters option!!!

I like the rule: "Don't use accessors and mutators." Like any good rule, this one is meant to be broken. But when?

First, let me be clear about what I am saying: adding getters and setters to OO classes should be the last resort after considering a series of better alternatives. I believe that a careful analysis yields the conclusion that getters and setters are harmful in the clear majority of cases.

What is the harm?

First let me point out that the "harm" I am talking about might not be any harm at all. The following is, in some cases, a perfectly reasonable class:

// Car1.java

public class Car1 {
  public Engine engine;
}

Notice, though, that feeling of tightening in your stomach, the bristle of your hair, the tensing of the muscles that you may experience looking at something like that.

Now, I want to point out that there's no meaningful functional difference between that class, a public class with a public class member, and the following class below, a public class with a private member that is exposed by getters and setters. In both classes, Car1.java and Car2.java, we get essentially the same result.

// Car2.java

public class Car2 {
  private Engine engine;

  public Engine getEngine() {
    return engine;
  }

  public void setEngine(Engine engine) {
    this.engine = engine;
  }
}

To show this, I read and write the engine in either Car1.java or Car2.java:

// Car1 member read and write
Car1 car1 = new Car1();
logger.debug("Car1's engine is {}.", car1.engine);
car1.engine = new HemiEngine();

// Car2 member read and write
Car2 car2 = new Car2();
logger.debug("Car2's engine is {}.", car2.getEngine());
car2.setEngine(new HemiEngine();

The point here is that anything I can do with Car2.java, I can do with Car1.java, and vice-versa.
This is important because we've been taught to get squeamish when we see Car1.java. We see that public member sitting there and we say, not safe! Engine is not protected by anything! Anyone can do anything! Aaaaaaaaagggghhhhh!

Yet for some reason we breathe a sigh of relief when we see Car2.java. Which--I'm sorry--I personally think is funny since there's literally the same (non-existent) protections around both of these things.

What could go wrong?

The following are some of the disadvantages of public getters and setters that directly expose a single private member, have the same name, and provide no other functionality.

Getters and setters are a fake insurance policy of isolated change

One supposed advantage of getters and setters is that on the off-chance that the type of a class member needs to change, the change can be limited to inside the class by making the existing getter simply translate from the internal type to the previously-exposed type.

// Car2.java, engine changed to motor

public class Car2 {
  private Motor motor;

  public Engine getEngine() {
    return convertToEngine(motor);
  }

  public void setEngine(Engine engine) {
    this.motor = convertToMotor(engine);
  }
}

My question is how often has the working programmer ever had to do that? I don't remember ever doing this in all my years of software. Not once have I been able to take advantage of the fake insurance policy that getters and setters provide.

Also, this argument becomes an entirely moot point if the engine had never been exposed to begin with (let's say it was kept private or package-private). Just expose behavior, rather than state, and you never need to worry about flexibility in changing implementation.

This realization that the private member should not have been exposed triggers another realization that this argument is tautological. Getters and setters expose the private member, and rest the case for their existence on the fact that the private member is exposed.

Getters and setters expose implementation details

Let's say I give you only the following API to my Car object:

 _________________________________
| Car                             |
|---------------------------------|
| + getGasAmount(): Liters        |
| + setGasAmount(liters: Liters)  |
|_________________________________|

If you assume that this is a gas-powered car that internally tracks gasoline in liters, then you are going to be right 99.999% of the time. That's really bad and this is why getters and setters expose implementation / violate encapsulation. Now this code is brittle and hard to change. What if we want a hydrogen-fuelled car? We have to throw out this whole Car class now. It would have been better just to have behavior methods like fillUp(Fuel fuel).

Things like this are the reason why famous libraries have terrible legacy classes. Have you ever noticed how most languages have a Dictionary data structure but it's called Map in Java? Dictionary actually was an interface that was introduced in JDK 1.0, but it had problems and ultimately had to be replaced by Map.

Getters and setters can actually be dangerous

Let me tell you a story about a friend. OK? A friend I said!!!

One day this friend came into work, and found that dozens of well-known web sites in countries around the world all had the header and navigation of the parent corporation's main web site (not their own), and were using British English. The operations team was frantically restarting hundreds of servers around the globe because for the first half-hour or so that these servers ran, things functioned normally. Then (bam!) all of a sudden something would happen that made the whole thing go sideways.

The culprit was a setter method deep in the guts of a shared platform that all these different sites were using. A little piece of code that ran on a schedule happened to be updated recent to this fiasco that changed the underlying value that determined site headers and languages by calling this setter.

If you only have a getter, things can be just as bad. In Java at least, returning a reference type from a getter provides that reference to the caller and now it can be manipulated by the caller in unexpected ways. Let me demonstrate.

public class Debts {
  private List<Debt> debts;

  public List<Debt> getDebts() {
    return debts;
  }
}

OK, that seems reasonable. I need to be able to see a person's debts to give them a statement. Huh? What's that you say? You can add debts now? Shit! How did that happen!

Debts scottsDebts = DebtTracker.lookupDebts(scott);
List<Debt> debts = scottsDebts.getDebts();

// add the debt outside scotts debts, outside the debt tracker even
debts.add(new Debt(new BigDecimal(1000000))); 

// prints a new entry with one million dollars
DebtTracker.lookupDebts(scott).printReport();

Eek!

One way to guard against this is to return a copy instead. Another way is to have an immutable member. The best way, though, is to not expose the member in any way at all and instead bring the behavior that manipulates the member inside the class. This achieves full isolation of the implementation and creates only one place to change.

When getters make sense

Wait a second! If there are so many disadvantages to accessors and mutators, why ever use them?

I'm convinced that getters and setters which just return a class member almost never make sense. But you might write something close to getter/setter functionality as long as you are actually doing something in that method.

Two examples:

  • In a setter, before updating the state in this object according to some input, we validate the input. The input validation is additional functionality.

  • The return type of a getter is an interface. We have therefore decoupled the implementation from the exposed interface.

See, what I'm really advocating for here is a different stance and philosophy towards getters and setters. Rather than say never use accessors and mutators, I want to give you the list of options that I try to exhaust before using one:

  • My "default" is to start with a private final member, set only by the constructor. No getter or setter!

  • If another class absolutely needs to see this member, I think about why. I try to see if there is a behavior that I can expose instead, and create a method for that behavior.

  • If it's absolutely necessary for some reason, then I relax to package-private (in Java) and expose the member only to other classes in the same package, but no further.

  • OK, what about the data use case? Literally I might need to have an object to pass data across some kind of interface boundary (let's say to a file system, database, web service, or something). I still don't futz around with getters and setters. I create the class with all package-private members, and I think of and use it as just a bag of properties. I try to limit these into their own packages and layers at the boundaries of the application.

  • I would consider creating both a getter and a setter for the data use case in a public API, like let's say I am writing a library meant to be used as a dependency in a lot of other applications. But I would only consider it after exhausting all of these list items.

Wisdom of the Masters

A short postscript. Obviously, there's debate about getters and setters out there in the world. It's important to know there's clearly a camp of "masters" like Robert C. ("Uncle Bob") Martin who are proponents of avoiding getters and setters. In the book Clean Code, Martin wrote about this in chapter 6:

Beans have private variables manipulated by getters and setters. The quasi-encapsulation of beans seems to make some OO purists feel better but usually provides no other benefit.

Josh Bloch has a nuanced stance in Effective Java, Item 14 that is slightly in favor of getters and setters for public classes, and slightly against for others. He ends up basically saying that what he is really concerned about is mutability, a point I touched on above:

In summary, public classes should never expose mutable fields. It is less harmful, though still questionable, for public classes to expose immutable fields. It is, however, sometimes desirable for package-private or private nested classes to expose fields, whether mutable or immutable.

Further Reading

Here's some helpful thoughts from smarter people than me.

Tell, Don't Ask

Why getter and setter methods are evil

Accessors are evil

Discussion

pic
Editor guide
Collapse
xowap profile image
Rémy 🤖

Well, I used to think that getters and setters are usually useless. Until one day I had to do some computations once a value was set and there I had to re-factor my whole code around the fact that the member was no longer directly accessible but had a getter and a setter.

So I'd say, putting getters and setters is more future proof whilst not being very expensive.

Yet I'd also say that this problem almost only exists in Java because other languages have ways around this (Python <3)

Collapse
jorgecc profile image
Jorge Castro

Until one day I had to do some computations once a value was set

But it depends on the type of the class. Usually, it is evil because it hides logic that it is not so obvious.

For example this example:

class Customer {
    public void setName(String name) {
        this.name = name;
        this.prefix="Junior";
    }
}

Customer cus=new Customer();
cus.setPrefix("Dr.");
cus.setName("John");

// it shows Junio John, not Dr. John

Then setName hides a surprise.

Collapse
bonobomagno profile image
Orland

This is just bad code example. In a real work case, you will check this.prefix before overriding it. Or better, Only getName with output name+prefix.
There is really no sense making a double setter with only one setter function. Particularly if the setter function name don't explain this.
If you really want to do it in this way, you will add a second argument on the setName with a default Junior value for easy overriding the default.

But again, this problems don't exist in other languages.

Thread Thread
jorgecc profile image
Jorge Castro

It is not the point. The point is setter and getters are justified because we could add logic (my code it's only an example). However, we don't want to, unless the class represents a visual object. So, using setter and getters usually are noise to our code.

C# resolved the problem by adding "setters and getters without logic", they please both parties while it does exactly the same than public fields.

public int MyProperty {set; get; }

In any case, setter and getters are generated automatically, like to follow a rite.

So:

  • We could add logic but it could give us a new set of troubles.
  • We could add logic-less but it does nothing but noise.
  • It could be generated automatically, however, it is still noise.
Collapse
jodydott profile image
Jody Dott

the computations should happen inside your object (in a OO world) you shouldn't be asking other objects for their internals (unless they are simple value objects).

Collapse
xowap profile image
Rémy 🤖

Yup but sometimes you start without needing the computation and then later realize that you need it for a new feature. In that case, it's hard to come back on your decision.

Thread Thread
jodydott profile image
Jody Dott

That's why you should program with an OO style and encapsulate. All requires computation.

Collapse
rafiq74 profile image
rafiq74

I was about to mention the same thing. I had the same experience many times.

Collapse
galdin profile image
Collapse
dilantha111 profile image
Dilantha

Actually when I just started reading this article. C# is what came to my mind instantly.

Collapse
jodydott profile image
Jody Dott

I think C# is even worse in this regard.

The argument is that getters/setters and properties VIOLATE ENCAPSULATION by exposing internals as properties rather than mutating through behavior as classic OO would prescribe.

I've seen excessive use of getters/setters/properties in Java, C#, Ruby, and Javascript. Changing the syntax does not help. If anything it aggravates the problem by telling people that its ok to set attributes willy nilly and separate the logic that dictates the behavior from the object.

Thread Thread
aminmansuri profile image
hidden_dude

I've seen huge problems in Ruby where people create "models" and then set all the attributes but forget to encapsulate the "rules" and behaviors around those changes. So later it becomes a huge mess to figure out how the class actually works.

If your "objects" are just a bunch of attributes with just getters and setters then they aren't really objects. They're structs (as in C structs) or records (as in Pascal). And you aren't really doing OO. You're using an OO language to do procedural programming.

Collapse
smontiel profile image
Salvador Montiel

You made me think!

Great post!

Collapse
florianschaetz profile image
(((Florian Schätz)))

Oh sweet mother of mercy, no. I am currently forced to work with code where someone once decided that getters and setters were evil and did everything with public variables. It's... not good. Yes, 95% of the variables work that way (because we have lot of them), but the remaining 5% make more work than it's worth.

Also your example "gasAmount" is completely nonsenical, because the problem exists no matter if you use getters/setters or just a public variable. How does a public variable with the same name change that problem?

Also your debt example is a perfect example why getters are BETTER than exposing the variables. With a getter you can protect your list by returning a copy. With direct member access? Not really.

So, your arguments against getters and setters are not really good. That's unfortunately, because the basic idea is not a bad one:

While getters/setters ARE better than directly exposing the member, we should of course try to prevent BOTH.
Immutable objects, for example, have far less problems than mutable ones - and if all members are final and imutable themselves, they can be exposed as public members directly, because it's read-only. But the problem this solves is not that getters and setters are but, but that mutability is more dangerous than the other way.

Collapse
bobbypriambodo profile image
Bobby Priambodo

I think you're missing a bit of the point there.

Scott wasn't comparing which of the two (getters vs. public variable) is better. What he said is that getters and setters by default (e.g. when automatically generated by IDE, or shown in beginner examples) expose the variable just the same as making it public; however, people seem to appreciate getters more than public vars, even when they're essentially the same.

The point is reinforced in your last sentence that, above all, the problem is mutability.

Returning copies are not getters (or at least not what most think as getters); they're essentially behaviors. You have to do the extra work to make them only as exposed/encapsulated as necessary.

The point I took from this article is to always strive to make your variables private, and that means not even getters and setters, and only expose behaviors around that data. Which I think makes sense, with some caveats that also have been stated in this article. Not necessarily agreeing, but a good food for thought nonetheless.

Collapse
florianschaetz profile image
(((Florian Schätz)))

That's what I said... "the basic idea is not a bad one" - it was just surrounded by bad arguments for the wrong problems. By starting with the public member thing, the whole text got the wrong spin from the start and the following bad argument didn't help.

Directly addressing mutability, exposing behavior, adding methods that directly work on the members instead of just holding them in a dumb object, etc. is a great idea. But by surrounding it with discussions about public members vs. getters/setters, etc. just dilutes those great points.

Thread Thread
bobbypriambodo profile image
Bobby Priambodo

I see, and that I can agree with. Hopefully the readers can see beyond it too. Thank you for elaborating!

Collapse
forsakenharmony profile image
Leah

In the debt example he didn't argue for public variables though, I think you misread that?

He said it wasn't good to expose it at all, but if you do with a getter that returns a copy.

But the better alternative is doing what you want to do with it in the class itself

Collapse
akostadinov profile image
Aleksandar Kostadinov

Yeah, it's too bad many inexperienced developers will not understand that this is just clickbait. Thank you for the great comment. I couldn't do it better.

btw the example of famous person being against setters/getters seem to be about very specific use case.

Collapse
dimpiax profile image
Dmytro Pylypenko

You have just shown bad design. Reason not in getter/setter, but in approach.
If you open properties to public you must have reason why. But not like exception with debt example.

If replace getter/setter theme with singleton or composite – and write in the same manner, the result that all is bad, will be the same.

Main point: use features properly. We have instruments in our belts, and to hammer nails with a saw is not the best choice.

Collapse
scottshipp profile image
scottshipp Author

Hi Pilipenko, my goal with this article was to show bad design. All of the code examples here are things I would not do, including the debt example. I tried to give guidelines for what I would do in the section at the end, but I probably could follow up with code examples of what I think people should do.

Collapse
dimpiax profile image
Dmytro Pylypenko

But your topic name is "Avoid getters and setters whenever possible", not "Bad design in getter/setter". This article just discredits specific area of programming, but not educational.

We have a lot of useless articles like "Don't use OOP", "Don't use functional programming", "Why declarative worse that imperative" and so on. But whole idea in right usage, and neither getter/setter neither functional or AOP are not bad.

Thread Thread
xtofl profile image
xtofl

I must say you have a point: we lack a vast body of "how to do X without violating design flaw Q".

This year I learned about Domain Driven Design, and the Onion Architecture, where they design apis around use cases instead of data. Maybe there is some source of positive guidelines we can tap.

Collapse
codemouse92 profile image
Jason C. McDonald

Very good write up. I had an undefinable suspicion about getters and setters, but you've helped cement it for me. Thanks for the much-needed kick in the teeth for us OOP purists! :)

I'd like to add to this, if you are only using a class/object for storing data, you've got bigger design issues than just getters and setters. Read Pseudo-Classes and Quasi-Classes Confuse Object-Oriented Programming by Conrad Weisert.

Collapse
aminmansuri profile image
hidden_dude

Getters/setters are not OO constructs.. they are inherited from "construction by parts" popularized by languages such as VB and PowerBuilder.

You'll find no such horrors in the old smalltalk codebase (though VisualAge for Smalltalk did have properties because it was a construction by parts system).

So if you were an OO "purist" you would have long eschewed getters and setters.

Collapse
codemouse92 profile image
Jason C. McDonald

Fair point. OOP, as Alan Kay (Smalltalk) envisioned it, is nothing like what we have today.

Thread Thread
aminmansuri profile image
hidden_dude

Thanks for the paper by the way.. very interesting.

Collapse
scottshipp profile image
scottshipp Author

Thanks for this paper Jason! It is great!

Collapse
tmfrisinger profile image
Travis Frisinger

Fantastic stuff! Ultimately, it is the lack of encapsulation and presence of mutability that are the real problems. It is not a style or language issue, rather, it is the lack of awareness from developers to push for better solutions that do not rely on 'cheap and nasty' to do the job.

Collapse
kallaste profile image
Tatiana McGarry

Getters and setters are an integral part of encapsulation in OOP. Yes, things can go wrong when you abuse a setter, but unfortunately, there is no such thing as "idiot proof" code. It used to be that programmers themselves were expected to have brains.

Everywhere I look there are new "suggested practices" popping up that seem to want to guard against someone else's poor programming messing up your code in the future, when unfortunately, that simply cannot be done. The suggestion to "avoid getters and setters whenever possible" is just another example. But inexperienced developers read an article like this one and just jump on the bandwagon. How about we simply omit them when it makes sense to do so?

Just program responsibly and think about your use cases when you need something to be inaccessible and/or immutable, and stop handicapping yourself trying to guard against any remote possibility of some future developer using poor practices in the future.

Collapse
aminmansuri profile image
hidden_dude

They are not part of encapsulation. They are the opposite.

An encapsulated class in "pure OO" does not expose its properties. But many people confuse this because their only exposure to "OO" has been through Java and C# (and their successors) and have had little exposure to a real OO system like Smalltalk.

Collapse
kallaste profile image
Tatiana McGarry

Yes, they are a totally legitimate part of encapsulation in the current paradigm of Object Oriented Programming, and will be mentioned as such in current literature about it. That isn't confusion, it is the maturation of programming language concepts. A lot has changed since 40 years ago when Smalltalk was invented. We had no idea what OOP was going to be back then, or in many ways how it was going to be used.

The argument that getters and setters aren't a valid part of encapsulation because Smalltalk did it differently is a little like debating what the World Wide Web is on the basis of how things were done in ARPANET. Quite simply, just not very relevant.

Thread Thread
aminmansuri profile image
hidden_dude

No. Its a misunderstanding about what encapsulation is.

If you have a computation like:

bankAcct.setBalance(bankAcct.getBalance() * bankAcct.getInterestRate())

Then you aren't understanding how OO is supposed to work. The correct encapsulation would be by having behavior based method:

bankAcct.accrueInterest()

Getters and Setters don't come from OO they come from "construction by parts" a style of programming made for automated UIs like in VB. It has its place, its related to OO, but it isn't encapsulation. It's the opposite. Its exposing your attributes to the outside world.

And plenty of OO was written by great programmers like Kent Beck and others that later helped influence how we did it in other languages. But the popularization of many techniques has little to do with good OO, and simply popularization of stuff that certain developers promoted.

Collapse
pocketstealer profile image
Pocketstealer

Get/Setter.

Why? Because it's easier to say in a set:
If(Value not null){
set value
}
else{
w/e
}

Than to go EVERYWHERE and check if that value is null then use something.

Sure a basic example looks stupid... but you were not taught not touching the flames by being explained what thermodynamics are...

Get/Setter's are better for a good approach and have assurance that the class will work no matter what the values will be given.

PHP is a loosely typed language getter/setter are perfect for this.

Collapse
scottshipp profile image
scottshipp Author

You're concerned about code duplication and that's a good concern. But what if there's a bigger issue here? The fact that this setter can be called "EVERYWHERE", as you say, is a bigger problem to me. Everyone has access to set this value. If just one of them makes a mistake, everyone else using it suffers the downstream effects.

So the real problem here isn't duplicated code, to my mind. It's the fact that there's a variable available everywhere. That sounds like a global variable with some procedural code manipulating its state.

Consider what happens if the field is kept private, and no get/set methods are made public either. Where is everywhere now? Only inside the class itself. It's not a global variable anymore. There aren't a bunch of random classes out there that can go set that value. Another developer can't come in with some new code that calls set on that value incorrectly, and stops several user scenarios from working correctly.

I think we've all worked in scary code like this and we can do better. In my experience, I've found that looking at everywhere the set method is called yields the result that I come out with at most a few different uses, and I can write a method for each use and call the new method from these call sites instead. They'd be behavior methods which keep that variable inside a class or at worst inside a package, and not available everywhere. That way I not only de-duplicate code, but I prevent other bugs that could occur as well. Bugs like the site header one that I mentioned. When no one can call setWhatever(newValue)--indeed they don't even know that the Whatever variable exists--then those kinds of things aren't possible.

Collapse
jstormes profile image
James Stormes

In PHP we also use reflection for hydrating objects. If all your objects properties have getters and setters you can hydrate by reflection, otherwise you have to write lots of exchange_array code.

However we can also hydrate on properties directly, but you don't get to do any validation of the data. As you say PHP is loosely typed, so that opens you up to hacking/injection.

What is harder to do is hydrate on both get/set and properties. So you wind up all ways using setters, even if you don't need them all the time.

Collapse
pocketstealer profile image
Pocketstealer

I think we are confusing bad practice with the role of getter/setter.

Bad practice is everywhere. But when you are using a getter/setter you expect to give a certain value and get a certain value.

You know you are setting a string. You will get a string. Thats the role of the getter/setter.
You are certain and sure that there will be in no circumstation a null there. Or a number. Always a string.

Using getter/setter for everything is bad as well. Leaving a variable there that is used and can be moddified to contain anything is even worse.

If you use get/set just to "return","$this->alfa = value" that's bad practice.

But a beginner doesn't know when should use it or not. So the one that's easiest to "implement after" it's the cheapest.

Scope of projects change. Agile is here and not always you have time to get all the information/specs or maybe some new information get there with constraints.

Always take the safest/easiest way rather than "smart way but it might blow up later".

Collapse
arhanger profile image
Arhanger

Someone has never changed his code. Sorry, but afet this "In both classes, Car1.java and Car2.java, we get essentially the same result" i stopped reading. Public properties are not the same as getters and setters. With getters and setters we have an entry point to our business logic, with public properties we don't have any. After changing hundreds of calls to any property through the whole project you'll understand why. This is the first point.
The second point was mentioned in comments. Calls by reference. When you use public properties you usually don't bother with copying stuff. Why should I? Doing that hundred times. That leads to a couple of painfull bugs. The most common one are date objects being modified by reference. Hours thrown away trying to debug that one. Especially by middle/juniors.
Third, getters and setters can be covered with unit tests. If someone changes something you will see that.
The last and not least. It's a lot harder to control workflow with this approach. Instead of reviewing code design, you are forced to check every property call through the whole project. Not very effective.
It's not bad to try to find something new, but getters and setters are used not by chance. If you want to remove a tool, propose something to cover that gap. Good luck.

Collapse
mduran profile image
Miguel Duran

It shows that you stopped reading at that point. His point was not that public attributes are just as good or better than getters and setters, his point was that the internals of a class should be as restricted as possible and having getters and setters violates that.

If you actually read the article, you would see this:


```My "default" is to start with a private final member, set only by the constructor. No getter or setter!

If another class absolutely needs to see this member, I think about why. I try to see if there is a behavior that I can expose instead, and create a method for that behavior.```

Collapse
arhanger profile image
Arhanger

My points wasn't on good/bad. He said that both ways give you the same result. And this is wrong. That was what I wrote about.

Second, but not least. Getters and setters can also be restricted, if you need that.

Third, there could be dozens of parameteres. Constructor will become huge and I personally don't like that. For that I'd better use a factory, that will garantee to create a valid object. For any other call there's code review to deny them.

Fourth, there's metaprograming in many languages. That lets you use even private members. So I don't see a reason to be so paranoic about that. But private members could give you headache when writing unit tests or changing class with tens of references to that private member.

To conclude, my main point was that these two methods don't give you the same result. Hope that makes my thougts clearer.

Collapse
elcotu profile image
Daniel Coturel

Hi,
I don't agree with expressing that package private attributes are a better approach than getters and setters.
Suppose you have the case of a bag of properties as you stated in the data use case. A bag of properties may be abstracted as a case of class with state but not behaviour.
Now, let's suppose that, in any time in the future, you have to add behaviour to one of the attributes.
If you implemented the getters and setters, then you put that behaviour in the corresponding methods and you are done.
If you didn't implement those getters and setters, you have several choices to make:
1) Put the new code without being coherent with the rest of the class
2) Refactor all the class to make it coherent and then include the new behaviour
3) Put the behaviour in the calling classes
Maybe I'm missing some point, but I don't see the advantages of the second option.

Collapse
scottshipp profile image
scottshipp Author

I didn't understand your option 1, but I would definitely not do option 3. If I understand right, option 3 would mean you go and duplicate the new behavior at every reference to the member. Option 2, then, is way better than 3 in my mind.

For option 2, since it is package private, I would expect the number of references to that field to be fairly limited. How large is a package usually? I'm sure it varies depending on context, but generally its manageable. I personally wouldn't expect more than a few places inside a package where there's a direct reference to a given field. Maybe I make smaller packages than others? With today's refactoring tools, my experience is that its quite painless to switch to a method call rather than a direct member access if that were necessary.

The other thing I would point out is that usually, in the case you mention, you would have to change the method name if you wanted to adhere to the principle of least surprise.

Let's say for a user object, you did start with a getter to reference the user's name, and there were now quite a few references to "user.getFirstName()". Now let's say you got a new requirement to return the user's nickname, if available, rather than their legal first name. Well, if you update the getFirstName() method to do that, yes, you don't have to change code everywhere, but it would kind of suck since it is unexpected for getFirstName to sometimes return the nickname and sometimes return the legal first name.

If we were following good coding practices, what we actually need now is to change all those references from "getFirstName()" to some new method (like "getPreferredName()") instead, which, once again, is no different than if we had used a direct reference to begin with.

Collapse
elcotu profile image
Daniel Coturel

Hi Scott, thanks for your answer.

I intended to leave the option 2 as the "more adequate" because the other two are very, very smelly.

Option 2 is more addequate but I wasn't thinking in a case like the one you describe. That case is not a change of behaviour in the getter, but a change in the behaviour of the class. I was thinking in some other cases:

1) Let's say you start with a setter that only does this:

public void setLastName(String ln) {
this.lastName = ln;
}

But in the future, you want to keep track of the modified fields after last read of the database, so in the next update you can only set those fields.

So you add an array of "touched" fields and say, "ok, so when every field is touched by a setter I will add it to the array". Like this:

public void setLastName(String ln) {
this.setTouchedField("lastName");
this.lastName = ln;
}

If you didn't had the setter in the first place, then it would be a pain in the ass adding this behaviour.

2) Let's say you have an object composed of some other objects. Your constructor creates an instance of every each object. But at some point you realize that you want to initialize some of the objects not on parent constructor, but when it's needed. So you could do something like this:

public CustomObject getInstanceOfCustomObject() {
if (this.instanceOfCustomObject == null) {
this.instanceOfCustomObject = new CustomObject();
}
return(this.instanceOfCustomObject);
}

These are some examples I had in mind when I said that it is at some point good to have those getters and setters already coded, even if they are initially totally dumb implementations.

Saludos,

Thread Thread
scottshipp profile image
scottshipp Author

Thanks for the thoughtful questions Daniel! In both cases, I think its still worth asking if there's not some behavior that can be exposed publicly instead of just exposing data. It is easy (because there's so many programmers doing it) to think in terms of data classes being passed around to behavior classes. This is not object-oriented, though. It's a near-cousin to global variables and procedural code operating on those variables. The paper Jason C. McDonald posted in the comments here is a pretty good discussion of these issues.

Unfortunately, both of the examples you gave are going to be prone to concurrency issues that are more serious than the discussion of whether they use "get" style methods. For the second example, try switching to the Initialization-on-demand holder instead. As far as the fact that the method is named "getInstance()" I would not put this in the same category as the getters/setters described in this article. This is a static factory method.

For your example 1, I feel that using the decorator pattern to track the changes in a separate class might be a better approach since it would be a cleaner separation of responsibilities, and you could dynamically add the change-tracking capability only where its needed. OTOH, you don't want to make a whole separate class if its not needed. If you really need to be able to track changes everywhere, then keep it as you showed (but think about concurrency!).

In that case, it would still have a "getXXXX" method then, and I would not be opposed to that. That's why I wrote:

I'm convinced that getters and setters which just return a class member almost never make sense. But you might write something close to getter/setter functionality as long as you are actually doing something in that method.

Thread Thread
elcotu profile image
Daniel Coturel

Hi Scott,
Thanks for your answer. Now I understand a little more about the concept you are communicating.
Saludos,

Collapse
bgadrian profile image
Adrian B.G.

At the begining I was ..."I hope he doesn't suggest to expose the variables", then

My "default" is to start with a private final member, set only by the constructor. No getter or setter!
Ok, we're all good, move on.

I agree that in most of the cases no variables should be exposes, in any matter, it is a statement of: "please side effects and bug, come and get me". In some env it makes sense because 99% of the time is about public vars (for example in Unity3d you have components, and you need to expose parameters of all sort so the game devs can visually instatiante and configure the instances, and ofc this leads to other big issues, beside the ones mentioned here).

Collapse
magmax profile image
Miguel Ángel García

I see you had two different problems here: The important one, you found a getter returning a pointer, what means you have the control over the content. Aditionally, you put the blame on the getters and setters.

The feature I hate most about Java are equals, getters and setters. They are harder to read (car.setEngine(engine) against car.engine=engine) and harder to write, even with IDEs help, because I need to be generating them and maintaining them if I decide to change the variable name.

They require more code, so when I open the class I have to read those methods just to be sure they are not doing anything more than an assignment. This is time.

And all of this, as you said, to override one in a million.

I found a library, lombok (projectlombok.org/features/GetterS...), that helps you to avoid the implementations with annotations. It is true that it still require to use .getFoo and .setFoo, but I avoid generating them from the IDE and maintain them.

Anyways, I miss a feature in Java like Python's properties, that allow you to override just that method in a million:

class Foo:
    def __int__(self):
        bar = None    # normal public var
        _bazz = None  # private var to be used as property

    def getBazz(self):
        return _bazz

    def setBazz(self, value):
        self._bazz = 2 * value

    bazz = property(getBazz, setBazz)  # property declaration

foo = Foo()
foo.bar = 5
foo.bazz = 10
print(foo.bar)
print(foo.bazz)

So, you can change any public variable to a property just when you require to override that method.

Collapse
pinotattari profile image
Riccardo Bernardini

I agree. I think that you should decide the method of your class on the basis of what you expect that class to do (in an abstract sense), rather than on the basis of its internal structure. My personal experience (but YMMV) is that most of the cases (note: not all) where you are tempted to use a setter can be solved with suitable constructor to set the attribute once for all when the object comes to life.

Usually my approach (I use Ada, not Java, so the jargon will be slightly different) is to initially define the internal structure of the object as a "null record," with no field at all. In the spec file then I write the methods I think I need, possibly trying to compile the rest of the code against that spec. Of course, I am not going to obtain an executable, but I can check if the API of my object is complete. Successively, I begin working on the implementation (and this includes the fields of the class).
Usually with this approach any getters/setters you end up with make sense since they do not start from the implementation, but from an abstract view of the object and they are getters/setters "by accident," just because their implementation boils down to reading/writing a field. The resulting code will naturally pass the "acid test" named in one of the linked article why getters and setters method are evil

Can you make massive changes to a class definition—even throw out the whole thing and replace it with a completely different implementation—without impacting any of the code that uses that class's objects?

Collapse
shaaza profile image
shaaza

Exactly! Embrace (almost) complete immutability, program with expressions, isolate mutation to a corner of your system, and you can start focusing on the problem at hand instead of orthogonal issues such as this.

It's so much easier to change software when you can read code without the mental overhead of tracking state through time. I know people who have gone back to writing OO languages but still don't let go of the ideas encompassed by the functional paradigm, and it often works out well for many cases.

For a deeper (and a level-headed) understanding of the benefits of FP and what to take away from it, I recommend the paper "Out of the Tar Pit", if folks haven't already it. github.com/papers-we-love/papers-w...

Collapse
marlysson profile image
Marlysson Silva

Awesome approach and good arguments.

I don't know if you knows the "jsf" ( web programming in java ) , that some specific classes that requires the getters and setters ( convention over configuration ) to their internal implementations uses all structure of the application that use some implementation.

Do you know some advice about it? Or isn't related to the post and there aren't to do?

Collapse
scottshipp profile image
scottshipp Author

I think I should have tackled this in the article. You are going to be on the hook to use getters and setters for libraries (like JSF) that reflect on them. Can't really avoid that.

But you can avoid a dangerous anti-pattern (in my opinion), which is then passing such objects around inside the application.

Usually, Java libraries that use reflection on getters and setters are doing it to bind data to/from these objects. There is usually a specific intent behind this, such as to create a POJO from incoming data, such as from the JSON body of an http request.

I believe that this type of automatic object creation should be limited to a single place at the edge of the application. If the usual pattern is followed of turning around and passing the resulting object around inside the app, it creates a situation where changes in the JSON body (or whatever it is), makes you have to change all the code paths that the object travels across.

So its best if you can isolate and decouple these auto-generated objects from your application. Build walls around them and keep them at the edges.

Collapse
aminmansuri profile image
hidden_dude

There are ways around getters/setters/properties but they aren't very simple. Like using a visitor pattern or renderers. They definitely aren't popular and would confuse the average programmer.

For some things getters/setters, while not real OO, are a good solution. For example the way Hibernate handles DB properties, or ActiveRecord. As long as people remember to wrap these with real objects later that expose behavior instead of attibutes.

Collapse
hussainakbar profile image
Hussain Akbar

(Darned cat walked over the keyboard and wiped my text)

I find Java programmers to be of the same cloth as Linux users; swearing by purity instead of concentrating on substance.

Case in point is the final declaration. It's my code. If I want to change a variable, I will. If not, not. So why use final?

This (and a boatload of similar posts) are because Java does have properties (public variables) but doesn't have any actual getters and setters. They're coincidental public methods that happen to set / read values of private variables.

I mean, just look at constructors that set multiple variables. Similarly, you can have a function for example:
public void setPerson(name, age, mobileNumber){...}

And another for:
public void setPersonAddresses(homeAddress, workAddress){...}

and not have individual setters for the above 5 variables. So, are they setters? They do the same work and the result is exactly the same. You can check for invalid values, copy arrays, etc. But, noooooo. Java purists would never deign to use them.

Now, have a look at DotNet. A VB.Net class would be:

Class Example
    Private _count As Integer

    Public Property Number() As Integer
        Get
            Return _count
        End Get
        Set(ByVal value As Integer)
            _count = value
        End Set
    End Property
End Class


`

That's a setter that's bound / fixed / glued to the property. You just use example.number = x and all the checks are carried out.

You get the ease of use with the needed functionality.

Purists: Go ahead and scream at me all you want. At the end of the day, Java still won't have any getters or setters.

Collapse
scottshipp profile image
scottshipp Author

It just sounds like you have your own brand of C# purism. In Java, the tools are there if you want to use them. "Final" keyword provides one ingredient towards immutable objects. The C# equivalent is the readonly keyword. If you want to use it, great, but if you don't, also great. I don't see anything to debate or any reason to compete Java against C#. Both have getters and setters, but different syntax for achieving the same result. C# properties are a little more compact and readable IMO which is nice. But Java is not missing anything.

Collapse
wrongabouteverything profile image
wrong-about-everything

Totally agree! Accessors is totally anti-OOP feature. I believe it was Martin Fowler who popularized a reprobation of this concept in his post Anemic Domain Model. But little changed from 2003. A lot of people still are not aware that the whole point of OOP is combining data and behavior. Thus accessors still don't make any sense there.

Generally, the $64k question is how to come up with such an objects that expose only behavior, not data. Well, my take on it that it all starts with the problem space -- your concrete domain at hand. Talk to your business-experts, consider the use of CRC-cards, draw use-case diagrams and find your smart and knowledgeable objects.

Collapse
aminmansuri profile image
hidden_dude

There are some solutions to the getter/setter problem but they aren't great. Like using a visitor pattern to feed data into a view, or using "renderer objects". Part of the reason for getters and setters is the more pressing desire to separate model's and views.

But I agree that from a purist point of view, getters/setters are not really OO and they violate encapsulation.

Collapse
aminmansuri profile image
hidden_dude

Getters and setters often violate the principle of encapsulation which is to NOT expose internal details of your class.

They aren't really an OO technique but rather a "construction by parts" technique popularized by UI oriented techniques from VB or PowerBuilder. They are designed so that automated UI tools can get and set attributes of a UI component like color, size, etc.. It was later used for "JavaBeans" (that also started in the UI) and then was used by frameworks like Hibernate.

But to suggest this is good OO is just because many people never saw real OO from the Smalltalk days.
If you have something like a Car with a getX() and getY() position then you set the x and y position you are overriding whatever animation sequence that car should do when you "drive to" a position. A Car should really drive to positions not simply jump across the screen.

Methods should encapsulate BEHAVIOR not simple data mutation. That being said, there is room for objects such as value objects to pass around.

Another phenomena that is becoming apparent is that in backend Web programming many of the techniques used today are not really where OO shines. OO shines more in GUI and front end designs where you have inheritance and composition between components.

So I have to agree with the article.

Collapse
rossdrew profile image
Ross

This seems to me like a list of cases of using something badly, then complaining they are dangerous. No, using things dangerously is dangerous. No awareness of mutable state of members (returning mutable lists of restricted data), no awareness of future proofing (space for future validation without changing APIs for example)...these are not problems with the feature, but with the user.

Collapse
kolyaio profile image
Nikolai Ilushko

I think the title is a bit problematic because you trying not to use getters and setters at every single moment just because we were taught to use them. At the end the message is to create real isolation between different parts of the code you do instead of doing setters and getters as check mark for OOP "requirements".

Collapse
lukbenda profile image
Lukas benzin Benda

And interface and inheritance and proxy for AOP you newer see? Yes I see a lot of project where was same stupid developers and the harm which they do was prity expensive. Mainly see in a lot of copy paste or repetitive work, because inheritance and interface coldn't be reasonable use.

Collapse
rodislavable profile image
Rodislav Moldovan

The article should be named: avoid auto-generation of getters and setters, (because it can cause free mutability issues on a plain field).
And has nothing to do with getters and setters in general.

Just fix the title and article will start to make way more sense, we all know - naming is the most difficult problem.

Collapse
coderangshuman profile image
Angshuman Halder

This post was amazing. It changed my perspective towards getters and setters.
Having getters and setters makes no sense only if it exposes the private members of the class for being manipulated by other classes.

Collapse
xtabdeveloping profile image
Márton Kardos

Yeah, one of my friend does this thing constantly in Scala, where basically all the fields he creates are immutable val-s. So there exists an immutable field, as well as a getter for it, which doesn't make sense at all, especially because the functional approach implies, that an immutable variable is basically the same as a constant function.

Collapse
theomails profile image
Theodore Ravindranath

I think within the code base of a single self contained application, you can just start with public variables. It's not difficult to refactor and add indirection later.

But if you are sharing a jar which is going to be is used by another team, then better expose via getters and setters so that there is some wiggle room to alter the implementation. Also, in such case it would have to be done with interface in the first place so public fields are out.

There is a distinction here to be made between just any Java public class and something that is module-public (something that you would expect outside teams to use)

Collapse
nallack profile image
cgray

You should never write public variables for a class in object-oriented programming.

  • You are exposing internal state, thus making it easy for someone put your class into an invalid state, it is now impossible for the class to determine if and when it is being put into an invalid state, and is why poorly designed software breaks.
  • Your class may need to perform extra functionality or provide a view of an implementing instance on a call to an accessor or mutator. You don't want to waste time swapping over instead of writing it the correct way to begin with.
  • You cannot provide an interface to public member variables, thus is not ideal to use when writing a library because the API layer can't provide access to everything needed to use your class anymore.
  • Engineers have spent thousands of hours incorporating accessors and mutators into languages to encourage their use for these reasons.

(However, in "some cases" a struct can be more suitable than a class (as seen in math libraries) where member variables should instead always be public. The only limitation you have for writing a struct is that all variables are also invariant. Some languages also don't have structs (e.g. Java), in which case you need to use a class to create a struct-like object that has no responsibility for preventing invalid state e.g. java.awt.Point has public x and y members. An awt ui object however will never return its internal state, accessors will always return a clone of an internal Point instance.)

Collapse
jorgecc profile image
Jorge Castro

Kotlin just hides the code and implementation, so it's not solving the problem but masquerading it.

We could also use @Lombox but again, it also hides the code and implementation.

Or we could generate the setter and getter and fold the methods. It's the same but different kind of syntax sugar.

Collapse
hack2root profile image
Artur Mustafin

It so naive for you to misunderstanding how getters and setters work;

The reality is that getters/setters have at least exactly the same security as of any over accessor modifiers.

Moreover, getters/setter have more security other the items thy control when geclared properly.

Getter/Setter is an abstracton of control, allowing you to make some additional operations before you get into trouble with references you incapsulated class data outside of a class.

For examle, SIMPLY buuld and return a COPY of data when getter called, when needed, or clone data when setter called. It is that simple

Collapse
amihaiemil profile image
Mihai A.

I'm happy to see that more people are avoiding getters and setters. But this is such a long wall of text and all of it can be sumarized into one simple idea: "model objects" (get/set JavaBeans) are not real objects!

They are lifeless toys, which we have to move ourselves, instead of relying on them to move and do the job for us. Model objects should not exist in an object oriented world at all. Here is a metaphor about it:

amihaiemil.com/2018/04/17/dolls-an...