4 ms·
I'm seriously tired of this argument against getters and setters, just generate them with the IDE some also support collapsible regions with a start and end com
by LoneWolf 11y ago
I'm seriously tired of this argument against getters and setters, just generate them with the IDE some also support collapsible regions with a start and end comment, and forget about them.
So considering you can just generate and forget why is it tedious?
- cballard 11y agoIf it can be generated, why doesn't the compiler do it for you? This shouldn't be done at the IDE level.
- zo1 11y agoBecause it's not about tooling, it's about being explicit vs implicit. Though, there is something to be said about having a nice default that you can easily invoke at the code-level.
- raphaelj 11y agoYeah, and loops are just (less powerful) syntactic sugars over jump instructions, too. Let's remove them and go back to IDE generated goto's !
- cballard 11y agoMany modern-ish languages with OO features (Swift, C#) let you declare that a thing has a getter without having to actually write boilerplate, i.e.: private(set) var foo: Int Int foo { get } etc.
- wtetzner 11y agoHaving the ID generate getters and setters makes it difficult read your data types, and adds additional work when modifying them.
- adrusi 11y agoThe best argument is that the compiler doing it add complexity to the language. One might say adding complexity to the language is justified if it means removing complexity from the programmer's workload, but in many languages that attempt to solve this problem that's not how it works out. Most solutions to this amount to allowing programmers to intercept field access via getters/setters. This way they can just use public fields and switch to getters/setters when they need to add special behavior without breaking the interface. Pseudocode: // using methods; no special behavior class Foo { private bar public get_bar() { return bar } public set_bar(_bar) { bar = _bar } } // using methods; special behavior class Foo { private bar public get_bar() { return decode(bar) } public set_bar(_bar) { bar = encode(_bar) } } // using getters/setters; no special behavior class Foo { public bar } // using methods; special behavior class Foo { public get bar { return decode(bar) } public set bar(_bar) { bar = encode(_bar) } } Rather than eliminate complexity from the programmer's workload, this just moves it elsewhere. Instead of tedium, which is something that can be alleviated by simple tooling (copy/paste, editor macros, templated code snippets), you get a constant concern over whether a field access will have unexpected behavior, which is something that can only be alleviated by complex tooling (semantic code analysis). So ultimately this approach adds complexity to the language/compiler, adds complexity to the tooling, and has no effect on the programmer's workload. I'm trying to think of a better approach and the best I can come up with right now is a macro system in the language (one that makes it very clear where a macro is being expanded, to avoid the same problem of "constant concern"). For example: macro #generate_accessors(field) { let paramname = unique_identifier() return #[ public #[ identifier_from_string("get_" + field.as_string()) ]() { return #[ field ] } public #[ identifier_from_string("set_" + field.as_string()) ](#[ paramname ]) { #[ field ] = #[ paramname ] } ] } // no special behavior class Foo { private bar #generate_accessors(bar) } // special behavior class Foo { private bar public get_bar() { return decode(bar) } public set_bar(_bar) { bar = encode(_bar) } } But I haven't seen any language where this is the canonical approach.
- cballard 11y agoYou also have that problem in a language with non-synthesized setters, because there's no guarantee that they don't do anything - and people avoid permitting direct field access, so you'll be going through a setter with unknown behavior. That being said, if you're throwing off side-effects like mad in setters, short of prohibiting either mutability or side-effects, there's not much the language can do to prevent that.
- rakoo 11y agoBecause it's actually useless, having the work been done by someone else or something else means the work is still done, and you still depend on that 3rd-party.
- hodwik 11y agoBetter program in Assembly then.
- rakoo 11y agoI was strictly speaking about getters and setters, and I do maintain that they are completely stupid and useless. If you're writing your 10 kLOC side-project, then sure, just use them and take comfort in knowing that there's a tool out there that you can just add to the toolset. You're (almost) the only one working on this project, there are no clear steps for how to setup a working environment because you gradually built it along the road. But when you're on a 10 MLOC projects that's been touched by hundreds of people for decades, most of which just can't program and aren't there anymore to fix the mess they left, with untouched original parts still being the core of your system, with nobody having a clear picture of how the whole thing works because it's been divided in so many parts that interact through a poorly-defined, undocumented interface, then you become extremely wary of adding anything because you don't want to complicate things further, but you still have to make it work, because it actually solves a problem for the customer. The more you can remove, and the less you need, the happier you will be. Using lombok or having the IDE do it may solve the problem, but there is a much better alternative: remove the problem altogether.
- edwinnathaniel 11y agoTry 1 MLoC project written in dynamic programming language (in this case: javascript) and touched by hundreds developers for 3 years. I guarantee you that you will deal with way more uncertainties than Java. This getter/setter is a micro-issue/insignificant.
- mgkimsal 11y agoI really prefer Groovy's approach - default get/set behaviour is provided at compile time, but you can override in code with explicit getter/setter methods. Really seems to be the best of both worlds.