Compared to something like a case class in Scala or even autoproperties in C#, writing classes with a bunch of getter and setter methods just to keep state is really tedious.
Compared to something like a case class in Scala or even autoproperties in C#, writing classes with a bunch of getter and setter methods just to keep state is really tedious.
Use public fields, add getters and setters if you have to. Serialize your POJOs using Jackson. All modern data frameworks can deal with public fields just as well as getter/setter combinations.
(Unless you are publishing a public API. In that case, you can't easily convert a public field to a private field/getter/setter setup if needed, as the cat is out of the bag and clients have code against the public field.)
Do I wish there were auto properties like C#? Oh yeah, I'd love that. But I do find modeling fairly easy.
I also lament having to manually maintain equals/compare/hashCode/toString implementations. However, with IDE auto-generation of code (using IntelliJ) makes this merely noisy and annoying, and not a time sink or a constant source of dumb errors.
So considering you can just generate and forget why is it tedious?
Let's remove them and go back to IDE generated goto's !
private(set) var foo: Int
Int foo { get }
etc.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.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.
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.
I guarantee you that you will deal with way more uncertainties than Java.
This getter/setter is a micro-issue/insignificant.
https://github.com/google/auto/tree/master/value
Not the same as what you reference in the other languages, but useful if you find yourself dealing with it in java.
Probably Meijer ...
Anonymous objects can also be really useful.
It is fundamental to OO that implementation details are not exposed. Accessor methods are, by their very definition, not Object Oriented.
It's okay to use them, but you're not doing OO, and you very likely shouldn't be using Java if that's the case.
For example, suppose you have an Employee class that contains the employee ID, name, birth day, etc. Employee records don't do anything. They're just data. Hiding that data makes no sense if the point of their existence is just to hold the data.
I don't reach into the employee class and "get" the employee ID so I can do something with it. The employee class knows what to do with their own ID.
Just like a cashier doesn't reach into a Person's brain for their debit code. The cashier asks them to type it into the keypad, and points them where to do it if it isn't obvious.
Low-level accessors to an "object's" state are almost never an accurate representation of the domain you are modeling -- they're bad design.
If you need them, you've probably missed a piece of the puzzle.
That being said, most programmers don't need to be doing OO at all. The level of guarantee it provides is, for most people, not worth the cost. In those cases, don't use Java.
We will all be having this same argument about functional languages in 10 years. Mutability is not functional, if you're relying on mutability you're probably just doing procedural code wrapped up in functional decorations.
Well, if we're talking Java, not everything is an object. None of the primitive types are, and Java has static methods.
> Just like a cashier doesn't reach into a Person's brain for their debit code. The cashier asks them to type it into the keypad, and points them where to do it if it isn't obvious.
OK, so I picked a bad example. What if you're dealing with records of tree data? Are you suggesting that modelling the domain means that trees should know what to do with the information about their diameter? In what way is that modelling a domain?
In software we're rarely writing simulations of the real world, and even then, it doesn't always make sense to have objects hide information that other agents could just observe about them.
We're usually dealing with information, not actors.
Integrates with the IDE to automatically provide getter/setters and additional features.