Should getters and setters be avoided?

Started by
23 comments, last by JohnnyCode 7 years, 11 months ago

He also implies in his webinar that all objects should be immutable. This idea sounds crazy to me, he is actually proposing to pass a new object every time we want to mutate it.

I am a huge fan of immutability. Yes it does mean building a new structure when mutating the data but this is not as bad/costly as you might think given the other benefits you gain.

Take the new C# compiler Roslyn. The old compiler was written in C++ while Roslyn is C# with everything immutable. Conventional thinking would be that C++ would be faster than a .NET language but even with the object churn the new compiler is far far faster.

Immutability is about getting your object structure correct, your structures are more like records from F# instead of more normal OO objects. If an object is immutable you never need to clone it as you can just reference it also there are no thread based locking issues issues ever etc. When you rebuild the structure you can reuse any referenced objects so you are only rebuilding what has changed if your design is right. There are a raft of immutable collections to ease working with collections of data, just updating the minimum of data.

If you also pick up concepts like lenses from Haskell the update of nested data is also very easy as it simulates get/set properties rebuilding all the object graph that needs it.

Languages such as Haskell are actually constructed around immutable state, you require massive hoop jumping to allow mutation.

Advertisement

In my opinion, getters and setters are fine. They allow you to separate data layout from access syntax. That way you can change whether a getter and setter are trivial member accesses or not without having to find all uses of a member object. Some languages have "object properties", which allow you to have methods that have the same interface as data member access. In these languages getters and setters are uncecessarily. Java and C++ aren't those languages, so getters and setters are useful despite their verbosity.

For example, Imagine you have a complex number class. Complex number can be stored as real and imaginary parts, or as phase and angle. Depending of how they are used, either storage method may perform better. Having getters and setters for all four of these properties would allow you to change data you store without changing all uses of your class; you can easily benchmark which is better for your application. More generally, it allows you to easily change which object properties are calculated on the fly, and which ones are stored or cached, after your first performance benchmark, instead of just when you're first designing a class.

You need to take what you read with a grain of salt and evaluate whether it makes sense or applies to your project. ESPECIALLY when someone starts calling something always evil like in one of the linked URLs in the original post. At this point, I don't think there is anything that is always evil. I think I actually even have a good case for a goto in my rendering engine's code, which is the pinnacle of the NO-NOes in programming. (And I'm still looking to get rid of it.) So if you tell me that something as ubiquitous and proven as getters/setters are always evil, no, just no. Misused? Yeah, I think people often write a lot more getters and setters than they actually need to. But always evil? No. (And only a Sith deals in absolutes. :P)

The truth is that there are a lot of people in the programming circles that would like to make themselves a name by calling well accepted practices "evil" just because it's bad by some completely unpragmatic point of view, or because once upon a time someone misused the pattern or principle. Now it's get/set, last week singletons were evil. Next week if someone calls having a main() function an antipattern... well, remember I called it first here. :P

Don't ignore what you read, just have critical thinking. If you're a seasoned programmer, you know more about how to go with your project than some blogger with a book so listening advices and new method can never hurt, but in the end you're the one who can judge how to go with your project. A lot of those people writing about programming practices are academic Java programmers looking to sell their books or conferences. Probably the same type of people that state completely obvious things, wrap them in silly catchy acronyms like KISS, GRASP and SOLID and write PhD thesis around those, but I disgress...

I do think though that if you're going to write a data object with full read and write access and know it's going to remain that way, just write an old-fashioned plain-old-data struct. It's not "prettier" to have to write my_object.GetXXX() instead of my_object.XXX and for setters it's actually annoying if you like to do chain assignments or swaps. Qt is guilty of that a lot: you need to pass through methods to set the values of a vector or a matrix. It's just annoying. Don't do that.

This is kind of why I would like to see properties in C++: you can expose naked properties if you don't need to control reading and writing, and if you change your mind later and need a getter or setter, you can write them without breaking any code. But again, I disgress.

Take the new C# compiler Roslyn. The old compiler was written in C++ while Roslyn is C# with everything immutable. Conventional thinking would be that C++ would be faster than a .NET language but even with the object churn the new compiler is far far faster.

The MSVC compilers are known for how slow they execute and compile code - they were about 10x slower than Borland's compilers and even gcc is faster today. I don't know why but they have "always" been that way so it's something in their legacy design that was not dumped until Roslyn.

Given C#'s bucketing memory allocation and garbage collection they probably just pool all memory used until compilation is complete then dump everything at shutdown and that is where I suspect most of the speed-up comes from so immutability has no impact on the compilation time.

- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara

Take the new C# compiler Roslyn. The old compiler was written in C++ while Roslyn is C# with everything immutable. Conventional thinking would be that C++ would be faster than a .NET language but even with the object churn the new compiler is far far faster.

The MSVC compilers are known for how slow they execute and compile code - they were about 10x slower than Borland's compilers and even gcc is faster today. I don't know why but they have "always" been that way so it's something in their legacy design that was not dumped until Roslyn.

Given C#'s bucketing memory allocation and garbage collection they probably just pool all memory used until compilation is complete then dump everything at shutdown and that is where I suspect most of the speed-up comes from so immutability has no impact on the compilation time.

There was no intention to imply that immutability had the impact, should have been more clear :) I was trying to imply that code structure and flow is the key to faster code such that even if you have the extra object churn that immutability brings it can still be faster than a badly structured program.

Methods on objects should be verbs or questions.

Sometimes it's appropriate that the verb is to set some state.

But generally no, the state of the object should not be visible or changeable from outside the object. So you don't need getters and setters.

If you find yourself with a "bag of values" object, just make it a verbless bag of objects. And make all the members public and save a bunch of typing.

One of the common flaws of developers is that given a setter interface, they try and drive the objects through it, leading to pages of boring settering code instead of a single verb operation to abstract that away -- and which, appropriately named, tells you what it does.

I would not place getters and setters as equal in their usage frequency. If a value is set, it is very prone to mistakes to conisder it is not full responsibly set from outer instructions, yet getters are much successfull attempt allowing objects to hide data they were priviously unable to hide, invoke and create data that does not exist and cache them, etc. There is also a common knowledge gap in many beginers, thinking that a get can be a question. If get does not return a reference of a cached, unique object, but a new value object without chacing it/updating it, you can(will) get quite screwed.

It is mostely perfect noob to use getter with conjunction of a setter, sole object returns/assigns, etc.

This topic is closed to new replies.

Advertisement