Avoid 'Get' and 'Set'
In Access Denied, I wrote about how I almost never create public getters and setters for my objects. When I decide that an accessor is necessary, I do everything I can to avoid using the get
and set
prefixes for them.
Let me say up front that there are languages and environments where get
and set
prefixes are either required or so standardized that it would be foolish not to use them. In those cases, I hold my nose and go with the flow.
But in most cases they’re not required, and should not be used if at all possible.
One of my favorite arguments on the subject comes from Kevlin Henney:
Prefixing queries with 'get' looks clumsy and illiterate. A query should be phrased in terms of the value of interest, not as a command.
— @kevlinhenney
For getters, I completely agree with this tweet. I always try to find an intention-revealing name for a getter – something related to the purpose and behavior of the object if possible, or like Kevlin suggests, something about the value of interest.
For setters, I talked about how I avoid writing the two main kinds in Access Denied:
The setter might be providing an initial value for the instance variable. In this case, I’d much rather provide the value via the constructor or initialization function. That way, the object is born fully-formed and ready to be used for any purpose. There are also no ordering dependencies to be aware of (“make sure you set
foo
before you call any methods”).The setter might be changing an existing value in the object. While this might be necessary in some cases, there’s usually a reason for this new value. I’d rather have a method named for that reason rather than just exposing the state. That way, future changes to the internals of the object won’t leak out to all of the clients calling the setter.
In Ruby, avoiding the get
and set
prefixes is relatively easy. Instance variable names always start with the @
character, so you can always name your getter the same as the instance variable without introducing a name conflict. In fact, that’s what attr_reader
, attr_writer
, and attr_accessor
do for you automatically.
Many languages support Bertrand Meyer’s Uniform Access Principle:
All services offered by a module should be available through a uniform notation, which does not betray whether they are implemented through storage or through computation.
Ruby’s accessors are a way of implementing this principle. Languages like Swift, C#, and Python support properties that enable this principle. And in Smalltalk, everything is done via messages because there is no direct access to another object’s instance variables.
Languages like C++ make things a bit more difficult, because I essentially have to come up with two similar names for the same concept. I’ll do my best here, but I will admit to using more get
prefixes in C++ than I prefer. This just makes me try harder to avoid getters entirely.
Some teams adopt a naming convention where instance variables have an underscore prefix or suffix to distinguish them. This does help with the naming of getters and setters, though I find those naming conventions a bit noisy and somewhat harder to refactor.
In general, my code is always easier to read and refactor when I can avoid the get
and set
prefixes.
I’ll leave you with one more gem from Kevlin Henney (original source unknown):
‘get’ is one of the words with the most definitions in the English language. It takes up pages and pages of the OED and has approximately 20 different meanings. So don’t use it in your code. The only word that I know of that has more definitions is ‘set’, which has about 30 different meanings and covers more pages.