Lol true
Don't forget all the getters and setters merely updating/reading a variable
Python says "explicit is better than implicit" but Java goes too far with it, and in the most verbose/inflexible ways possible
> and in the most verbose/inflexible ways possible
It's actually extra flexibility meant for two things: being able to override the getter/setter in a subclass, and keeping a consistent interface so users don't need to change how it's called if there was a refactor that adds something to the getter/setter (such as transforming the value because a different representation was more useful internally; particularly useful for libraries).
Python has @property to maintain that interface if need be, but these Java conventions started when no such thing existed in the language. I haven't done Java in a long time, so I don't know if it has it even now..
Is there language support for these in the newer Java versions (I'm not up to date with newer features, since I won't be able to use them on Android anyway)? The reason for these getters/setters is as you said: a workaround for the language deficiencies. It's true for quite a few patterns, and it's not unique to Java; you get similar (in nature) patterns emerging in all languages. Greenspun's tenth rule and all that.
What's problematic is porting these workarounds wholesale to languages that don't have the limitations that originally led to their creation. In Kotlin, for example, every property has an implicit getter and setter, by default - you can override either easily with a dedicated syntax. In that case, insisting on writing explicit methods for getters and setters is simply a misuse of the language. Same in Python, as you note, where you can replace direct access to object attribute with a property without changing the user-facing interface of a class. I think JS also developed a feature like this? It's kind of impressive the OO languages managed to get this so wrong for so long, even though Smalltalk got it right in the 70s...
If your class has any setter function, you're doing OO wrong. Mutating an object should 1) only happen if you have a very good, inescapable reason; 2) never be exposed directly to code outside the class, including children. If your class must have a mutating function, it should be a high level operation, not "set". If it really is "set" then that implies the field being set isn't a part of that object in any real sense.
A well designed class might have a couple of getters, but the inclusion of getters is a deliberate decision to allow client code to see the internal state.
In other words, blame the IDEs for the idea of auto-generating getters and setters. The language itself did a decent job of protecting class state.
A class may need a setter function for some boring, pragmatic reason like, say:
- the language doesn't have keyword parmeters: constructors have only positional parameters
- the class has a large number of properties.
- most users set only a small subset of the properties, defaulting the rest. (And you can't easily predict which subsets are popular enough to get their own constructor variants.)
In that situation you might want to just construct the object in two steps: default everything and set a few selected properties (and then don't touch them). It's de facto immutable, just not around construction time.
But I do agree that in most cases you don't need to call individual setters. And especially not automatically create one for every variable in your class
> being able to override the getter/setter in a subclass
I think even C++ can do this without an explicitly named getter/setter
> and keeping a consistent interface so users don't need to change how it's called
Just use a better language
> Python has @property to maintain that interface if need be
Exactly. Java is unjustifiably limited in this regard
Perhaps you may also appreciate PImpl/D_PTR etc.
This always strikes me as any-benefit mentality thinking. I agree there is some small marginal benefit to this pattern, but the cost (in time, decreased readability and lines of code) is massive. The benefit of being able to change your getters and setters later in a public interface almost never actually shows up.
Most getters and setters aren’t even part of a public interface anyway - because either they’re private or they’re in application code. In both of these cases, you can delay replacing a public class field with public getters and setters until you actually need to. When it actually provides value, it’ll take all of 5 minutes to do the refactor. Intellij can probably do it instantly. And, Spoilers: this will almost never come up in practice. Public fields are almost always fine.
I can see the argument for putting them in APIs exposed in jar or class files without the source. But the tasteless trend of adding getters and setters everywhere just looks to me like cargo culting. Its sheep programmers leading other sheep. You can tell its cargo culting because if you questioned anyone about the practice they would always ultimately justify their actions by saying "oh, I just do it because everyone else does it".
I believe its the responsibility of every engineer to decide for themselves what they think beautiful code should look like. You get some pointless arguments, sure, but the alternative is always a mess.
I for one would rather punch the person who proposes such a global function as the only mechanism for conversion, because charset conversion is a reasonable thing to do on chunked partial inputs, and maintaining the state for conversion yourself is actually quite painful. Wrapping a stream converter into a one-shot function is much easier than the reverse, wrapping a one-shot function in a stream converter.
Said another way: the functional, simplified interface doesn't mean you have to get simplified or lacking functionality. Haskell wouldn't exist if that was the case. The simplified interface providing as much functionality as the more complex interface is possible because the expressive power of JS is leagues above Java - porting Java patterns that emerged due to Java's shortcomings (some call them "design decisions", and they're also right) to JavaScript is simply not a good use of JS as a language.
String.fromUint8Array: (input: Uint8Array, encoding: string): String;
Would be a fine, simple addition where it probably should be. Maybe calling the default for UInt8Array "String.fromBinary" instead.Fight me.
Javascript has a separate TextDecoderStream class if you want to support chunked, partial inputs. The TextDecoder class doesn't support streaming input at all. And it never will, thanks to the existence of TextDecoderStream.
TextDecoder only provides 1 method - TextDecoder.decode(). And the method is pure! So you could just make it a global method without any loss of functionality. The entire class has no mutable state whatsoever. Its just a container for some options, passed into the constructor. Those options could just have been passed straight to a global decode() method.
https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder
This might be idiomatic C++, but its terrible javascript. I had a friend who worked on the Chrome team years ago. He said a lot of the browser engineers who design javascript APIs are C++ programmers who don't know javascript properly. So of course they port C++ ideas into javascript directly. They don't know any better. This is why javascript's standard library is an incoherent mess.
Regardless, it’s a strictly worse api in the general case. And it’s on par with passing around an options object in the case you want to share the same options in multiple places.
If the current api is either the same or worse compared to a pure function version in all cases, I’d prefer the pure function version thanks.
> If the current api is [...] the same [...] compared to a pure function version in all cases, I’d prefer the pure function version thanks.
Why?
No, it would be an explicit dependency.
// definition:
function decodeText(input, [format | options])
// use:
decodeText(someBuffer, 'utf8')
// or:
const opts = {encoding: 'utf8', fatal: true, ignoreBOM: false}
decodeText(someBuffer, opts)
decodeText(somethingElse, opts)
> Why?Because a pure function is idiomatic, concise and clear. Its easier to use, easier to document and easier to understand. The only benefit of a class is that it encapsulates its state behind an interface. That makes sense for a BTree or a database. But TextDecoder has no mutable state. It has no state at all except for its passed-in configuration.
Decoding text is a verb not a noun. In programming, verbs are translated to functions, not classes. You don't have an "adder object" to add things. You don't have to instantiate a JSON stringifier before calling JSON.stringify. If thats not obvious, you may have spent too long in OO languages.
AS3 and Flex was practically an attempt by these people to take over the language. Thankfully that failed.
TS is great by comparison!
I don’t know any good resources unfortunately. I feel like we need a “motherfuckingwebsite” equivalent for this - “just use a motherfucking function”. I want to link it to whoever insisted on a useless TextDecoder class in javascript, instead of just calling .decode(…, “utf8”) on a global function like the rest of the standard library.
I think part of the problem is that most people who hate enterprise java just learn a different language, set their resume on fire and start over somewhere better. That’s certainly what I did. I’m writing rust at the moment, and thankfully the lack of classes and distance from the JVM seems to keep most of this nonsense out. But having all the doubters leave makes the problem within the java ecosystem worse.