4 ms·
There's some good, some bad here. Stuff he gets right: * Getters/setters is a nonissue * Operator overloading is a nonissue. I did like how Ceylon handled it
by stickfigure 4y ago
There's some good, some bad here.
Stuff he gets right:
* Getters/setters is a nonissue
* Operator overloading is a nonissue. I did like how Ceylon handled it (operators are aliases for normal spelled-out methods) but honestly overloading is not something I ever miss. And it was a minefield back in my C++ days.
* Dependency management in Java is decent. It's worse in every other ecosystem I've encountered.
Stuff he gets wrong:
* Checked exceptions are horrid. The people who hate them aren't driven by laziness, they're driven by the desire to use standard interfaces - especially now that we have lambdas. You can use `Runnable`! Unless your code throws a checked exception... in which case you have to go through the ceremony of wrapping it. This is stupid. You can have standard interfaces, or you can have checked exceptions, and standard interfaces are vastly more useful.
- sandGorgon 4y agogenuine non flamy question here. why getters/setters. Most frameworks (and not languages) use everything public. Rails, React, golang's frameworks, flask/fastapi. Code has generally not suffered from being public. Would you not accept a Java framework with everything public ? i asked this question on /r/java some time back and got badly flamed. So im trying to understand this. This seems to very philosophical...but then most other frameworks in other languages dont carry this philosophy.
- courgette 4y agoI would not bad an eye. But at this point with records... I don't care. I declare a Integer 'bla' and a 'getBla()' is made available by the IDE right way. Sometimes the records fields end-up being accessible without the getter. ( declaring the record in another class for instance...). But that is also a moot point : all the data they are holding is final and I know what can be null or not.
- stickfigure 4y agoI'm currently working in a Java codebase without Lombok and the habit is to make all fields public for record-like objects. It's fine 99% of the time. Every so often I want to change the behavior of something, and it's a big PITA. For example, maybe I'd like to ensure there's a default value for something that is sometimes null. If access was via getter method, I can just override the getter: class Foo { private final String name; public String getName() { return name == null ? "Default" : name; } } No need to change the hundreds of places that call .name or .getName(). This kind of thing happens often enough that it really should be baked into the language. Lo and behold, most post-Java languages support it, including C# and (modern) Javascript. Java is a bit stubborn in this regard, but Lombok solves the problem in a way that is almost language-native.
- sandGorgon 4y ago>I'm currently working in a Java codebase without Lombok and the habit is to make all fields public for record-like objects. It's fine 99% of the time. this is so cool! thanks for sharing that anecdote. trust me, ur the first person who has ever written this publicly. so I hear your argument for getters/setters. And IMHO, all paradigms do have their usecases -probably so do CQRS and everything else. But ultimately, you can refactor using the tools available today. I would (politely) argue that your example is also a notnull situation and perhaps i would have solved it on initialization, versus the way you did it. Ultimately, you can create getter/setter structures in python as well. But in most large codebases, it still ends up being unnecessary.
- stickfigure 4y ago> you can refactor using the tools available Sometimes. You can refactor your own codebase. If you're working with independent modules, or building libraries that you publish to the world, refactor tools will not help you. You can't refactor other people's code. Even in your own monolith, this kind of refactor is not great. You've turned a 1-line logic change into a patch that spans potentially hundreds of files. Reviewers hate that. > a notnull situation and perhaps i would have solved it on initialization You don't always get to decide that. The data may be serialized in from JSON, loaded from a database, imported from some weird EDI system, etc. Maybe the initialization process is not so simple, and spread out all over the codebase (or even just dozens of constructors). > you can create getter/setter structures in python Python is extremely dynamic and while I can't remember how offhand, I would be surprised if you couldn't simply override variable access the way you can with Javascript (eg, add a `get fieldname()` method). So you don't need "getters" the way you do in Java, which makes a distinction between field access and dynamically dispatched functions (and has performance benefits).
- sandGorgon 4y ago>Python is extremely dynamic and while I can't remember how offhand, I would be surprised if you couldn't simply override variable access the way you can with Javascript (eg, add a `get fieldname()` method). So you don't need "getters" the way you do in Java, which makes a distinction between field access and dynamically dispatched functions (and has performance benefits). So this is the thing - that there is nothing in python at a language level that enables/disables this. it just doesnt give a private construct. same as in javascript. you can add getters/setters if u want. in fact ECMAScript introduced getters/setters - https://www.w3schools.com/Js/js_object_accessors.asp https://www.w3schools.com/Js/js_object_accessors.asp But the thing is, huge huge codebases exist without private. There's nothing that i can see in java that requires private. not to say, ur not wrong...but so it is with almost all patterns. even CQRS. There is a certain level of complexity when it makes sense. The question is - how early do u enforce this ?
- The_Colonel 4y agoIf everything is public, you don't make a difference between an interface and implementation. Meaning, your framework users can depend on any implementation detail and if you change that detail, the framework will break for these users. They will be disappointed since they didn't know they were doing something wrong (all is public and thus available to use).
- sandGorgon 4y agothats a good reason, however a lot of code doesnt need to do these kind of contracts. They are perfectly ok being more accessible to developers than enforce a lot of correctness. Which is where a lot of the JS/Ruby/Python frameworks operate. You're not wrong - my point is that a lot of places, it is not necessary.
- The_Colonel 4y ago> it is not necessary For the price of increased breakage rate. And then people still wonder why many big projects keep choosing Java instead of Ruby.
- JodieBenitez 4y agoProperties being private seems to give Java devs (and also PHP devs to a lesser extent) a false impression of security. The lack of public/private/protected is always a surprise to fellow programmers when I introduce them to Python, even though we still have conventions and it's never a problem in practice. Culture, I guess...
- kaba0 4y agoI don’t know, it seems to be a significant reason why java codebases, no matter how bad and written by how many almost completely separate teams chug along for decades. Empirical evidence does show that Java is very good on the maintainability front:
- JodieBenitez 4y agoWe've all seen unmaintainable monstruosities in any language. I think maintainability is a subject that goes way beyond language features. But if I were to relate a language feature to maintainability, that would be proper typing, not variable accessibility. Even though it's not enforced at runtime, a Python code base with type hints makes a huge difference in maintainability compared to one without. Of course Java has that by default and it's nice.
- piva00 4y agoI use this argument quite often when someone jokingly snark about me working mostly with Java. It's not my favourite language, I've worked with quite a few others, Java has just been the most consistently less painful than anything else. Ecosystem is pretty good, dependency management works; refactorings are easy with modern tooling and the typing system also works fine. Yes, it's verbose as hell and you definitely will depend on some basic tooling to be productive, I've worked in monstrosities that we managed to strip out piecemeal and get the codebase in good shape and modernised, it does require time and an experienced team though. Like you mention, the systems keep chugging along, in places with good engineering practices it's also a given to keep updating those codebases, simplifying and it happens organically when systems are running for 8+ years with 20-30 different engineers rotating in/out during this time. It works, it's not beautiful, it's not concise. It has quirks and gotchas as any language, and requires tooling, but it's quite mature and modernised enough to be a safe bet for bigger projects. Better than any alternative I've had experience with at scale.
- thangalin 4y agohttps://stackoverflow.com/a/1462424/59087 https://stackoverflow.com/a/1462424/59087
- kaba0 4y agoI think there is a fundamental difference between “OOP classes” and data. Java didn’t have a way to differentiate between the two so a convention was created with POJOs with properties, so reflection-based tools could use arbitrary classes in some way. Records are imo a really great addition, making the difference explicit. As for why private fields are important, think of a class implementing a circular buffer with a fixed-size array. Here, the start and end indices used are private state, which is a must for proper OOP — without it it couldn’t enforce class invariants.
- sandGorgon 4y agonot denying "proper OOP". my point is that a lot of code does not need it. If u were writing the exact same code in go/nodejs/python, you would get by fine without it. You would not break the contract of maliciously trying to access variables that shouldnt be accessed. For example, a popular convention is to have underscored variable names (__thisisprivate). Works perfectly OK. 99% of getters/setters dont do anything more. They do exactly this. No validation, nothing. So I'm questioning the ordinary....not the special cases.
- stickfigure 4y ago> You would not break the contract You wouldn't. Someone else would. Without fail.
- lamontcg 4y ago> Code has generally not suffered from being public. I spent 10 years suffering under a ruby app where literally every interface had to be considered public because someone might have gone code surfing and decided to be clever, so literally nothing was a simple code refactoring of private interfaces that nobody should touch. I don't understand what kinds of software people who make this argument write, but I assume it has to be something like web services where the http routing layer is the actual public interface definition and so you're benefiting from strong encapsulation at that layer. Yes, in that case the language doesn't need strong encapsulation because your external framework already provides it for you.
- sandGorgon 4y ago>web services where the http routing layer is the actual public interface definition and so you're benefiting from strong encapsulation at that layer this is actually one of the best ways anyone has put it. You may be right. I have often wondered how does the huge amount of Ruby/Python/JS work in building large companies and products, when Java mandates all this amount of massive complexity. You may be right here - in the web services world, the hard contract of the API layer makes up for less strict encapsulation everywhere else.
- thfuran 4y ago>but honestly overloading is not something I ever miss. And it was a minefield back in my C++ days. For a lot of things, it's fine. And there certainly are potential problems with operator overloading. But the experience of, say, reading/writing, linear algebra code using a C++ library with arithmetic operations on vector and matrix types vs using its java bindings where that's all done through explicit method calls wildly favors C++.
- stickfigure 4y agoIn fairness, that's more or less what I remember (from 20 years ago). Operator overloading in libraries built by incredibly smart people could produce beautiful syntax. Unfortunately, most library builders weren't that smart. Maybe it's better now. As a language feature I can't feel more than ambivalent about operator overloading. Kotlin has it, Java doesn't, I'm ok either way.
- kaba0 4y agoI think Rust’s approach is a good tradeoff. Don’t allow arbitrary operators like haskell/scala (!!< is never gonna be readable), but do give an Addable/Multipliable/etc interface/trait which will define add/multiply, to which the corresponding symbols desugar to. It might even help heal the object-primitive rift in java.
- WkndTriathlete 4y ago> Checked exceptions are horrid. Came here to say exactly this. Exceptions are a poor-man's implementation of an error-handling applicative or monad type. Checked exceptions are especially terrible because their usage forces handling of exceptions in every layer of the call stack above the point where the checked exception might be thrown instead of simply writing a single exception handler at an appropriate layer.
- mrkeen 4y ago> Exceptions are a poor-man's implementation of an error-handling applicative or monad type. True, but in those languages, exceptions can be thrown from anywhere anyway. > Checked exceptions are especially terrible because their usage forces handling of exceptions in every layer of the call stack above the point where the checked exception might be thrown That's not true. Handling a checked exception in one layer means you don't need to handle it in the above layers.
- kaba0 4y agoMy opinion is that error-handling sum types are a poor-man’s checked exception :D Here are my reasons for thinking so: https://news.ycombinator.com/item?id=32944346 https://news.ycombinator.com/item?id=32944346