Hacker News new | ask | show | jobs
by werkjohann 2752 days ago
I'm curious, is JS your primary language? Getters and setters have been around since ~2010 (other languages also make heavy use of them, like Obj-C). I suspect that you only see this as "invisible" because you first learned a language that didn't have getters/setters (and if you started with modern JS, or Obj-C the fact that properties aren't "dumb" would just be a given). Thoughts?
1 comments

I've been using languages with getters and setters for long enough to be familiar with them. There was a time that I thought they were useful and used them in my own code. But I've been burned enough, and thought enough about language design that I've come to avoid them. I say they're "invisible" because of the property illustrated by these two statements:

foo.bar = 0; foo.baz = 0;

One of these gets compiled/JIT-ed into a few assembly instructions and the other calls an O(n^2) function (with side effects) on a giant tree structure that foo is a part of. You can't guess which is which from looking at those, unless you've read the source for the foo class and memorized which properties are behind setters. They're "invisible" because you can't see when you're using one.

A good property for code to have is that you can infer its semantics from its syntax with as little outside information as possible. When you read a line of code, you should get reliable clues about what that makes the computer do. You might not need to know /all/ the details - e.g. a method call encapsulates the details of an operation but the name (and documentation) give you a good idea of what's happening.

The problem with getters and setters is that they do more than abstract away details, they cloak potentially important semantic information about code in ways that can be misleading.

By contrast, if I read:

foo.setBar(0); foo.baz = 0;

I might not know all the details about what setBar does, but at least I have a clue that it's more complicated than the following line.

I've been burned IRL by this kind of thing - I've seen very expensive getters mysteriously ruin hot loops (making what looked like a linear operation into an O(n^3) operation) and developers pulling their hair out because of setters that silently rejected values and all sorts associated headaches. Working in settings where they came up semi-frequently made me feel like complexity could be hidden anywhere, and reduced my confidence that I understood code that I read.

JS and other languages with reflection have a whole host of associated issues. If a field gets refactored into a getter, it's suddenly not enumerable and will silently fall out of a lot of copy operations. Suppose you want to find every place that the setter gets called, so you grep for `.bar = ` but did you remember the myriad of other ways that setter could get called (e.g. foo["bar"] =, foo[someVariable] =, Object.assign, etc.)?

In my experience, unless you have some extremely strong reason why you can't refactor or some very well-defined standards about when to use them, they're not worth the trouble they bring when code suddenly stops behaving the way you expect it to.

Thank you for writing this. I was on the fence about the utility of getters/setters in js, and wasn’t convinced by your first paragraphs. By the end (“if a field gets refactored into a getter, it’s suddenly not enumerable”), I was 97% on board.