I don't like getters and setters and prefer direct field access

September 13, 2018

One of the great language divides and system design debates is between direct access to fields in objects and doing things through getter and setter functions. In this debate, so far I come down firmly on the side of direct field access. I have at least two reasons for this.

The obvious reason to dislike getters and setters is that they're bureaucracy and litter. We've all seen codebases that have a whole collection of tiny methods whose only purpose is to get or set a field, and they only exist because someone said they had to (sometimes this is the language, sometimes this is someone's coding standard). Using these methods is annoying, writing these methods is annoying (and I consider that IDEs can automate this to be a danger sign), and just having them around cluttering up the code is annoying. Direct field access wipes all of this extra clutter away.

The more subtle reason I don't like getters and setters is that they obscure what's actually going on. A getter could be a simple field access that will be inlined into your code in many situations (in some languages), or it could be a whole series of expensive operations that talk to a database and so on. The difference between these two extremes matters quite a bit when you're actually writing code that uses the getter, so one way or another you have to know. With direct field access, generally what you see is what you get; direct field access is just that, and method calls are for things that clearly involve some computation (and perhaps a lot of it, you'll want to consult the documentation).

This straightforward honesty matters, because part of the purpose of an 'API' boundary is to communicate to other people (perhaps you could argue that this is its entire purpose). Getters and setters are mumbling; direct field access is speaking clearly (at least in theory).

At this point it's traditional to raise the possibility that you'll need to change the internal implementation of your objects (or structures) without changing the API that other people use. Using getters and setters theoretically allows you this freedom, while direct field access doesn't. One part of my views here is that performance is part of your API, at least as far as slowing things down goes. Because performance is part of your API, in practice how much you can change your getters and setters is already fairly constrained. If you turn a fast getter or setter into a slow one, people will be unhappy with you and they will probably have to change their code.

All of this gives me certain biases in larger language design issues. For one relevant example, I rather wish that Go interfaces included fields, not just methods (although I sort of see why they don't).

Sidebar: The downside of fields in Go interfaces

If you allow interfaces to have fields, not just methods, anything implementing such an interface must have those fields. In other words, such interfaces can only be implemented by types that are structs (or pointers to structs, which is the more likely case). Method-only interfaces have the advantage that they can be implemented by any type, including weird types such as functions or the empty struct.

Written on 13 September 2018.
« A surprise discovery about procmail (and wondering about what next)
How you migrate ZFS filesystems matters »

Page tools: View Source, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Thu Sep 13 01:03:44 2018
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.