Settings

Theme

Java 21 makes me like Java again

wscp.dev

412 points by wscp-dev 3 years ago · 776 comments

Reader

northern-lights 3 years ago

The biggest feature in Java 21 is the release of Virtual Threads: https://openjdk.org/jeps/444

For some reason, this is missing from the article. If there was any feature that would sway existing Golang developers to switch to Java, it would be this. It would perhaps also convince the haters of the reactive-style concurrency patterns.

  • impulser_ 3 years ago

    I don't think any existing Go developer is going back to Java.

    I worked with Java for 10 years and switched to Go and I will never go back.

    This is mostly because applications and libraries are so hard to reason about and understand due to inheritance, packaging, OOP, build tools ect compared to Go.

    Go is simple. It's easy to understand, read, and maintain. The packaging is like how you would package files on your computer in single folders. The tooling is built into the language. You don't need a IDE like IntelliJ just to make it feel reasonable to work with.

    Maybe all of this has changed, but most of the libraries I see in Java today still look like this.

    • kaba0 3 years ago

      > This is mostly because applications and libraries are so hard to reason about and understand due to inheritance, packaging, OOP, build tools ect compared to Go.

      You are just at the early phase of the project.

      > Go is simple. It's easy to understand, read, and maintain

      My opinion is that Go is too simple, to the point that it hinders understanding and readability. 4 nested loops with random mutability is much worse than a clear Stream api "pipeline". The 31st if err check will not be actually handling the underlying problem, while you can't forget about Exceptions -- even if they do bubble up to the main app, you will clearly get an actionable stacktrace.

      > The tooling is built into the language

      This has benefits, I will give you that. At the same time, I think all these new build tools are anemic and can't be used for anything more complex than interacting with the same language's standard dependencies. Gradle is not sexy, but is actually capable of doing any kind of build.

      • nonethewiser 3 years ago

        Im convinced Go is just an incomplete language masquerading as a simple one.

        • goldinfra 3 years ago

          Go is a complete and simple language, and this is a fairly objective claim.

          Unless by "incomplete" you mean it could have more features. But C++ and Rust (and Java) have been piling on features for years, with no signs that they will ever slow down or stop, proving that they're also "incomplete" by this definition. IMO this is really just a result of there being too many cooks in the kitchen, and a lack of leadership committed to saying "no" to feature requests.

          This is also why using Rust or C++ requires every organization to agree on a subset of the language they will utilize. Rust isn't as far along this path, but it's heading in the same direction as C++.

          But with Go, every organization can use the complete language. That's how simple it is.

          Go has been used by many organizations to build stable, large, and scalable systems that have been operating successfully in production for many years now. That's how complete it is.

        • acje 3 years ago

          I wonder if replacing the type system in Go with the one in Rust and adding native Actor model support would be doable. Or if GC and compile time would regress too much. Modern languages without good sum types just seems like such a lost opportunity to me.

          • kaba0 3 years ago

            What would be the point? Why stick with Go if you want so deep-reaching changes?

            • vmfunction 3 years ago

              That what I often wonder, if one is going to start using a new language why go? Rust at least it gave one memory safety and not having to use GC make it more stable usage of resource as the discord article have already pointed out. Seem like go is just google's .NET, every big corp need to have their own language.

      • kamaal 3 years ago

        >>You are just at the early phase of the project.

        Nah.

        99% of the code written out there doesn't need layers of indirection, responsibility tossing around, Code splitting across classes, design patterns, inheritance and the class jungle that is common in Java.

        Rise of languages like Go is simply majority of the people realising when they want X, they are better of writing just X. You don't have to write a generic version of X that needs to work in a dozen situations. This is for a simple reason. Most of the times, there are no dozen situations. Most, not all the times.

        Most of the code I write, doesn't change all that much. If you are writing code that needs to run for decades in an industry where grifting and job hunting is a daily affair you are doing it wrong.

        • 4m1rk 3 years ago

          > Most of the times, there are no dozen situations.

          After 20 years of building all sorts of software, I know that this a fact, but the challenge is to make others aware of it.

      • tuyguntn 3 years ago

        > You are just at the early phase of the project.

        Lately, I am seeing very few codebases getting supported more than 3 years in companies offering software products. Every 2-4 years services are getting rewritten, what's the point of having tool intended for 15 years, when services are deprecated in 4 years

      • __MatrixMan__ 3 years ago

        It would be good for my job if learned go, but I've been having a hard time because it's just so boring.

        • goldinfra 3 years ago

          You're doing it wrong if you think programming for work is about the code being a means of expressing your inner soul. The most successful professional programmers derive their enjoyment from achieving business objectives, like making products that users love and improve the world.

          If you want to express your soul in your code, do that on the weekend using whatever language you want. Trying to mix these motivations is a recipe for disaster.

          • nemetroid 3 years ago

            > The most successful professional programmers derive their enjoyment from achieving business objectives, like making products that users love and improve the world.

            Successful by what metric? Achieving business objectives? I don't necessarily disagree with the point, but this seems like a truism.

            • iraqmtpizza 2 years ago

              Or a tautology. No true professional programmer would derive more enjoyment from beauty than from making his boss happy.

          • __MatrixMan__ 3 years ago

            I have too much skepticism of "businesses objectives" to be especially interested in success. I want something that'll bend my mind.

        • kakwa_ 3 years ago

          Honestly, just find yourself a project and just Go for it (sorry for the pun).

          The syntax is easy enough you can start coding just after having looked at basic examples.

          Personally I actually like Go because it's so boring.

          I tend to see languages more like tools rather than valuable knowledge I must learn, so a simple yet powerful enough language is a perfect fit for me.

    • jpgvm 3 years ago

      I did. Did Go professionally for ~5 years and went to JVM.

      Go is easy, but it's surface level easy. Building and maintaining large applications in Go if you don't have a huge team is a giant pain.

      JVM (especially paired with Kotlin) for me atleast has meant regaining the expressivity I was missing from Ruby and Python when I moved to Go whilst retaining (well actually usually beating) it on performance and scalability.

      I lost absolutely nothing to go to JVM but gained so many things.

      • chrisdinn 3 years ago

        I’ve got to disagree with this strongly. I built and operated the same large system in both languages (acquisition forced me to rewrite) and both the dev and operating cost of the JVM was much higher.

        Go is a high velocity language. Code reviews on language/style issues are non existent, it’s GC is blazing fast (not our experience with JVM) and it’s really easy to read. I’ve watched many new engineers ramp up on both systems, as both operated side by side for a while, Go was inevitably faster for engineers.

        What made maintaining Go hard for you?

        • jpgvm 3 years ago

          The main pain-points in a large org at least:

          Lack of a "default" stack for nearly anything. The stdlib is great but the ecosystem isn't. Which web framework? Does it come with a logger? If not which logger? Do the third party libraries I want to use work with my logger/have a mechanism to provide one via an interface or am I shit out of luck? This goes for so many more things though, cache libraries, data structures (because Go stdlib collections are a joke). Contrast to Java here you have a relatively minimal set of very long-lived deps for all of these "basic" things. Ecosystems like Spring, the slf4 facade, Apache etc provide the foundation that most Java programs sit on and that has no alternative in Go land.

          Go module transition was also hot garbage. It's better after sure but going through it was worse than Java 8-9 or to Java 11+ both of which were "difficult" transitions for Java but vastly less disruptive for me personally at least. Then take all of this stuff and multiply it by the number of teams you have if you don't have a central team doing library choices and laying down architecture guidelines - which we eventually got but not before all the Go codebases had turned into by and large unmaintainable messes.

          IMO Go is high velocity only in the simplest sense, it's very easy to pump out shit tons of code. With a big team of mediocre developers this is even more true. The problems all come later. Big change in requirements? Good luck with that. Had a team try to go crazy functional with Go and now they have immutable data everywhere and allocations are completely destroying the throughput of the Go GC? Good luck fixing that. etc.

          The velocity eventually moves from it's strength to it's achilles heel once the codebases are big and bad they are really hard to fix.

          I get that most of these problems are "big company" problems and maybe in smaller teams with a stronger hiring bar you won't run into these or maybe not at the same severity but they severely impacted my view of how well the language scales to large teams and codebases.

          • chrisdinn 3 years ago

            Teasing this apart I see a few things: a) logging, b) modules rollout and c) missing frameworks.

            I’ve never had a logging issue in large systems. Explicit error return (as you know, on every function) allows you to log in your code, not lean on only libraries that support your interface.

            Modules rollout was part of growing up. But, you won’t get Go 1->2 upgrade issues as we have 100% backward compatibility on version upgrades. Moving to the latest version of Go is trivial and simply unlocks new features.

            Too many allocations for Go is going to be too many allocations for JVM too. This seems like an problem isolated to that team.

            I’ve done Go at both a three engineer startup and at Google and I can’t help but notice none of these are really the type of problem that crop up later.

            • jpgvm 3 years ago

              Good to hear logging has gotten better.

              Though I still don't see a standard web stack. "stdlib is enough" is only true for people that don't need their hand held and/or can organise good standards across teams.

              If it was just me or people I know are good writing the software that works. At Google it probably works because of aforementioned hiring bar. At the average large-ish company? Not something I like leaving to chance because I have usually ended up disappointed.

            • kaba0 3 years ago

              > Too many allocations for Go is going to be too many allocations for JVM too

              No, Go’s GC is a toy compared to the JVM’s. It is lowerish in latency by actually stopping the application threads when under high contention.

              Java doesn’t slow down the allocation rate, it tries to keep up with the churn.

              • jpgvm 3 years ago

                Even it's latency is outclassed by ZGC and Shanandoah.

                The GC monoculture is great from a simplicity and out of the box experience but there is a very good reason to a) want multiple different GCs tuned for different workload types and b) have competition so that the best designs can be found rather than having to fight to be the only implementation.

              • geodel 3 years ago

                Huh, Go also does not allocate ten times more more memory like Java. So even if Go's GC is 1/10th performant as Java (and it isn't) it will be equally better Go applications.

                Java's GC improvement is relentless because Java's applications are relentless in memory allocation.

                Being on endless Java memory/perf issue prod calls I can say Java GC improvement, performance tuning is cottage industry in itself. Meanwhile end users keep suffering but at least Java devs get to tune GC to their heart's content.

              • chrisdinn 3 years ago

                I’d love to see you elaborate on this. Anecdotally, my experience was the exact opposite. Is there some documentation making this point?

                In the course of optimizing I came to know the various JVM GC algos (concurrent mark/sweep, parallel old, etc) by the corresponding memory graph alone. I never, ever had to debug similar latency in the Go stack.

                • the-smug-one 3 years ago

                  >> (concurrent mark/sweep, parallel old, etc)

                  Both of those are only picked for low sized heaps with few cores, probably within a container. Were these micro services?

                  G1 is the default for larger heaps and multiple cores, and ZGC and Shenandoah (low latency GCs) have to be manually turned on AFAIK.

                  OP said:

                  >Java doesn’t slow down the allocation rate, it tries to keep up with the churn.

                  This is incorrect. ZGC will block a thread when it cannot give a thread any memory, because it can't collect and free memory at the pace needed. Google "allocation stall" for this. ZGC can achieve very low latencies akin to Go's GC, I don't know if the throughput is higher or not. Multiple cores and some GiB of heap space is when ZGC will shine.

          • jppittma 3 years ago

            No web framework, the standard library is enough. log/slog is in the standard library now, and is compatible with zap, which seems to work with everything.

            >IMO Go is high velocity only in the simplest sense, it's very easy to pump out shit tons of code. With a big team of mediocre developers this is even more true. The problems all come later. Big change in requirements? Good luck with that. Had a team try to go crazy functional with Go and now they have immutable data everywhere and allocations are completely destroying the throughput of the Go GC? Good luck fixing that. etc.

            I doublt things would go better for teams trying to go full OO in haskell, or full functional in Java.

            • jpgvm 3 years ago

              The stdlib really isn't enough unless you want num_teams x session handling implementations etc.

              > I doublt things would go better for teams trying to go full OO in haskell, or full functional in Java.

              That is the beauty of Java, no one does this.

              They don't feel like they need, should or will get approval to.

              Go is pretty much the wild west because "the std lib is enough" attitude permeates everything. Build your own datastructures, build your own anything really.

              I can understand why many people find that attractive and hate Java as a result, sometimes Java feels more like Lego and less like programming but it does create predictable reliably constructed software that is generally easy to clean up even if it's done a bit poorly.

              Which is something I value because I often end up in the code janitor role and/or being air-dropped in to get a project back on schedule or drastically cut down the defects etc.

      • cies 3 years ago

        > JVM (especially paired with Kotlin)

        I agree the Go lang compiler/runtime needs "a Kotlin", with more null-safey build in, proper sum types, a std lib that makes heavy use of null-safety and sum types, better story for polymorphism, better ergonomics for writing stream pipelines, and additional compilation targets (like JS, WASM). This all while proving stellar interop with all Go code, obviously.

        Kotlin is quite a sweet deal.

        • chrisdinn 3 years ago

          Curious to understand what you are suggesting here. What’s a better story for polymorphism than duck typing? What would (better?) null-safety look like in Go?

          • cies 3 years ago

            I'm saying that we need an XYZ to Go what Kotlin is to Java. The I name some ways that Kotlin improved upon Java that Go would also benefit from.

            > What’s a better story for polymorphism than duck typing?

            Something that give compiletime guarantees and has not runtime overhead.

            > What would (better?) null-safety look like in Go?

            https://kotlinlang.org/docs/java-to-kotlin-nullability-guide...

      • anacrolix 3 years ago

        Going on 12 years with Go and agree with everything.

    • synergy20 3 years ago

      Go's major selling point to me is that you can ship one binary, nothing beats that.

      Python, Node, Java all have to pre-install lots of dependencies before you can use them, fine for developers, not so great if you want to distribute software for people who are not software savvy, who typically just wants to download one file, install and start using it.

      c and c++ can also do one executable, but, it is not as portable as Golang, and not as static-link friendly as Golang.

      • lenkite 3 years ago

        > Go's major selling point to me is that you can ship one binary, nothing beats that.

        You can ship one compiled binary in Java too if you want it. https://www.graalvm.org/22.0/reference-manual/native-image/

        > Go is simple. It's easy to understand, read, and maintain

        Go involves a lot of code repetition which makes it difficult to human-scan and maintain. Worked on both large scale Go and Java projects and I found Java projects easier and more comfortable to maintain. Had to pay a lot more attention to Go. Go is easier to write though thanks to its well-designed and extensive standard library which is possibly the best in the world, but the maintenance angle still tilts to Java. There are also more Gotchas in Go compared to Java.

        • reacharavindh 3 years ago

          I’m neither a Golang nor a Java developer per se, but I touch source from both as an SRE. I find it weird to see so many comments saying Go is verbose and Java is not. I found the opposite to be true. To do every little thing, the Java code has a ton of abstraction, and the actual implementation of anything is so far removed from the place where it is used that it gives me such a headache to touch anything without wondering “whatever else would break if I change this behavior?!”

          However, the Go code bases I’ve encountered have been less abstract and to the point(even if it means repetition of some little things). I also found it to be free of boilerplate except for the if err != nil part.

          I guess those that have spent decades in such abstractions must have learnt a skill to navigate such a spaghetti. But, I still hate it every time.

          • lenkite 3 years ago

            Quite a bit depends on how the codebase has been written and what era are you looking. Before Java 8/9 or after it. Java code written in the recent era is pretty lean and mean.

            No matter the amount of abstraction though, one rarely runs into the sort of issues in Java that Go code tend to run into frequently - causing multi-million dollar mistakes frequently even for experienced Go programmers. For loop semantics https://bugzilla.mozilla.org/show_bug.cgi?id=1619047, Unintended variable shadowing, common mistakes in slice appends/copies, slices and memory leaks, defers inside loops, nil interface vs nil, panics in go-routines. There are loads of bugs in OSS projects wrt to these usually repeated again and again.

            Go is very simple to learn and very hard to master writing bug-free code. Looking forward to seeing how languages like Rust perform if/when adopted by enterprise.

        • vips7L 3 years ago

          > You can ship one compiled binary in Java

          Even if you’re shipping a jar. You can ship one artifact by using jlink or you ship the runtime in the docker image.

          This has been a solved issue for ages.

      • chii 3 years ago

        > not so great if you want to distribute software for people who are not software savvy, who typically just wants to download one file, install and start using it.

        i think it's a flaw that wasn't considered properly in the standard java toolchain to not produce an embedded java runtime into a final packaged artifact that is self-executable.

        You end up with third party tooling like: https://www.ej-technologies.com/resources/install4j/help/doc... (and https://launch4j.sourceforge.net/ too).

        If oracle bundled this tool into the JDK, it would've not been an issue at all.

        • pjmlp 3 years ago

          It has existed for 20 years, and already started with Sun.

          Having AOT compilers as commercial offerings, was seen as one way to capture value in the Java market, in a culture where most compilers were still commercial, GCC being the exception.

          • coldtea 3 years ago

            >It has existed for 20 years, and already started with Sun.

            In an anemic way, with mostly third party offerings few people know or care about, and various degrees of pain and shortcoming to their use. It should be a first class feature, and as simple to use as is in Go (including for cross compiling).

            In general, if something exists in "some form" for 30+ years in a language, and only a handful of people use it, whereas in another it's used all the time and people from other languages are jealous of how well it works, then the formers "some form" is not a good one.

        • nvm0n2 3 years ago

          There is jpackage and jlink, which don't do single files but make single directory apps.

          These days there's also GraalVM native image which does produce Go-like results. But with everyone using Docker on the server anyway it doesn't matter anymore. People who talk about single binaries are confusing to me. What are you doing where shipping one file is so much simpler than shipping a container?

          • chii 3 years ago

            > What are you doing where shipping one file is so much simpler than shipping a container?

            Desktop applications.

            Java would be a more popular desktop application platform if it weren't for the difficulty in this area (which, to be fair, isn't the only difficulty - cross platform is difficult inherently).

          • synergy20 3 years ago

            it's pretty hard for average Joe to install a docker engine before he can pull and run dockers, plus docker is not that great for cross platform desktop GUIs.

          • otabdeveloper4 3 years ago

            > everyone using Docker

            Not really.

        • javcasas 3 years ago

          That wasn't a flaw. It was a "feature". Can yo you think of a way to increase market awareness of Java other than putting an icon on every computer in the world saying "Your Java needs to be updated" every two weeks?

        • vips7L 3 years ago

          jpackage and jlink are shipped in the jdk.

      • ashishb 3 years ago

        Fully compiled languages have another huge advantage. If you write a tool in Python and targeted say Python 3.10 then people using Phython 3.9 might not be able to use it. So, you really can't use latest and greatest features of Python 3.11 or 3.12. However, with Go, you can build your tool in Go 1.21 or whatever, and the user does not even need a Go toolchain on their machine.

        I was planning to write a small side-project to generate GitHub Actions boilerplate. And this time, I intentionally chose Go for that exact reason. https://github.com/ashishb/gabo

        • pjmlp 3 years ago

          Unless dynamic linking is used, or OS APIs change between version, or specific OS files change location.

          • pkolaczk 3 years ago

            Go binaries are traditionally statically compiled.

            • pjmlp 3 years ago

              Hence my 2nd and 3rd points.

              Also DNS uses dynamic linking unless configured otherwise, while being OS specific, then that are the libraries that rely on cgo.

              • ashishb 3 years ago

                Yeah, you can list 100 such cases.

                Let me tell you the most common scenario. I have a fairly popular FOSS CLI tool written in Python. I cannot use the features from the latest version of Python or else I will alienate ~50% of the userbase. This problem does not exist with Rust or Go.

                This problem would have existed for Java on Android except Google took the burden of "desugaring" the Java 17 code -> Java 8 compatible bytecode for the old devices.

                • kaba0 3 years ago

                  Google dug their own grave here, Java is as backwards and forward compatible as it gets.

      • mdhb 3 years ago

        I never see Dart talked about in these contexts but just to highlight a few things.

        1. Compiles to native code with a single and very reasonable sized binary on pretty much any platform.

        2. Compile to WASM (coming this year) if that’s your thing.

        3. Excellent concurrency support with lightweight and simple mental models

        4. Variables are not nullable by default thus simplifying tedious checking in your codebase.

        5. Syntactically it’s the best parts of Java and JavaScript combined without all the foot guns and verbosity.

        6. Full support for both OOP and functional code styles

        7. Existing interop support with C, C++, Rust, Java and JavaScript and in the future WASI.

        8. Fully static / compile time metaprogramming capabilities coming this year.

        9. Also have maybe one of the best teams working on it that I’ve ever seen in an open source project anywhere. They put in a stupid amount of detail and care to try and keep everything pointing in the right direction at a macro level and have really strong levels of transparency around how the language is developed https://github.com/dart-lang/language

        Honestly I think it’s critically under-rated and under-used. Most of its common criticisms I see about it are many years out of date.

        • tsss 3 years ago

          Combining the best parts of Java and JavaScript isn't exactly something to boast about. Dart lives and dies with the Flutter framework. Other than that it's not doing anything special. Not terrible but also not a significant improvement.

          • mdhb 3 years ago

            I mean you’ve taken my point, cut it in half to remove the relevant context and are now arguing against a point you’ve made up as some kind of gotcha… I don’t know what you want me to say to that.

            Same with your second point. I made a big point to explicitly say I think that right now Dart is very underused and has a huge potential outside of Flutter. Quoting that back to me as though it was something I hadn’t considered is equally as confusing.

            • ihateolives 3 years ago

              I'm with you, I think that Dart is very sensible and very underappreciated language. But he does have a point in saying that currently Dart is tied to Flutter. Google is presenting Dart as a language that you write Flutter with, not as a separate entity. I'd much prefer if Google would present Flutter as a GUI framework for Dart, but alas. Perception is everything. As much as I'd love to start my next project in Dart I probably won't because I can't be sure that Dart won't end up in Google's graveyard in next couple of years whereas I'm pretty sure that Go won't.

              • palata 3 years ago

                I support that. I tried Flutter a few years ago, and I liked Dart and the Flutter way of defining the UI (compared to the old xml stuff in Android).

                Then I moved to Kotlin + Jetpack Compose, and I don't see the point of Dart anymore.

            • tsss 3 years ago

              You say Dart is underused, but why build something new with Dart when you could do the same thing with a better language? The only reason to use it is Flutter.

              • simon_void 3 years ago

                Familiarity comes to mind. Dart has developed into a nice direction with sound null-safety, extension functions, sealed classes and compilation to native&wasm. (The libaries weren't very mature when I used Dart, not sure if that changed.) I'd pick Kotlin because I'm familiar with it, but if mdhb is familar with Dart, maybe from his work with flutter, maybe from a time where you'd mostly use Dart to compile it to js, then go for it. Dart is a nice enough language to earn my thumbs up. (not that that would be important to anyone.)

        • lakomen 3 years ago

          Performance matters. Dart isn't even in the same league.

          And its null handling and checking is the worst.

          I absolutely hate it. Java over Dart any day.

          • sgt 3 years ago

            Dart has excellent null handling[0] so I am not sure if you're perhaps talking of another language? It has had this since release 3.0, if I recall, and has been out for quite a while.

            https://dart.dev/null-safety

          • mdhb 3 years ago

            What specifically about the null checking are you talking about?

            I’ve never heard this criticism before and have no idea what you’re even referring to here but I am genuinely curious..

        • synergy20 3 years ago

          you still need wrap in Dart's runtime though, just like Rust, it's possible to pull in the libraries, it's just not static-link "friendly".

      • cbm-vic-20 3 years ago

        Since Java 9, developers can use jlink to provide a pre-packaged runtime environment bundled with the application. It's not static-link friendly or a single executable, but it does not require the user to pre-install anything or pull dependencies at runtime.

      • paradite 3 years ago

        You mentioned "distribute software" but did not consider Electron for Node.

        You can make an Electron app with JavaScript and ship the binary (or installer) on any platform. It's not a single executable file, but the user experience is the same.

        I don't think there's an equivalent in Go that allows you build a desktop app like that (with frontend and backend both written in Go)?

        • mike_hearn 3 years ago

          You can do that with Java too. The JDK has jpackage, but if you want something better than I'm willing to sell that to you (or give it for free, if you're open source):

          https://conveyor.hydraulic.dev/

          It can be used to ship servers, we use it that way for our own servers. It sets up systemd so you don't need to use Docker. But where it shines is desktop apps.

          Windows users get a little 400kb EXE that installs/updates your app and then immediately starts it without user interaction required, so it's effectively a single EXE. Mac users get a bundle. Linux, well, Linux users get a deb that sets up the app+its apt repo, or a tarball. Maybe in future a FlatPak or Snap or something else.

          It knows how to bundle and minimize a JDK along with your app as part of the release process. Works great for desktop apps.

          It's for Electron too, same deal, easier than Forge in my humble and very biased opinion.

          • synergy20 3 years ago

            Java GUI is less appealing though

            • mike_hearn 3 years ago

              That was true in 2005. Modern Java UI can look pretty great. Two examples:

              1. Start IntelliJ and check it out. It's Swing but it feels modern and fresh.

              2. Go to https://www.jfx-central.com/ ... JavaFX was introduced years ago to add far better support for modern visuals. JFX Central is a website written with JavaFX itself - it runs server side and streams drawing instructions to the client (implemented using a mix of divs, svg tags and css). You can do this because JavaFX implements the CSS2 drawing model. The website looks modern, like any slick website would today, but you can also download and run it locally. It uses Conveyor to do that in fact. The desktop version looks exactly the same as the web version.

            • dzonga 3 years ago

              but it would still be bettter and more performant than electron based apps.

              a little memory heavy, but no more than electron apps while being less janky

              • synergy20 3 years ago

                For me I use neither, I actually picked wxWidgets after all those desktop GUI troubles over the years, not ideal, but it's the best I found for myself.

        • caskstrength 3 years ago

          > You mentioned "distribute software" but did not consider Electron for Node.

          Sorry for the snark, but users will undoubtedly be very grateful to them for not considering Electron.

          • paradite 3 years ago

            I'm not so sure if the users of VS Code, Discord, Slack, etc would agree.

            Yes it's bulky and sometimes slow, but it offers a lot of features and allow developers to ship features and updates really fast, while only needing one codebase for all platform.

            • coldtea 3 years ago

              I'm a user of VS Code and Slack and I'd be very happy if they didn't use Electron.

              >Yes it's bulky and sometimes slow, but it offers a lot of features and allow developers to ship features and updates really fast, while only needing one codebase for all platform.

              Like Slack having 1000x the memory and CPU use for 1/10th of the features a 200K app like ICQ used to have 25 years ago?

              • forty 3 years ago

                I feel vscode is quite good at hiding the fact it's not native, and felt quite snappy when I used it. Slack on the other hand feels painful slow and heavy (and very sensitive to network events like change of network or short disconnections, while native apps are generally much better add handling such glitches for some reasons)

            • nirvdrum 3 years ago

              I can't see users caring about it all being one single codebase and I don't think that they should. Every cross-platform development tool like this means awkward, non-native UIs. Maybe there's something to new feature development. But, I suspect the big players could be a little less profitable and deliver a better experience for their end users.

              I've used Electron as a developer, too. While it may have been fast & easy at one time, I think that argument is losing merit. Electron had a lot of security holes and patching them has made common tasks harder. Security with Electron is a problem in general given its massive surface area.

              Users definitely notice the performance issues. It's certainly not just devs complaining about abstract issues. Yes, people use these tools, but that's mostly out of necessity, not preference. Moreover, big players like VS Code have had to write swathes of the app in C++ for performance reasons.

              I look forward to a return to optimizing for the user, not developer velocity. There will likely always be attempts at cross-platform toolkits and there may be a good solution in that space. I hope Electron isn't the best we can do.

              • paradite 3 years ago

                > Security with Electron is a problem in general given its massive surface area.

                I'm new to Electron development. I've read the docs recommending hardened runtime. Would it be sufficient for security? Can you give examples of such security issues?

                • nirvdrum 3 years ago

                  Here I was referring specifically to pulling in a web browser as a dependency. Chrome pumps out security releases regularly for all sorts of issues. If you're essentially making Chromium the core of your application, you inherit those security issues (setting aside the fact it may happen in code paths you don't use). And, consequently, you need to keep up on updating Electron and distributing new builds to your end users, even if you haven't made any code changes.

                  I'm not suggesting every Electron app is a giant bag of vulnerabilities, just that you have a lot more to keep on than you would writing with GTK or UIKit. And, since everything is bundled with the application, you can't rely on OS updates to fix things for you. You need to cut a new release and distribute it.

                  If you follow the Electron recommendations on security you'll be on the right path. You'll just find common tasks have become harder than they were back when Electron was attracting people with its ease-of-use. I found trying to do type-safe IPC to be an exercise in frustration. If you read the old docs, tutorials, or books, you'll find IPC used to be considerably more free-wheeling. Locking it down is the right trade-off, I think. But there's been an accumulation of many small changes like that. As a result, I don't think the framework is nearly as easy to work with as when Slack or VS Code adopted it.

                  • paradite 2 years ago

                    Thank you for your response. I have previously dealt with IPC for a different project and it was painful indeed.

                    But I found out that there is this new Preload module in electron that lets you use Node.js very easily via normal export and import. I'm using a popular starter template and it works great so far.

            • palata 3 years ago

              Haven't used VScode, but Slack absolutely sucks IMO (on Linux). I don't even want to install Discord, I use it from the website (but I'm pretty sure the Electron app would be similar to the Slack one).

              > Yes it's bulky and sometimes slow, but it offers a lot of features and allow developers to ship features and updates really fast, while only needing one codebase for all platform.

              So you are saying that it is bad for the user (bulky and slow), but good for the developer productivity. I really don't see how the users could like the fact that the developers are being more productive while making a worse app.

            • neuromanser 3 years ago

              Using Discord for voice comms in CSGO on Ryzen 3600x w/ 32GB RAM had noticeable impact on my framerate, big enough that I refused to use for this purpose. No impact using Teamspeak. Both in Windows.

        • synergy20 3 years ago

          electronjs is probably the best cross platform desktops GUI,just a bit heavy.I actually use wxwidgets for GUI desktop apps.

          • troupo 3 years ago

            The best cross platform desktop GUI is Qt.

            • synergy20 3 years ago

              whose license model is a mess unless your GUI is totally open source.

              • wtetzner 3 years ago

                Isn't it just LGPL? Why is that a "mess"?

                • synergy20 3 years ago

                  I'm not a lawyer, I wish it's as simple as "it's just LGPL", it's not.

                  Otherwise Qt has already conquered the desktop GUI world, it did not for a reason: the license mess.

                  • troupo 3 years ago

                    It did conquer (-ish) the desktop GUI world, for a while: quite a lot of software was written in it.

                    And then Electron happened.

                    • palata 3 years ago

                      > And then Electron happened.

                      Which is worse for users, but better for developer productivity (probably nicer for developers too: C++ is not exactly fun).

                      I am still hoping that JVM Desktop apps come back at some point, maybe with Kotlin Multiplatform?

      • saiya-jin 3 years ago

        You can easily pack every single class file and resource into one single .jar if you desire to do so, no external dependency apart from JRE itself. Oh and of course no installation necessary, just put it anywhere with read access, all works.

        At least in the past you could also make a single .exe out of it via 3rd party if you wanted, but I didnt use that for 20+ years so maybe its not valid anymore.

      • mathiasgredal 3 years ago

        You just add the -static argument, if you want a fully static executable that can run on any linux distro: ‘g++ -o main main.cpp -static’

        You can even go above and beyond with cosmopolitan libc v2, which makes c/c++ build-once run-anywhere: https://github.com/jart/cosmopolitan/releases/tag/2.0

        There seems to be some work getting cosmopolitan libc support in Go, but it is not ready like it is for c/c++: https://github.com/golang/go/issues/51900

        Edit: There can be some problems with using static, if you are using your system package manager for library dependencies. I would recommend compiling dependencies from source using CMake and FetchContent, this has solved pretty much all problems I have had with c++ dependency management.

      • ozim 3 years ago

        If you want to distribute app to non tech people you do it via browser ;)

        • synergy20 3 years ago

          there are many apps that are not suited for a browser :(, on some embedded devices with a touch screen, it does not even have a browser and no internet connection either.

          • ozim 3 years ago

            From my POV that is bad example, for those embedded apps you have technical personnel installing and configuring those. Non-technical users don't have any means to install/modify whatever is there.

      • sangnoir 3 years ago

        > Go's major selling point to me is that you can ship one binary, nothing beats that.

        Are .war files no longer a thing? ;)

      • vips7L 3 years ago

        Shipping one binary to install on a users machine has been solved by jlink and jpackage for ages.

      • palata 3 years ago

        How do you distribute a Go library? How do you distribute a Go library that has dependencies?

        • mariusor 3 years ago

          I'm not sure if your question is rhetorical, but Go doesn't have the concept of compiled library that you can link to another binary.

          So in Go you make available the library's source code, and the end-user will download it at build time, or vendor it in the source tree.

          • pjmlp 3 years ago

            Which is a non starter for businesses that don't ship source code.

            • ncruces 3 years ago

              Businesses that want to sell libraries without a source code license can ship APIs.

              • palata 3 years ago

                Not sure I understand what you mean here. How do I ship the API of my library without shipping the library?

              • pjmlp 3 years ago

                Sure, if they don't care about performance.

            • lakomen 3 years ago
              • pjmlp 3 years ago

                Not only it doesn't work in all platforms, it uses a bare bones C API with unsafe code, and it hasn't been removed yet due to backwards compatibility, as Russ Cox already expressed his opinion that plugin was a mistake from his point of view.

              • mdaniel 3 years ago

                > Plugins are currently supported only on Linux, FreeBSD, and macOS, making them unsuitable for applications intended to be portable.

                uh-huh

                but, in all seriousness: I wonder why that is? I struggle to think of a technical reason that go would be unable to load and invoke a .dll even if one had to name it .so https://github.com/golang/go/blob/go1.21.1/src/plugin/plugin...

          • palata 3 years ago

            Right, so it feels like Go hasn't solved this problem. It just completely ignores it.

      • invalidname 3 years ago

        I suggest reading about GraalVM...

    • totallywrong 3 years ago

      > Go is simple. It's easy to understand, read, and maintain.

      Matter of taste I guess, to me Go code looks ugly, it's too verbose with all that error handling every other line which hurts readability. Also the docs are often so cryptic and unhelpful, one needs to rely on examples elsewhere. I do use it though, when I need something fast in a single binary.

      • speedgoose 3 years ago

        My main pet peeve with Golang is to use single letter or very short abbreviations when naming variables. The Golang documentation recommends what is considered a bad practice by most programmers communities.

        • waffletower 3 years ago

          Yes, short abbreviations are brutal in long sprawling code contexts. Write in a compact, functional, and readily unit testable coding style, and those tiny variables reduce your cognitive load and bring great clarity. Use comments and/or docstrings to provide context for compact parameters and local variables once, rather than implicitly documenting with every usage.

          • ctxc 3 years ago

            >Use comments and/or docstrings to provide context for compact parameters and local variables once, rather than implicitly documenting with every usage.

            Context that isn't documented with every usage is context you need to remember. Trade off, but I'd much rather not have to remember multiple contexts for the same name every few hundred lines.

        • classabove 3 years ago

          Are you specifically referring to method function receiver type annotations? Those are often left shorthand but shouldn't exist out of the type definition file anyway eh?

    • arein3 3 years ago

      Exception handling and generics are missing key pieces from go. But adding them will make go look like java.

      I just wish java would add null safety in the type system in a first citizen way.

      For enterprise use java has no competitors. You have c# which is microsoft trying to estabilish nash equilibrium fu*ing the developers. I am a bit worried about ever increasing complexity and a steep learning curve, but seems like this is a problem on all fronts.

      • neonsunset 3 years ago

        Java is an inferior language to C#. To get a superior language you would likely have to go for Kotlin. There is no comparison, because Java gets features today that C# had for years. Not even mentioning having to retrofit green threads because adopting async/await (used by TS, Rust, Swift and other languages) is impossible at this point.

        • bad_user 3 years ago

          C# does not have virtual threads. What C# has is async/await. Which was nice for its time, but at the same time it's an error prone design, as computations should never start async by accident, blocking should be the default. C# also has no useful interruption model. Java's interruption model is error prone, but at least you can work with it.

          Async/await also splits the standard library and the ecosystem in 2 (blocking vs non-blocking, or blue vs red), and it can't automatically update the behavior of old code.

          The introduction of virtual threads in Java also works well with "structured concurrency", as seen with Kotlin's Coroutines. Kotlin's approach to concurrency is also superior to that of C#, actually. But what's interesting about Java is that its evolution is often one that involves runtime changes, lifting all boats. Java engineers preferred pushing more changes in the runtime, and somewhat ironically, the JVM ended up being the true multi-language runtime.

          Java is a good case study of how languages should evolve. It has extreme backwards compatibility, and features being pushed are assessed for how they impact the whole ecosystem, including libraries or languages not in Oracle's control. Project Loom was developed in the open, compared to what Microsoft usually does.

          • neonsunset 3 years ago

            Do give async/await in C# a try, it has all the structured concurrency features other languages have to invent APIs and special syntax for :)

            (if you want to take a look at good structured concurrency, you might be interested in Swift implementation)

            • bad_user 3 years ago

              I worked with C# professionally.

              The async/await syntax works with the language's other statements, but for a long time it had gotchas. It doesn't qualify as "structured concurrency", and it has the aforementioned issues — it's (accidentally) error-prone, it splits the ecosystem in two, and has no interruption model.

              I am not familiar with Swift, but I think you can hardly beat Kotlin's implementation. This is a good introduction from Kotlin's lead:

              https://www.youtube.com/watch?v=Mj5P47F6nJg

              • neonsunset 3 years ago

                What do you mean by "it splits the ecosystem in two"? I never observed such split, certain methods intentionally offer sync and async variants.

                Interruption is achieved through cancellation tokens and has to be handled by consuming methods. There is no way around it because interrupting execution at an arbitrary point would lead to all kinds of issues regardless of the language (unless it implements some form of transaction abstraction and rollbacks all uncommitted changes).

                • bad_user 3 years ago

                  Those "cancellation tokens" from C# are a band-aid.

                  In Java, you don't need to initialize those "tokens" manually, because the interruption signal is baked into Threads. Moreover, a lot of the standard library cooperates with Java's interruption, which is why you see plenty of methods throwing `InterruptedException`; and it's also reflected in types such as `CancellableFuture` or the `Flow.Subscription` (reactive streams). Of course, user-level code that isn't well-behaved, can end up catching InterruptedException, or resetting the interruption signal, without actually interrupting. This makes Java's interruption model somewhat error-prone, but it's workable, and at least it's baked in.

                  Note that interruptions could also be preemptive, as you don't necessarily need cooperation. If you think of the call-stack, or flatMap/SelectMany in reactive APIs, the compiled code could check the interruption flag automatically and interrupt the call chain.

                  And resource leaks aren't necessarily a problem, if the interruption protocol is well-thought-out. In Java, try/finally still works in the presence of interruption, since at worst you get an `InterruptedException`. It's not ideal because you can interrupt the interruption process, and in truth the ideal would be for interruption to be its own communication channel, complementing that of exceptions. But it's totally doable, and here I am familiar with several libraries from Scala's ecosystem, namely Cats-Effect, Monix, and ZIO that show it (with limitations imposed by the runtime).

                  Either way, what C# provides is basically next to nothing. In fairness, some C# libraries tried fixing it, such as Rx.NET, but it's not enough. And the aggregate result in the .NET ecosystem is that interruption is not something people design for. Like what to interrupt a network socket? This ends up being a setting, presented as a timeout in case of inactivity, as a configuration of the connection, instead of a higher-level generic function that can be applied on the consumer side. And the probability for resource leaks goes up actually, because in the presence of concurrent races, you really need interruption.

                • Too 3 years ago
                • pjmlp 3 years ago

                  Except when there is only one version and someone has to write the transition code.

                • kamma4434 3 years ago

                  > regardless of the language

                  That’s a choice, but it is unfortunate for the programmer. The truly right way to do it all is like Erlang does - where all processes are cancellable and nothing bad happens.

            • pregnenolone 3 years ago

              There shouldn't be a reason for a managed language to introduce function coloring. It's horrible.

            • orra 3 years ago

              But async/await is special syntax. I agree it's a nice improvement over using Task APIs directly.

            • pjmlp 3 years ago

              And don't forget to bookmark David Fowler guidelines to avoid all the gotchas that everyone falls into while using async/await.

        • thangalin 3 years ago

          Java, prints 1:

              Set<File> s = new HashSet<File>();
          
              s.add( new File( "c:/temp" ) );
              s.add( new File( "c:/temp" ) );
          
              System.out.println( s.size() );
          
          C#, prints 2:

              ISet<FileInfo> s = new HashSet<FileInfo>();
          
              s.Add( new FileInfo( "c:/temp" ) );
              s.Add( new FileInfo( "c:/temp" ) );
          
              Console.WriteLine( s.Count );
          
          C#, test fails:

              string path = "/tmp/filename.txt";
              FileInfo f = new FileInfo( path );
          
              File.CreateText( path ).Dispose();
              Assert.True( f.Exists );
          
              f.Delete();
              Assert.False( f.Exists );
          
          https://en.wikipedia.org/wiki/Principle_of_least_astonishmen...

          Languages have their strengths and weaknesses.

          • metaltyphoon 3 years ago

            FilInfo doesn’t override Equal operator in C#. HashSet will use it for comparison and those are two different object references so idk what the confusion is here.

            • thangalin 3 years ago

              A set is a collection of objects in which order has no significance, and multiplicity is generally also ignored. Observing the code alone, it isn't obvious that two FileInfo instances having the same path are themselves not equal. As has been mentioned elsewhere, FileInfo should not be hashable to prevent declaring it as a Set, avoiding the situation entirely.

              C# isn't flawless. Java isn't flawless.

        • kaba0 3 years ago

          You can’t decide language superiority by the number of features. While C# indeed has many cool features, I do think it has already went into C++ territory where all the different, independently cool features have very non-trivial interactions that make it very hard to reason about.

          Also, async-await is not a good thing — virtual threads are superior in every way in case of a managed language.

          • neonsunset 3 years ago

            Why async/await is not a good thing? What makes green threads better? Do you know the difference, the issues async/await addresses that green threads simply do not?

            • tomp 3 years ago

              This is code with async/await:

                async fn read_file(filename):
                  f = await os.open(filename)
                  let data = f.read()
                  await f.close()
                  return data
              
              this is equivalent code with green threads:

                fn read_file(filename):
                  f = os.open(filename)
                  let data = f.read()
                  f.close()
                  return data
              
              As you can see, async/await is pure syntactic noise, it doesn't convey any important meaning.
              • neonsunset 3 years ago

                Async enables clear contract for a type that represents a delayed result.

                Better implementations offer eager execution and allow to easily interleave multiple concurrent futures/tasks, like C#. Green threads on the other hand are a workaround to deal with blocking for the most trivial case of cooperative multi-tasking, offering little beyond that.

                • kaba0 3 years ago

                  > Async enables clear contract for a type that represents a delayed result.

                  It's not really a type, otherwise it would be something like Future<T> in Java and plenty other languages. It is usually implemented as a transformation to a state machine.

                  Also, Loom is M:N and calling them green threads doesn't give you the whole picture at all. Not exactly sure what you mean by easily interleave -- functionality wise the two is more or less equivalent. You just get to keep your simpler mental model (and tooling) with virtual threads.

                • tomp 3 years ago

                  with green threads, every result is "delayed" and available exactly when you want it (i.e. as indicated by naive reading of the control flow in code)

                  > eager execution, interleave multiple concurrent tasks

                  green threads give you that for free

                  > deal with blocking

                  blocking is an implementation detail; both async/await and green threads can be implemented on top of either traditional blocking IO, or callback/non-blocking IO

                  I'd be even happier to discuss concrete code blocks / examples, that's where the superiority of green threads truly shines

            • kamma4434 3 years ago

              Because they were created to manually run multiple threads on one physical thread, which is the kind of decoupling that a VM/OS is supposed to do for you.

            • ncruces 3 years ago
            • pjmlp 3 years ago

              Read David Fowler's guidelines.

        • pjmlp 3 years ago

          C# is turning into C++, sadly.

          It appears every six months there must be new language features being added.

          The last one, for declaring fixed size arrays in structs, with an annotation instead of proper grammar change is getting ridiculous.

        • ecshafer 3 years ago

          F# is far superior to C# as a language. If you are going to jump to the .NET runtime that's the tool to go for.

        • throy930493 3 years ago

          C# is a better language, but the JVM is a significantly better ecosystem. Java will always be behind (and type erasure for generics is annoying enough as someone who started in C# that I don't think it will ever catch up) but between hotspot and being the preferred language of 2/3rds of the clouds I think it clearly wins.

          • bcrosby95 3 years ago

            Type erasure is why there's such a rich ecosystem of 3rd party languages that run on the jvm.

            • bmm6o 3 years ago

              Meaning that it would be harder for those languages on the clr because of generics? Would typing all generics as Object not be essentially equivalent?

          • throwaway2037 3 years ago

               type erasure for generics is annoying
            
            I too have spent significant time programming in both C# and Java. This complaint about type erasure in Java: When does it affect your daily life? There are so many craft workarounds available now that it hardly comes up anymore.

            Also, would your opinion of Java significantly change if type erasure was removed or never existed?

            • throy930493 3 years ago

              I have much more experience in C# then Java FWIW, so you're welcome to take my opinions with a grain of salt. I've had a couple of really annoying errors with Beam serializers that took me way longer to debug then I thought was worthwhile.

              I think it is a worse choice, it's too ingrained in the language and ecosystem to change. That and a couple of other nits would likely make me pick Java over C# or Go if I was starting a new project going forward.

          • anoy8888 3 years ago

            If you like jvm, use closure instead.

            • hmottestad 3 years ago

              Sorry you’re down voted. Closure might not be what the author is looking for.

              There are a lot of languages you can use with the JVM, Closure is one of them, Groovy, Scala and Kotlin are some more. Kotlin is gaining a lot of traction, especially since it’s backed by JetBrains.

        • imtringued 3 years ago

          Java 21 doesn't retrofit green threads though. Quasar [0] is a library that implemented fibers for Java and the main developer pron has joined the OpenJDK development team. All that was necessary for first party support is to make the JDK libraries yield when blocking.

          Adopting async isn't impossible at all, there is very little demand for it.

          [0] https://docs.paralleluniverse.co/quasar/

        • kamma4434 3 years ago

          Async/await is an inferior product compared to threads, for so many reasons (function coloring and meaningful stack traces come to my mind). Keeping the same interface as native thread, plus structured concurrency, are best of breed.

          Many uncancellable threads + mutability + goroutine panic kill it all are serious issues for golang.

      • kaba0 3 years ago

        > I just wish java would add null safety in the type system in a first citizen way

        With valhalla (value types), it might just come!

      • guideamigo_com 3 years ago

        Afaik, no language as great of exceptional handling as Java. I prefer Go but I have to admit, Java's checked exception handling is amazing.

        • wscp-devOP 3 years ago

          That is an extremely debatable topic. Which is why kotlin completely ignores checked exceptions.

          Frankly, Id rather have a result and optional/nullable type like in rust/kotlin than deal with exceptions in any capacity.

          • wice 3 years ago

            Kotlin’s decision to make every exception runtime is the main reason I don’t use Kotlin. It’s especially baffling that they realized the issue with implicit nullability and got rid of it (though not with Java methods, which opens another can of worms), then went and intoduced implicit “exceptionality”.

            The correct way to deal with Java’s checked exceptions would have been introducing a Result type, or, preferably, type algebra, like in TypeScript, so something like:

              fun openFile(fileName: String): File | FileNotFoundException {…}
            
            Then you could handle it similarly to null:

              val content: String | FileNotFoundException = openFile(“myfile.txt”).?read()
              …then you have to do a check before you use content as a String…
            
            or

              val content: String = openFile(“myfile.txt”)?.read() ?: “File not found”
            
            (There could also be other possible ways of handling the exception, like return on exception, jump to a handling block, and so on.)

            In fact, null should be treated as an exceptional value the same way all exceptions should be.

            • thewix 3 years ago

              This would be my preference. I like `Either`or some other container type, but a simple union that makes exceptions explicit works also.

        • iopq 3 years ago

          Checked exceptions are gross, they get in the way when you're prototyping, and you end up just ignoring them anyway (since you're prototyping)

          • quelltext 3 years ago

            The ergonomics of checked exceptions may be debatable but compared to golangs explicit error handling at essentially each function call is definitely worse.

            • peterashford 3 years ago

              Yeah, I've got a lot of Java experience and a wee bit of Go language experience and I agree with you. I like Go in almost every way except for it's error handling. It's just wrong to have to check every goddam function one by one

              • pkolaczk 3 years ago

                I guess that's the reason why most Java programs I use cannot do proper user-facing error messages. Because it is so easy to just ignore error handling. The exception will be caught by the top-level, right? This is how almost every Java cli tool prints a stacktrace on even most trivial user errors like file not found.

                Having to deal with errors and forcing the developer to do proper error handling is a good thing.

            • guideamigo_com 3 years ago

              I don't mind Go's errors. I do mind the complete lack of hierarchy in that. Java's exceptions are hierarchical. I can create an exception that specializes from `IOException` and that I feel is really powerful. Go added this half-baked and much later. So, most FOSS libraries don't support it yet.

            • pkolaczk 3 years ago

              Both Java checked and unchecked exceptions are inferior to signaling errors by return values like Go/Rust/Haskell do.

              Exceptions are not composable, cannot be generic, and it is not visible in the source code which lines can throw, so every line is a potential branching point.

        • osigurdson 3 years ago

          I don't think the jury will ever return on this topic.

      • turndown 3 years ago

        Go has had generics for more than a year now

        • simon_void 3 years ago

          I agree, Go has had generics for a little while (of course they are different from Java's generics because Go's type system is different from Java's type system) and I don't think the parent comment writer was aware of that.

        • latchkey 3 years ago

          Not even in the same league as Java.

      • rcme 3 years ago

        What is “enterprise” use? Plenty of enterprises use Go.

        • arein3 3 years ago

          By enterprise I mean a lot of features related to data consistency, scalability and integrations.

          I do not know about go ecosystem, but java and spring have mature solutions that cover the most advanced use cases.

          • Thaxll 3 years ago

            Kubernetes is what I would call very advanced use case.

            But that's the thing with Java, yes there are libraries for everything and one could see that as a problem actually.

            Spring was mentioned before, but it's the perfect example of an overengineered/ heavy library that does a lot of black magic.

            • bcrosby95 3 years ago

              Java is strange because it can be both verbose and magical at the same time.

              Just the other day I ran across an issue where spring was wiring things up correctly on Linux but not Windows.

              • throwaway2037 3 years ago

                I too dislike dependency injection frameworks. I try to always wire manually myself. I'm tired of debugging old SpringFramework apps where changing the JVM by a patch level or changing one JAR dependency breaks the wiring. I have seen it too many times to count.

            • pjmlp 3 years ago

              Originally prototyped in Java, rewritten in Go when a couple of advocates joined the team.

            • jmauritz 3 years ago

              If all you have is spring boot, everything looks like a spring boot problem.

              • eastbound 3 years ago

                Plus Spring is honestly quite badly programmed.

                The pagination object is bulky and unnecessarily complex, where a simple offset/limit is enough (and a nextUrl for cursor-based access).

                When we looked into cluster locks, they’re not even released if one node goes down. I mean, who would need a lock implementation that just stores a line in a DB? And the doc doesn’t even warn about it.

                Apache contributors were much better-skilled.

                • throwaway2037 3 years ago

                      Apache contributors were much better-skilled.
                  
                  That is quite a broad statement. Two negative points about Apache Java libraries I can think of: The original "lang" libraries have not aged well at all. Also: The HTTP client libs are a fiasco. Very challenging APIs and weak documentation.
        • pm90 3 years ago

          Not really. Software first enterprises do. But most enterprises that have a non-software focus generally prefer languages that have been around for a while and are known by lots of people.

          • cdogl 3 years ago

            I’ve written go code for large corporates in Australia who absolutely did not have a tech or software focus. One was a notoriously bureaucratic company which used to be a government owned enterprise. For the niches it fills well, it’s become almost ubiquitous.

            With regard to this:

            > But most enterprises that have a non-software focus generally prefer languages that have been around for a while and are known by lots of people.

            I know developers who work for large blue chip financial sector and other traditional sectors. They’re on the same React/Vue/Webpack/whatever treadmill as all the frontend devs devs working at web dev agencies. And they’re often compiling it down from TypeScript, which has not been around for a very long while at all and is not known by lots of people (relative to the size of the JS community.

            Swinging a bit of Go for a service in an environment like that isn’t really that hard.

        • housemusicfan 3 years ago

          By enterprise he means non-webshit industry.

        • anoy8888 3 years ago

          Wow

          • winrid 3 years ago

            The programmers don't make that call. The CTO does, so they can hire anyone.

      • throwaway2990 3 years ago

        This is definitely one of those. “Tell me you don’t know .NET with out telling me you don’t know .NET” moments.

      • mseepgood 3 years ago

        > Exception handling and generics are missing key pieces from go. But adding them will make go look like java.

        You know that Go has generics since a couple of years now?

    • iampivot 3 years ago

      Coming from Spring Boot with it's 17+ level deep abstractions to Go / gin-gonic was such a breath of fresh air!

      • _ZeD_ 3 years ago

        With the little difference that spring boot offers you 99% of your needs, both to fetch the data from (sql, nosql, you-name-it), and to offer your interface out (web, rest), and programming style (syncronous, asyncronous), and observability, ....

        while for go you'll find yourself deep in the mud of choosing what 3rd part library to use for logging and how to make it work with the rest of custom stuff you have to write

        • kartoshechka 3 years ago

          it's kinda funny to me when people with latest macbooks, loaded with actually useful but comically expensive programs, open up goland that itself has a shit ton of features, to write some error handling in go

      • nprateem 3 years ago

        I went the other way as I was sick of all the repetition in Go. Spring boot/JPA data repositories save so much SQL, and spring boot automatically marshals to and from JSON, form data, etc. It means you can just work on the meaningful business logic. Add on Lombok and there's even less to maintain.

    • pjmlp 3 years ago

      Go is Java 1.0, nowadays 1.5, as they thankfully finally at least added some support for generics.

      I am not touching Go, other than on the projects I have some customer or higher up telling me to do so.

    • hota_mazi 3 years ago

      Go gives you the illusion of simplicity because it gets rid of guard rails and error checking. If you remove all error checking, of course your code is going to look a lot simpler. It's also going to be a lot more wrong and crashy.

      Wait until your code base grows, your team grows to >10 developers, and you will understand what I mean.

      Java (and preferably Kotlin) are a lot more serious about making sure your code is robust before it compiles.

      • segfaltnh 3 years ago

        Wait, are you implying Go doesn't have error checking? In what way? It has famously verbose error semantics.

      • sgloutnikov 3 years ago

        I've heard this argument before, and I point out Kubernetes to them. Is that code base complex enough, because it's pure Go doing just fine and runs on plenty of systems?

        • troupo 3 years ago

          You can point to a complex project in any language, and that would prove nothing.

        • kaba0 3 years ago

          I mean, that’s pretty much go’s first complex application that was specifically written with that, so don’t think it is a good example.

      • javcasas 3 years ago

        > Java (and preferably Kotlin) are a lot more serious about making sure your code is robust before it compiles.

        You are making great points for Rust, Ocaml and Haskell.

        • kaba0 3 years ago

          There isn't all that many plus in their type systems that is not expressible in Java. OCaml and Haskell has Monads, sure. There is Scala for that on the JVM.

          • javcasas 3 years ago

            > There isn't all that many plus in their type systems that is not expressible in Java.

            Thanks to Turing, anything that is Turing-complete can duplicate any other thing that is Turing-complete. So, yes, you can do all of Haskell's types in Java. That is not a flex.

            The flex is doing them in a non-horrific way.

            • kaba0 3 years ago

              The kind of Turing completeness certain type systems have is useless beside academic curiosity - look at the vavr library, that’s what I’m talking about. You can have plenty Haskell types without any hacks, except for Monads in Java.

              • javcasas 3 years ago

                > vavr - turns java™ upside down

                "turn X upside down" are different words for "use X contrary to its original intention and design".

                You will find very few people willing to let go what people undestand as Java so as to be able to do Haskell-in-Java.

                • kaba0 3 years ago

                  It’s goddamn immutable collections and Optionals, not brain surgery come on.

                  It’s not like Java hasn’t been going in the same direction, see records, sum types, pattern matching.

                  • javcasas 3 years ago

                    Yes, it's goddamn immutable collections and Optionals.

                    People still hate it because it's immutable, therefore you can't do hashmap.add(), and it's hard because they can't randomly return nulls, and it's slow because the hashmap now takes o(log n) always instead of o(1) sometimes and o(n) other times.

                    People hate it because it's different to the Java they learnt 20 years ago, that they claim is exactly the same as today.

          • Xeamek 3 years ago

            Is it possible to express Rust enums (tagged unions) and especially the option type in Java? Ofcourse. But the power of good type system doesn't come from the fact if you can express something, but rather how seamlessly it is integrated in to the language.

            • kaba0 3 years ago

              Rust has sum types named wrongly as enums, which java also has as sealed interfaces. The option type is just one example for a sum type, which is as easy to express in Java as

                sealed interface Option<T> permits Some<T>, None<T> {
                  record Some<T>(T value) {}
                  record None<T>() {}
                }
              
              Sure, you have written 3 words more than Rust, and?
    • nine_k 3 years ago

      Go has made many decisions that i'm not happy about.

      If they did one thing exactly right on the language level, it's the [lack of] OOP: interfaces in their implementations, and no inheritance, overridden methods, covariance / contravariance games, etc.

      You can of course write in Java in that style: only extend interfaces, never inherit classes. But many libraries, including the standard library, actively refuse to cooperate.

      • nprateem 3 years ago

        And yet even after writing Go for 5+ years I still have to Google for what actually implements Reader so I can read a file, etc.

      • aarbor989 3 years ago

        Do you mean overloaded methods? You can "override" methods in Go in the sense that if you have an embedded struct you can provide your own implementation in your struct to use instead

    • whateveracct 3 years ago

      Go also sucks. It's so easy to leak threads.

    • nradov 3 years ago

      I never understood some of the objections to inheritance. It always made it easier for me to reason about the code, not harder.

      • FpUser 3 years ago

        Some people are aware about various concepts/paradigms and are able to put each to good use where appropriate.

        Other follow fashion and if some dick looking for fame declares A as obsolete and B as the new and shiny one (to be replaced soon anyways) then the lemmings would follow and sing the gospel.

    • anoy8888 3 years ago

      This is correct. It is about culture too. Java is the kind of language that attracts some mediocre programmers who produce mediocre code based on the wrong ideas of object oriented programming. of course, there are great Java programmers. It is just that a better programming language would help average programmers like us to achieve more

      • x86x87 3 years ago

        That escalated quickly. There are good and less good people everywhere and using language X does not automatically tell anything about you.

        If anything I think the cases where you can use Go successfully are only o fraction of the cases where you can use Java successfully. It's not necessarily Java itself but the ubiquity of the JVM and its ecosystem (see Kotlin, see Scala as examplea that have leveraged this ecosystem successfully)

        • blq10 3 years ago

          So the ideal blub language will be whatever language is too new to really be the legacy thing with tons of black magic you just have to know, but also too old to include tons of new ideas in language design the programmer has to grapple with.

          Old languages force you to understand really core issues because the stack is 1m+ lines of code and you need an operating model for all that magic.

          New languages do the same thing, but it's because half the really good stuff is <experimental>

          Python and JS are in the current sweetspot, go is up next, and after that, Rust.

        • riku_iki 3 years ago

          > the cases where you can use Go successfully are only o fraction of the cases where you can use Java successfully

          could you elaborate why do you think so, and maybe give examples of cases where Go can't compete with Java?..

          • Scarbutt 3 years ago

            Libraries for application programming, last time I used Go nothing came close to the Java PDF creation libs for example.

          • x86x87 3 years ago

            Imho Go is really good for self contained micro-services. The way Go does binaries and the cross-compilation part are great.

            Otoh, Java has a huge ecosystem. Huge. This plus dependency managemnt make it the first choice in most cases. Not even going to go into the massive innertia given that Java has been around for decades (who is going to rewrite everything in go?)

            Today most of the time I pick Kotlin which is sort of whatbJava could have been (or maybe will become) with proper investment and care.

      • za3faran 3 years ago

        Let's not forget who golang was made for:

        "The key point here is our programmers are Googlers, they’re not researchers. They’re typically, fairly young, fresh out of school, probably learned Java, maybe learned C or C++, probably learned Python. They’re not capable of understanding a brilliant language but we want to use them to build good software. So, the language that we give them has to be easy for them to understand and easy to adopt. - Rob Pike

      • sverhagen 3 years ago

        You're entitled to your opinion. I guess I must be a mediocre programmer then. (Don't forget that 90% of developers thinks of themselves as above average.) But if Java can evolve, why wouldn't its practitioners?

      • Xeamek 3 years ago

        In the past, when java was dominant and most popular language - sure.

        Today though, with languages like js being the most popular one, I would be surprised if inflow of mediocre developers into Java world would be even the same, not to mention higher, then with those more popular languages (Go included)

      • throwaway2037 3 years ago

        This generalisation is easy to explain. On the server-side, Java "won" the enterprise battle. In the last 20 years, big corporates re-wrote their server-side C/C++ stack in pure Java (and thick desktop clients in C#). It is so much easier to maintain than C/C++. As a result, they can hire mediocre Java developers to maintain their "new" legacy services.

            who produce mediocre code based on the wrong ideas of object oriented programming
        
        This overlooks this history of OOP. Each decade, lots of new ideas have emerged so that skilled programmers continue to use the same languages (Java, C#, C++, C), but change how they use them. C++ in 1996? Let's fight about diamond inheritance! C++ in 2006? C++ in 2016? C++ in 2026? Repeat for all four languages that I mentioned. The story will look similar. Anyone good writing new code in these four languages isn't using many levels of inheritance. It is gone. Sure, it exists in the language for historical reasons, but it is hardly used in new code. "Prefer composition over inheritance."
      • FpUser 3 years ago

        And some people for no fucking reason think that they're smarter than everyone else and are qualified to tell others how they should go about they business.

      • yMMe2WYE_D 3 years ago

        > attracts some mediocre programmers who produce mediocre code

        That will be reality for most companies, no matter the language. And if Java projects still got delivered in such conditions - it might also be a mediocre language but it is also just good enough.

      • realusername 3 years ago

        Yeah that's not going to be too popular but Java in particular has a tech culture problem. It's way more common to find overengineering and overabstractions in Java projects than any other language.

        The language itself might be fine but I'll never touch it because of that.

      • aarbor989 3 years ago

        Despite the fact that this is a claim with no basis in reality, what you are saying is that people who don't understand the core concepts the language is built on write bad code...Isn't that true for every language?

    • sgt 3 years ago

      This is also the killer argument for going Python, by the way. Go is going to be much faster, of course, but you can still scale quite well with just going Python. And sometimes / most often you don't need scale.

    • aarbor989 3 years ago

      I use Go and Java every day, and Java is way more enjoyable to use

    • datavirtue 3 years ago

      Lol...you use the language most appropriate for the given situation. What's appropriate in the browser....hmmm. Can't slam your foot down on that one.

    • mx_02 3 years ago

      > The packaging is like how you would package files on your computer in single folders

      How does that vary from Java?

  • brightball 3 years ago

    Java 21 has me anticipating the next JRuby release because of Virtual Threads. Charles Nutter gave a talk about JRuby in August where he showed a demo of the impact on Ruby fibers and it’s pretty significant.

    There’s a lot that I really like about the JVM and it’s tooling, I just don’t like writing Java code anymore. JRuby kinda gives the best of both worlds.

    Here’s the talk. Virtual thread demo is around the 45 minute mark.

    https://youtu.be/pzm6I4liJlg?si=GtxQ4MThEaNDfC67

    • kaycey2022 3 years ago

      I loved this. Is there any post comparing Ruby performance with JRuby?

    • kaba0 3 years ago

      How does jruby relate to truffleruby?

      • brightball 3 years ago

        He actually talks about that during the video as well. Short answer is “it depends”.

        IIRC Truffle is dramatically faster in some benchmarks but slower in others. And there are some usability aspects of the language that are negatively impacted.

        • sideeffffect 3 years ago

          I think he shows the performance of running JRuby on top of GraalVM. GraalVM uses Graal (the JIT compiler) in place of C2 (the JIT from HotSpot).

          But TruffleRuby is something different. It is another Ruby implementation (just like JRuby is a Ruby implementation) using the Truffle framework. And Truffle framework requires to be run on GraalVM.

    • ksec 3 years ago

      Wondering if anyone is using JRuby on Rails in production.

  • g9yuayon 3 years ago

    > If there was any feature that would sway existing Golang developers to switch to Java, it would be this.

    Not sure about this, but a trajectory question: why does the Go community have so few concurrent containers but Java community does? I mean, even `sync.Map` is specialized for two specific use cases instead of like Java's ConcurrentMap that is of general purpose. And In Java there are concurrent sets, queues, barriers, phasers, fork-join pools, and etc. I'd assume that even with Go's go routines, we can find great use of such containers, right? At least fork-join is not that trivial to implement. And using mutex everywhere seems just so... low level.

    I understand that there are 3rd-party implementations, but concurrency is so tricky to get right that I would be really hesitant to adopt a 3rd-party package, unless it is as mature as Java's JCTools or Google Guava, both of which are also backed by a large number of users and developers.

    • segfaltnh 3 years ago

      Because the predominant patterns are to do concurrency with message passing, so having multiple goroutines trying to mutate the same container is the exceptional case (though as you say, mutexes are the answer when needed). Another reason is containers are embedded features not stdlib, which has huge implications to how willing someone is to go against the grain, for better and worse.

      • za3faran 3 years ago

        Ironically, golang does not have constructs to build immutable types to pass them around, while Java does (records).

      • bbkane 3 years ago

        Yet another reason is that you really want generics for container types and Go's generics are relatively new

    • throwaway2037 3 years ago

      What concurrent data structures that Google Guava offer than the standard library does not?

  • insanitybit 3 years ago

    `Executor.newVirtualThreadPerTaskExecutor` versus `go` really gets to the heart of why I think that Go developers aren't going to be switching.

    edit: Sorry, it's actually:

        try (var executor = 
            Executors.newVirtualThreadPerTaskExecutor()) {
           executor.submit(...)
        )
    
    instead of `go`
    • erik_seaberg 3 years ago

      You’re likely to need a lot of boilerplate that “go” statement won’t generate: pass and wait for completed results, report errors, timeouts, cancellation, bounded parallelism, pushback, service monitoring.

      • insanitybit 3 years ago

        My comment is perhaps too glib. I'm not trying to say that Go is better, I frankly like Java more. I only mean that if I'm in a Go mindset and I read the linked document on virtual threads, and I see that code example, I'm going to close the tab.

    • mattbee 3 years ago

      Starting a virtual thread in Java isn't that clumsy:

         Thread.ofVirtual().start(() -> System.out.println("Hello"))
    • zaphirplane 3 years ago

      The go example is missing the channels, select, wait group, context, cancellation

      Doesn’t sound like a fair comparison thou the Java version is missing things

      • insanitybit 3 years ago

        > The go example is missing the channels, select, wait group, context, cancellation

        The Java version would require all of those in the exact same way though.

        • za3faran 3 years ago

          Java has structured concurrency in the works, which will not be much more verbose, unlike golang.

    • mike_hearn 3 years ago

      If you want to use that with more concise syntax, there is Kotlin for that. In which case abstracting that is one line of code tucked away in a utility file:

          fun <T> go(body: ExecutorService.() -> T): T =
              Executors
                  .newVirtualThreadPerTaskExecutor()
                  .use(body)
      
      Now you can write:

          val result = go {
             val result1 = submit { slowOp() }
             val result2 = submit { blockingOp() }
             result1.get() + result2.get()
          }
      
      or words to that effect. You can also reduce it a lot in Java too, as mentioned by another commenter.

          class Shortcuts {
              static <R> R go(Function<ExecutorService, R> task) throws RuntimeException {
                  try (....) { return task.apply(service) }
              }
          }
      
      and then you can write:

          var result = go(service -> {
              var result1 = service.submit(() -> slowOp());
              var result2 = service.submit(() -> blockingOp());
              result1.get() + result2.get();
          });
      
      using static imports.

      Now if you're making a cultural point then sure, Java APIs tend to be named quite explicitly. It has advantages when searching or auto-completing, and it's easy to wrap with aliases if you want to abstract a boilerplate pattern away.

    • ivan_gammel 3 years ago

      Wrap it in class Go { static void go(…) } and it will look better with “import static”

      • insanitybit 3 years ago

        I assume `Go` would have to be Closeable and you'd still need the try-with-resources, right?

        • kaba0 3 years ago

          You don't need a try-with-resources, you can manually call close if you want, or has to work in a non-lexical scope.

          But you often want the concurrently running threads to return some results, that try-with-resources is part of the structured concurrency that helps you with closing off a branching point, similarly to how we use while loops instead of gotos. `go` in itself corresponds to `goto` basically, with many of the same negatives.

        • ivan_gammel 3 years ago

          Maybe you re-read my comment, check the signature of Go::go() and think again?

    • kaba0 3 years ago

      So basically executor.submit(). And you still have a language that is significantly less verbose than go, objectively.

    • foolfoolz 3 years ago

      go will always lose vs java when it comes to code verbosity

    • lenkite 3 years ago

      Extend that to a full function and the Go code will be 2x more verbose than Java with all the `if err != nil` stuff.

  • cgh 3 years ago

    Java 21 also previews structured concurrency (https://openjdk.org/jeps/453), which uses the virtual thread implementation. It seems really nice, at least from reading the examples, and removes a number of pain points when dealing with thread-based concurrency.

  • jjav 3 years ago

    > The biggest feature in Java 21 is the release of Virtual Threads

    Is there a good honest writeup on why is this interesting? Very curious.

    The earliest JVMs had this, green threads. Performance was terrible so it was eventually dropped.

    I want to fully utilize every CPU and every core I have, why do I want green/virtual threads again?

    • kaba0 3 years ago

      The JVM automagically swaps out blocking network calls executing in a virtual thread to a non-blocking implementation, so potentially many other requests can be served in the same time.

      So you get the benefit of async frameworks, with none of the negatives: the blocking model is trivial to reason about, read, maintain, and works perfectly with tooling (you won’t get an exception in some WhateveScheduler, but at the exact line where it actually happened. Also, can step through with a debugger).

      • jjav 3 years ago

        Thanks. Any good books that cover the current java performance landscape but is grounded in the history of what came before?

        I used to be heavily involved in java-based server performance and scalability work back in the 90s and 00s but have been working on other things the last decade. But it would be fun to learn more about where things stand.

    • okeuro49 3 years ago

      > I want to fully utilize every CPU and every core I have, why do I want green/virtual threads again?

      If your task is CPU bound, then virtual threads don't gain you anything.

      On the other hand, if your task is IO bound, e.g. for a webserver, virtual threads make it trivial to spin up a new thread per request, for massive workloads.

      https://en.m.wikipedia.org/wiki/C10k_problem

    • mike_hearn 3 years ago

      It's not the same. The earliest JVMs weren't really thread safe at all but machines were single core so it didn't matter, you could just cooperatively multi-task.

      Later HotSpot became thread safe (and fast - a rare achievement), so started using real OS threads so it could go multi-core.

      Virtual threads are M:N threading. There are multiple native threads so you can exploit all the cores, and also user-space runtime managed stacks so you can pack way more threads into a process.

      • jjav 3 years ago

        > The earliest JVMs weren't really thread safe at all but machines were single core so it didn't matter, you could just cooperatively multi-task.

        In the 90s we didn't have multiple cores but we had multiple CPUs. I started using java in '96 on a 2 CPU SPARC and the lack of real thread support was limiting. When green threads was dropped in favor of real (OS) thread support there was much rejoicing. I worked primarily in server performance back in those days.

        > Virtual threads are M:N threading.

        Solaris had M:N threads early on but it also was dropped.

    • tommiegannert 3 years ago

      For me, it's the difference between code structure and resource usage.

      Green threads are for a cleaner code structure. async/await comes quite close, but requires function coloring, creating high coupling. The threads have to have low overhead, so that I don't have to think about whether I should create a new one or not.

      Kernel threads are for parallelism and scaling across cores.

  • waffletower 3 years ago

    From my vantage as a Clojurist, virtual threads on the JVM seem to have very minimal benefits. All I can think of at the moment, is that we could have thread-safe JDBC connectors: https://medium.com/oracledevs/introduction-to-oracle-jdbc-21...

    • eduction 3 years ago

      I mean couldn’t you have the performance equivalent of core.async’s go except with the ability to take across cross function boundaries? That seems pretty huge.

  • jayd16 3 years ago

    I don't think Golang devs are waiting to switch to Java if only making a lot of threads was easier.

    Honestly, its way too early. Virtual Threads will need a a "killer app" (in this case a killer framework) to pull in devs.

    • kaba0 3 years ago

      Like Helidon Nima, Micronaut, Quarkus or recently, Spring?

      • jayd16 3 years ago

        I haven't really used or heard of the others but Spring was already quite good and you really didn't need to think about threads very much. This might help some benchmarks but, again, who is pining for "Spring but with more threads?"

        I'm thinking something that would be a clear differentiater such as a multithreaded GUI framework.

    • bcrosby95 3 years ago

      The great thing about virtual threads is they're basically a drop in replacement for threads.

      • za3faran 3 years ago

        For cases that are IO bound yes. Threads still have their place (another thing that golang doesn't have).

  • kryptonomist 3 years ago

    Go almost instant build time is a huge productivity boost when compared to Java. You get both the solidity of a typed language, and the development speed of interpreted languages (py, js).

    • troupo 3 years ago

      Java's build times are very fast. Java's build tools are anything but. And I'm surprised no one is doing anything about it.

      • palata 3 years ago

        That's because everybody is busy shipping full web browsers with a hard-coded website inside and calling that an "app".

      • kaba0 3 years ago

        Gradle, when the daemon is runnning is very fast, people just often fck up their build scripts to include config-time run functionality, which is just all around a stupid thing to do.

        It only ever runs tasks that actually have to be run, has integration with javac, can work in parallel, and even has cross-company build caches if needed.

        Also don't forget that Java can do hot reloads with the debugger, or with tools like JRebel. Certain frameworks support it 100% and it will be much much faster than whatever go does.

        • troupo 3 years ago

          I've never seen Gradle run fast, even with the daemon running. Gradle itself can take multiple seconds to startup. God knows what it's doing.

          • MrBuddyCasino 3 years ago

            Gradle is steaming pile of garbage. But since the zoomers are allergic to XML, Maven (actually fast) is slowly dying.

            • Phelinofist 3 years ago

              We are in the process of switching to Gradle at work and I'm not sure I like it. I used Gradle when building some OSS projects, but my experience wasn't that great.

              • kaba0 3 years ago

                Just make sure that whoever writes the majority of the build file actually understands gradle, at least its fundamentals. It really is not hard, and afterwards it is a really great tool that can significantly improve compile/CI times.

                • troupo 3 years ago

                  The tool whose main purpose is to build stuff should not demand "understand gradle at least fundamentals so that afterwards you can probable possibly improve times".

                  Why isn't it fast out of the box? Why does the simple "provide a list of deps, provide a list of paths, build" take so darn long? Because Gradle is a great tool or something?

                  Don't forget that it's also already at version 8, where each change is mostly incompatible, bizarre and inexplicable breakages between versions, often due to meaningless option renames. Imagine if they spent all that effort on actually making it a great tool.

            • kaba0 3 years ago

              Gradle is much faster than maven as it can properly parallelize the workloads. Sure, it won’t be visible on a hello world, though.

              • troupo 3 years ago

                I've never seen gradle be faster than Maven. I have no idea what purose its daemon serves or its promise to "parallelize workloads". Which workloads? Its purpose is to build the project, fast. It spends about a magnitude of time more just trying to start up, even with daemon running.

              • throwaway2037 3 years ago

                There seems to be some disagreement to your statement. Can you provide some concrete examples?

              • MrBuddyCasino 3 years ago

                Has never been the case in my many years of using it. Hundreds of MB permanent RAM usage for the daemon (which it wouldn’t require if it was properly designed), everything taking well above 10s. None of this has ever been an issue with Maven.

                • kaba0 3 years ago

                  You can disable the daemon in gradle if you don’t want it.

        • SpaghettiCthulu 3 years ago

          Gradle is anything but fast

      • lenkite 3 years ago

        If you are leveraging Maven, use mvnd during development: https://github.com/apache/maven-mvnd

      • throwaway2037 3 years ago

        If you avoid pre-Java 11 modules in Apache Maven, it is very fast to build. Plus, IntelliJ is auto-magically incremental build. Can you give some specific examples where Java build tools are slow? Most Java developers spend their whole day in an IDE that is doing incremental build, jumping in and out of a debugger to fix bugs or broken unit tests.

        • troupo 3 years ago

          Maven is okay-ish, Gradle is an abomination. Incremental compilation doesn't always work, and the fact that the build tools often spends a magnitude or more time just starting up than actually doing useful work is inexcusable.

  • osigurdson 3 years ago

    I once posted an Ask HN: what are your build times. A golang developer stated their 25 million line project compiles in less than half a second. If that is really the case, I must say, this is very impressive and potentially a reason to switch from other languages.

    • peterashford 3 years ago

      I work on a product written in Go which is considerably smaller than 25 million lines and our compile times are... really... really long. I really don't believe that claim at all. If it's true, I would love to see how it's done because that is SOOO far away from my daily experience.

      • osigurdson 3 years ago

        I was skeptical as well. Thanks for providing feedback. I suspect the way they were counting lines was wrong as 25M lines is a very large project in its own right.

    • lenkite 3 years ago

      Isn't this an exaggeration ? I have a 100k line go project and it takes several seconds to compile. No idea how a 25m line project compiles in less than half a second.

    • kaba0 3 years ago

      Java compiles very fast especially with a running gradle daemon, definitely on comparable levels. It also supports hot reloads to a degree.

      Also, was that a clean build?

  • mongol 3 years ago

    I wonder what will happen with these patterns now. They seem to have been invented to work around the problems with regular threads. Will new patterns emerge, or will the reactive patterns be ported to run on virtual threads?

    • bberrry 3 years ago

      The reactive patterns are now obsolete and will die. And good riddens I say.

  • winter_blue 3 years ago

    I wonder: are virtual thread at the JVM level? If so, would Kotlin (and other JVM languages) be able to leverage virtual threads to improve (e.g. produce more optimal JVM bytecode) for their async functionality?

    • midoBB 3 years ago

      It is a JVM level feature but the Scala guys at ZIO are not that excited about it IIRC.

  • wscp-devOP 3 years ago

    That is true, but there are many who have discussed that. I wanted to bring some attention to the new syntactic changes Java brings that can help with implementing better logic.

  • krzyk 3 years ago

    It depends what one needs. VT are nice, but I don't use threads much, so it is a cool feature I won't use.

    For me bigger feature is pattern matching for switch and records.

  • imetatroll 3 years ago

    No thank you. There is limited time in the day and go fills my needs.

    Go, Rust, Ruby. These three cover all cases.

  • adamsb6 3 years ago

    Will that also make existing Sway developers go?

msgilligan 3 years ago

The title of the blog post is IMO a poor choice. The (hidden) subtitle of the post is "Algebraic data types in Java" which is much more descriptive of the content. A better title would have been "Algebraic data types in Java 21".

Perhaps because of the title, many/most of the comments here are off-topic. I was hoping to see more discussion about algebraic data types, strengths and weaknesses of the Java implementation, technical comparisons to other languages, etc.

  • fatfingerd 3 years ago

    Yes, I'm also not really sure I want to see algebraic types in Java even though I would prefer if a language that focused on algebraic types was more popular.

    All the existing Java code doesn't go away, so is it really going to be nicer to have code like this mixed randomly into that?

    • owlstuffing 3 years ago

      Of all the features most Java devs (and ex-Java devs) desire, algebraic types are near the bottom.

      How about intersection and union types? (NO, sealed classes are not a substitute for unions).

      But, yeah, in my view JDK 21 is a a disappointment. I rarely want pattern matching, but I would like properties please and records are nice, but actual tuples are more useful. Etc.

      • smrtinsert 3 years ago

        I would love a union type in Java, but I still enjoy the language, community and especially development experience. I wouldn't recommend it for everything, but it's sturdy by design and enjoyable for when it fits.

      • mx_02 3 years ago

        I'd love if interfaces worked as in typescript.

        As long as the object signature matches the interface as parameter then you can use it.

    • msgilligan 3 years ago

      Well hopefully it won't be mixed in _randomly_.

      I have some use cases in mind and think it will be very helpful. I have been converting a 10+ year-old code base to modern, functional-style Java and believe that sealed types and pattern matching will help us further simplify our code and eliminate more usages of nullable values.

      A challenge for us will be that we need the core library to stay on JDK 8 for a while. But, in general, I am finding that you can implement a JDK 8 library that works well with newer JDKs if you are careful (and willing to write more verbose code using the older syntax/libraries to support the newer paradigms)

  • wscp-devOP 3 years ago

    I did title it that way at first but ended up changing it at the last second, ended up shunting it off course.

adrianmsmith 3 years ago

The "Sealed classes" feature, as described here, just feels all wrong to me.

They are saying that if you have a (normal) interface, anyone can create a new class implementing it. So if you do

    if (x instanceof Foo) {
        ...
    } else if (x instanceof Bar) {
        ...
    } ...
then your code will break at runtime if someone adds a new class, as that code won't expect it. So the article is saying the solution is to use the new "sealed" interfaces feature, so nobody can create any new classes implementing that interface, and your "if" statement will not break.

Surely object-oriented programming already thought about that and already solved that? (I know object-oriented programming is out of vogue at the moment, but Java is an object-oriented language.)

The solution there is to add a method to the interface, and all your classes implement that. Then rather than having a massive if/switch statement with all the options, you call the method.

That is better than preventing people from extending your code, it allows them to extend your code. They just have to implement the method. And the compiler will force them to do that, so they can't even accidentally forget.

The example given of color spaces (RGB, CMYK etc.) is a great example. I can absolutely imagine writing code which uses color spaces, but then some user or client having a need to use a weird obscure color space I haven't thought of. I wouldn't want to restrict my code to saying "these are the color spaces I support, due to this massive if/switch statement listing them all, the code is written in such a way that you can't extend it".

  • valenterry 3 years ago

    > The solution there is to add a method to the interface, and all your classes implement that.

    What if you don't know all methods that you will need in advance?

    That is the problem and this problem is solved by sealed classes. However, by doing so they introduce a new problem: what if you need more extending classes and you don't know all of them in advance? Which raises the question: is there a way to achieve both?

    This problem is called expression problem. [1]

    There are (statically typed) languages that are able to solve the expression problem, Java is one of them [2]. However, unfortunately the way to do that in Java is (still) very complex and unergonomic, hence rarely used. Languages like Haskell or, if you want to stay in the JVM world, Scala do much better here.

    [1] https://en.wikipedia.org/wiki/Expression_problem [2] https://koerbitz.me/posts/Solving-the-Expression-Problem-in-...

  • pkolaczk 3 years ago

    The solution with sealed classes also allows anyone to extend the code, but in a different dimension than the solution with an interface method.

    The solution with interface method and virtual call is very inflexible when you want to add new operations instead of adding new classes. If you want to just add one new operation, then you have to go to all the implementations and add new methods. And you possibly break the implementations you don't have access to. And all those methods must be defined in a single class, even if they are unrelated to each other. This seriously degrades code readability (and performance as well - those vcalls are not free either).

    The sealed class extends much better in this case. You just add a new switch in one place and done. No breaking of backwards compatibility.

    This is the famous expression problem.

    https://pkolaczk.github.io/in-defense-of-switch/

    • andrekandre 3 years ago

        > If you want to just add one new operation, then you have to go to all the implementations and add new methods.
      
      not necessarily, if you have extension methods (kotlin, swift) you have the option to extend the interface and only override the specific implementation when needed
  • mrkeen 3 years ago

    I understand what you're recommending, and I've seen Bob Martin talk about it extensively (polymorphic dispatch instead of instanceof), but it's something I disagree with.

    To do this kind of polymorphic dispatch, objects have to deal with multiple concerns within themselves.

    In a video game, a Car might have .render(), .collide(), .playSound(). Later on you can add a Dog, which also has those three methods, and you don't need to edit/recompile the Renderer, the PhysicsEngine, and the SoundEngine. And other programmers can add additional entities like this without introducing bugs into my precious code! What's there not to love?

    Well, now both my Car and my Dog need to know about graphics, physics, and sound. And these entities don't exist in isolation. Cars and Dogs need to be rendered in the right order (maybe occluding one another). They'll definitely need to check for collisions with each other. And (something which has actually happened to me in a Game Jam) my sound guy is going to need to step into all my objects to add their sound behaviours.

    I would much rather work in the Physics.collideAll() method, and have it special-case (using instanceof) when I'm thinking about physics, and work in the Graphics.renderAll() method when I'm thinking about graphics.

    A more common example I see in day-to-day backend Java web dev: when I'm sitting in the (REST) Controller deciding how to convert my Java objects into HTTP responses, I much prefer it if I can consider them all in one method, and map out {instanceof Forbidden} to 403, {instanceof NotFound} to 404, etc., rather than putting getCode() (and other REST-specific stuff) into the Java classes themselves.

    • jppittma 3 years ago

      The OO solution is to have a PhysicalObject class that dog and car both inherit from (or use via composition).

      • mrkeen 3 years ago

        Then there's even more scattering around of the logic.

        Good way:

          PhysicsEngine {
            List<Entities> entities;
            doCollisions() {
              // Logic involving instanceof
            }
          }
        
        Bad way:

          PhysicsEngine {
            List<Entities> entities;
            doCollisions() {
              // Delegate to whomever.
              entities.forEach(e -> e.collide());
            }
          }
        
          Dog {
            collide() {
              // What the hell can I do here?
              // I don't know about the rest of the world
            }
          }
        
          Car {
            collide() {
              // What the hell can I do here?
              // I don't know about the rest of the world
            }
          }
        
        
        Worse way:

          PhysicsEngine {
            List<Entities> entities;
            doCollisions() {
              // Delegate to whomever.
              entities.forEach(e -> e.collide());
            }
          }
        
          Dog : PhysicalObject {
            collide() {
              super.collide();
            }
          }
        
          Car : PhysicalObject {
            collide() {
              super.collide();
            }
          }
        
          PhysicalObject  {
            collide() {
              // Not only do I not know about the rest of the world
              // I don't even know how *I* collide, because what am I?
            }
          }
  • kaba0 3 years ago

    It doesn't always make sense to allow extending -- String is `final` for a reason (and one might even argue that final should be the default, and one should explicitly mark with `open` classes that can be subclassed).

    The stereotypical FP example for sum types are a List -- there you only have an Element<T>(T head, List<T> tail) and a Nil(). There is no point extending it, it would, in fact, result in incorrect code in conjunction with all the functions that operate on Lists.

    Also, the Visitor pattern, which is analogous to pattern matching is very verbose and depends on a hack with the usual method dispatch semantics of Java. I do think that pattern matching is several times more readable here.

    • erik_seaberg 3 years ago

      In a world of untrusted code and SecurityManagers, it was critical that strings be immutable so a data race couldn’t bypass a policy decision. The JVM doesn’t have immutable arrays, so string methods carefully protected the embedded array from tampering, and couldn’t be overridden.

      Most classes don’t have this problem. The original authors of a class don’t know what I’m trying to do, and they don’t bear consequences if I (a consenting adult) get it wrong.

  • nine_k 3 years ago

    There are valid use cases for that.

    Consider a security interface of some sort, e.g. such that validates a security token.

    With a normal interface, it is easy to implement it and ignore the token (allow all), siphon off the token, add a backdoor, etc. If a class doing that is somehow injected where a security check is done, it can compromise security.

    Now with a sealed interface, there cannot be new, unanointed implementations. If you get an object that claims to implement that interface, it's guaranteed to be one if the a real, vetted implementation that does the actual security check, not anything else. You've just got rid from a whole class of security bugs and exploits.

kaashif 3 years ago

Nice article as someone familiar with sum types but not sum types in Java.

I don't know if sum types alone are enough to get me to like Java, pervasive nullability is still around and even rears its head multiple times in this article.

  • leapis 3 years ago

    Nullable is a huge issue in Java, but annotation-based nullability frameworks are both effective and pervasive in the ecosystem (and almost mandatory, IMO).

    I'm really excited about https://jspecify.dev/, which is an effort by Google, Meta, Microsoft, etc to standardize annotations, starting with @Nullable.

    • kaashif 3 years ago

      This can never be as effective as changing the default reference type to be not nullable, which would break backwards compatibility, so you can never really relax.

      I know Kotlin is basically supposed to be that, it has a lot of other stuff though, and I haven't used it much.

      • martindevans 3 years ago

        That's basically what c# has done. But it's implemented as a warning which can be upgraded to an error. I think it might even be an error by default in new projects now.

        • kaashif 3 years ago

          Holy shit, how didn't I know they'd taken it this far? This is great! https://learn.microsoft.com/en-us/dotnet/csharp/nullable-ref...

          They actually fixed the billion dollar mistake...

          • 5e92cb50239222b 3 years ago

            They didn't. A proper fix would require getting rid of null altogether in favor of ADTs or something similar. I work with C# daily and nulls can still slip through the cracks, although it's definitely better than @NotNull and friends.

            I haven't worked with Kotlin in a while, but IIRC their non-nullable references actually do include runtime checks, so you cannot simply assign null to a non-nullable and have it pass at runtime like you can (easily) do in C#.

      • foolfoolz 3 years ago

        they won’t change the default reference type to non null. might take a few years but you can see their planned syntax here: https://openjdk.org/jeps/401

    • wayfinder 3 years ago

      I hope they succeed. So many people have tried.

      • mrkeen 3 years ago

        Not having nulls is easy.

        Persuading Java devs not to use nulls is hard.

    • mrkeen 3 years ago

      I was just writing about nullability annotations!

      https://news.ycombinator.com/item?id=37534184

    • netheril96 3 years ago

      Nullable annotations don’t work with well with generics, or at least those tools I use.

  • wscp-devOP 3 years ago

    With valhalla, we will have explicit nullability as well, so that problem will also be handled.

  • pharmakom 3 years ago

    It's also not expression orientated yet.

    • kaba0 3 years ago

      Fortunately switch has now an expression variant. But I would die for an if-else expression (very subjective, but I would prefer a more verbose if-else to ternaries), and especially a try-catch expression!

aranchelk 3 years ago

> Why do we call them product types anyway?

Answer in the piece is not wrong, but put more intuitively and succinctly: the total number of possible value (inhabitants) in a product type is the product of the quantity of inhabitants of the constituent types.

Replace the “product”s with “sum”s and it works too.

Interestingly, the total number of unique functions (judged only in terms of input and output) from a -> b can be found by exponentiation, (inhabitants of b) ^ (inhabitants of a).

  • trenchgun 3 years ago

    >Answer in the piece is not wrong, but put more intuitively and succinctly: the total number of possible value (inhabitants) in a product type is the product of the quantity of inhabitants of the constituent types.

    More intuitively and succintly: product type is equivalent to a cartesian product of sets

  • tubthumper8 3 years ago

    Maps (and lists) are other examples of exponential types. Intuitively this should make sense that these are the same as functions because any pure function could be (theoretically) replaced with a map lookup of pre-computed values. In this context, list is a special map where the keys are integers.

    Writing it out mathematically, given a List of Bool, the left-hand side is the number of elements and the right-hand side is the total possibilities.

    - 0 : 1

    - 1 : 2

    - 2 : 4

    - 3 : 8

    - 4 : 16

    - 5 : 32

    and so on

  • wscp-devOP 3 years ago

    Ill add that in, somehow forgot about that golden bit of info

logicchains 3 years ago

I can't wait 'til Project Valhalla is complete and Java finally gets value types. Then with sum types, value types and goroutines it'll be one of the nicest languages out there.

dzonga 3 years ago

java was never really a bad language.

the people were. if not massive over-engineering. too many abstract concepts that make it hard to grasp a codebase.

code voodoo - in the form of reverse GOTO statement i.e annotations

DI frameworks .

what needs fixing is not the language but the ecosystem. there needs to be a "reformation" movement within the java ecosystem.

yeah people migrating to kotlin or clojure or scala isn't enough.

fooyc 3 years ago

The author cites this to justify the need for Records:

> Most Java objects set every field to be private and make all fields accessible only through accessor methods for reading and writing.

> Unfortunately, there are no language enforced conventions for defining accessors; you could give the getter for foo the name getBar, and it’ll still work fine, except for the fact that it would confuse anybody trying to access bar and not `foo'.

Scala supports pattern matching on objects implementing the `unapply` method.

Is this considered harmful? Why didn’t Java follow this route?

  • wscp-devOP 3 years ago

    it's a matter of standardisation again. Java's standard is like C++; ponderous. The record pattern jep indicates in final footnotes that something like unapply may be in the works, so all hope is not lost.

YetAnotherNick 3 years ago

Java was always a great language. It's the enterprisy ecosystem that make me want to throw up. To implement a line of logic, I have seen dozen classes and interfaces.

earthboundkid 3 years ago

道生一,一生二,二生三,三生萬物。萬物負陰而抱陽,沖氣以為和。

The Function gives birth to the Unit type. The Unit type gives birth to the Boolean. The Boolean gives birth to the Value type. The Value type gives birth to the Top type. Each Top type contains 0s and 1s, thereby bringing harmony to the computation.

truth_seeker 3 years ago

Golang is simple, smart and opinionated subset of Java/C#.

Everything moves slowly in corporate world. It will take another at least 2-3 years for large community of Java ecosystem and average devs to adopt Java 21 and capabilities.

  • kaba0 3 years ago

    Go is just a dumb subset hyped up as simple, but it is useless and slowly it will have to introduce all the remaining pieces in some ugly way as they didn’t plan with them ahead of time - see generics.

    • truth_seeker 3 years ago

      That is exactly what I used to think when I started with it. But I changed my opinion after 6 months with Go and eco-system. It's not ugly, it's different and much more concise.

jjtheblunt 3 years ago

Is there any widespread concern over lack of unsigned int native types?

  • kaba0 3 years ago

    Not really. With valhalla they can be user-implemented efficiently, although without syntactic sugar like +.

    • jjtheblunt 3 years ago

      Does that mean addition would look like

        Uint32 a,b,c;
        c = a.plus(b);
      
      in what you describe, once project valhalla is complete?
      • kaba0 3 years ago

        Well, that will be available as a basically zero-cost abstraction. But I haven’t seen more specific mention of it in the mailing lists/design proposals - they definitely didn’t want to add a new primitive type, but perhaps if they manage to heal this rift between objects and primitives and it will only be add syntax-level complexity, they might go for it.

pharmakom 3 years ago

the argument for Java seems to be that it's gradually gaining features we already have in Scala, Kotlin, OCAML, F#, etc... so why not use the languages that have those features today?

  • agrounds 3 years ago

    Inertia. There are still a ton of Java shops out there, and many of them will not switch even partially to another language anytime soon. The hope is that these orgs might find it easier to upgrade to Java 21+ than to learn and start using Kotlin/Scala/etc. I fully expect I might find myself working at such an org again, and when I do I’ll be grateful for newer Java features.

    Signed, a dev who would never willingly choose Java over Kotlin for anything ever again.

  • msgilligan 3 years ago

    One thing about "gradually gaining features" is that the Java language architects do a very good job with backward-compatibility. This means that your application/library will be easier to migrate to newer versions of the language and you will continue to have a large number of 3rd-party libraries available. The Scala community is currently migrating to Scala 3 and many libraries have not been ported (Scala experts correct me if I'm wrong.) Kotlin also seems to be less stable at the API level than Java (but I may be wrong here, Kotlin experts please correct me.)

    This backward-compatibility does comes with costs (e.g. non-reified generics)

    Also, if you're a library developer and you want to create a JVM library that can be used by Scala, Kotlin, etc. developing in Java is often the best choice. For one thing it avoids any dependencies on the standard libraries of those other languages.

    Disclaimer: I like Kotlin and Scala, but mostly use Java.

  • MagicMoonlight 3 years ago

    Because Java will still exist in 5 years

andrea76 3 years ago

I hate Java because the docker containers based on it take too much RAM. The smallest Spring JAR takes about 70-120 MB for a single container!

ahurmazda 3 years ago

My favorite go feature (not exclusive to go) is `implicit` interface. Once I drank from that cup there is no going back!

michaelcampbell 3 years ago

What a weird title change.

  • wscp-devOP 3 years ago

    did that to make it a bit clearer what I was really optimistic about, but I unfortunately can't edit the hn post itself.

billfruit 3 years ago

Does it add value types?

  • wscp-devOP 3 years ago

    Thatll probably come in about a year or so going by the pace of valhalla's completion.

jjtheblunt 3 years ago

Is there an Ocaml vatiant for the JVM (similar to F# for dotnet)?

mathisfun123 3 years ago

any advice on a book/tut to learn "modern" java?

  • msgilligan 3 years ago

    Manning's Modern Java in Action is outstanding. It assumes you already know basic Java.

    https://www.manning.com/books/modern-java-in-action

    • mathisfun123 3 years ago

      both suggestions here are for books that cover java 8. how is it possible that java 8 is modern relative to java 21?

      • msgilligan 3 years ago

        Modern Java in Action (the 2nd edition of Java 9 in Action) covers Java 11 and contains a final chapter that talks about "future Java" features -- many of which are now implemented.

        It's a great book for Java programmers who want to make the jump to functional-style programming. If that's the transition one is hoping to make, then I would definitely recommend the book.

      • Tomte 3 years ago

        Core Java for the Impatient (3rd) is less than a year old and updated for Java 17.

      • msgilligan 3 years ago

        ... and I agree that there is a need for a Java 21+ book which includes discussion of algebraic data types, pattern matching etc.

  • Tomte 3 years ago

    Core Java for the Impatient by Horstmann.

acheron 3 years ago

In other news, we have an upgrade path at work to go from Java 8 to Java 11 pretty soon.

  • MBCook 3 years ago

    We (finally) upgraded last year from 8 to 17. Lots of nice things, I’m so glad we were finally able to. But it was a big project due to some dependencies and how some things were done internally.

    I can’t wait for 21, but I’m not sure when we’ll switch. At least it will be trivial compared to leaving 8.

  • taf2 3 years ago

    do/i/still/need/to/create/sub/directories/for/the/things/i/want/namespace?

    • mdaniel 3 years ago

      Only if you're using vim like someone from the 70s, otherwise any sane IDE handles those things for you

      But, yes, namespaces are still mapped to paths, it's not like they rewrote the JVM to use blockchain or something

      • imbnwa 3 years ago

        >Only if you're using vim like someone from the 70s, otherwise any sane IDE handles those things for you

        I don't think that's quite it when Ruby is also from the 90s and figured out not to tie namespace resolution to the directory tree

        • unlikelytomato 3 years ago

          I am not sure why this is a problem. Looking at the organization of the resources directory of every project I've ever worked on, I am not sure I want more opportunity for physical and logical concepts to unnecessarily diverge.

        • segfaltnh 3 years ago

          Let's not hold ruby up as a poster child for modularity.

      • ttyyzz 3 years ago

        Yeah I really like my IDE doing stuff in the background without me knowing shit about it.

        • piva00 3 years ago

          Yeah, I do like my IDE doing the tedious work for me. It's also really nice to unzip any JAR I need to troubleshoot and know exactly where to navigate to find exactly the file with the code I need.

          I like Golang a lot but the standardisation and verbosity in Java-land has some benefits after you get used to it enough to learn to ignore the boilerplate, it's pretty good to have some kind of consistency enforced by the VM when working in large codebases.

          • quickthrower2 3 years ago

            Yes some C# codebases end up with wildly inconsistent namespacing as you can do anything you like

        • threeseed 3 years ago

          I don't understand how it is doing stuff in the background.

          You literally ask it to move some class and then it does it. And it's very obvious what it's doing.

        • Too 3 years ago

          Then you’d be thrilled to hear about all the stuff your NVME drivers are doing in the background without you knowing shit about it. Or maybe you prefer to engrave your ones and zeroes in stone by hand?

          Abstractions exist for a reason. In Java, that abstraction is coding in classes and packages, not files of text.

    • chii 3 years ago

      better_than_having_just_a_single_file_that_have_lots_of_functions_without_namespacing

    • wscp-devOP 3 years ago

      Yes/you/do/but/the/ide/does/it/for/you/so...

      • javcasas 3 years ago

        The/ide/giveths/the/ide/takeths/all/this/could/be/easier/and/you/know/it.

    • paulddraper 3 years ago

      Yeah, just like Python, Ruby, JavaScript.

  • approxim8ion 3 years ago

    We made the jump from 8 to 17 this year! Some of our developers of course still write 1.6 level code, of course

  • hmottestad 3 years ago

    Going from 11 to 21 is a lot easier.

    • leapis 3 years ago

      Depends- one of the hardest parts of the 11-20 upgrade for us was that cms gc was removed.

      If you run a bunch of different microservices with distinct allocation profiles, all with high allocation pressure and performance constraints, and you've accomplished this w/ the help of a very fine-tuned CMS setup, migrating that over to G1/ZGC is non-trivial

      • xxs 3 years ago

        Java sort of suck for microservices (microservices suck on their own) as it has relatively high bootstrap cost.

        High allocation rate feels weird with micro services - I suppose that depends a lot on the coding style. G1GC is meant for generally large setups, with several cores at least. E.g. the default setup of 2048 areas on 2GB heap means, allocations over 1MB require special care.

      • bberrry 3 years ago

        I can't help but think if you're teetering on a knife's edge, only holding on thanks to hyper tuned GC params, then you should take a step back and consider getting out of that predicament.

      • hmottestad 3 years ago

        Is that what happened at your company?

        • leapis 3 years ago

          Yup. We've clearly benefitted- G1 and generational ZGC have large advantages over CMS- but it's a lot of experimentation and trial-and-error to get there, whereas other deprecations/removals are usually easier to resolve.

          • kaba0 3 years ago

            Isn't the default config correct for pretty much all workloads, unless you have very special requirements? Like, at most one should just change the target max pause time in case of G1, depending on whether they prefer better throughput at the price of worse latency, or the reverse.

  • rendaw 3 years ago

    What were the backward incompatibilities preventing that move? I thought Java was pretty backward compatible, but I've heard this a lot.

    • chii 3 years ago

      It's more likely that there's some dependency that is not easy to upgrade, because the upgrade also includes api changes (from the dependency, not from the jdk).

      Compound this with multiple dependencies that exhibit this issue. If you have a "legacy" application that does not require active development, there's zero business incentive to invest into the upgrade. Unless you could prove value in having the upgrade, it just doesn't get prioritized.

    • wscp-devOP 3 years ago

      Java has in recent times actually removed some apis from the standard library, and made some inaccessible (undocumented internal apis especially) so any advanced frameworks that use them would have been affected.

  • sebazzz 3 years ago

    7 -> 8, but JBOSS 6 is a pain to migrate away from.

  • kyawzazaw 3 years ago

    8 to 17 for us

neonsunset 3 years ago

Sad this gets to front page while a blog post which documents that .NET 8 has 200 A4 pages worth of performance improvements gets absolutely ignored.

C# keeps being the language people are looking for but don't know about.

  • paulddraper 3 years ago

    It's because C# only "recently" became cross platform in a reasonable way.

    Hard to overstate the mindshare that it lost for that

    • 5e92cb50239222b 3 years ago

      And it's still not as cross-platform as Java is, or pretty much all other tech stacks. FreeBSD and commercial UNIXen are not supported at all. If you prefer to develop on macOS or Linux (hi there), you don't get access to many Windows-only tools (mostly for debugging and performance measurement). Microsoft only cares about other operating systems to inasmuch as you can host the resulting application there, but really expects you to develop on Windows. Which makes sense... for them.

      • neonsunset 3 years ago

        For Linux and macOS you can use Rider and CLI tooling (as expected for most other langs), VS Code is up there but obviously does not come with profiling or advanced debugging tools.

        The bias does exist but it's going away, especially that now a lot of developers are moving over to M-series macs.

  • kaba0 3 years ago

    Since it is a Java thread, I’m gonna mention that ecosystem-wise, the JVM is just much much bigger and of higher quality - you very often see copied JVM packages in C# with much less features, less stability, and often even being paid.

    With that said, it is a cool language and platform, that is indeed underhyped.

    • olavgg 3 years ago

      This 100x, C# and Java are also very similar programming languages. C# may be a better language, but the difference is minimal. Most C# developers claiming that C# is a better language often don't know Java. I remember one C# guy telling me that Java didn't have closures before Java 8, which was not quite true. Java developers had access to Groovy which had closures. Groovy may be another programming language, but it has always had 99% Java syntax compatibility and they both compile to the same byte code and work seamlessy together. Groovy 4 also has LINQ if you like that. And using Groovy is no harder than including it as a dependency in Gradle/Maven.

      Java eco system is so vast, and of top notch quality, with excellent documentation available for free. It enables businesses to move faster, at a pace most other languages cannot offer. It's not perfect, especially I find data sciene libraries lacking in Java compared to what the Python eco system offers. But depending on the task I try to choose the right tool for the job, not the same language for every job.

      • raziel2p 3 years ago

        Groovy is... not Java.

        • olavgg 3 years ago

          I think it is, just as Gradle is Java. Groovy is a superset of Java, and makes some parts of Java development better. I for example write many tests with Groovy or implement DSLs for my clients with Groovy.

  • mrkeen 3 years ago

    I've written in C#. It's Java. If they're not the same language to you, you need to learn more languages.

  • mu53 3 years ago

    Its a good language, but the corporate sponsor and community is suspect. Microsoft has a long history of user hostile actions. The types of companies that use C# often treat SWE as second class. Learning and using C# limits career options to low salary, high stress jobs.

    • neonsunset 3 years ago

      I'm going to vouch for this comment but not because it is correct but rather it presents good opportunity to address the concern.

      C# and .NET are most heavily invested in by Microsoft which owns and steers its development, that is true. It is also true that JVM world sees investment from multiple MSFT-sized corporations.

      And yet, despite the above, it keeps moving forward and outperforming Java on user experience, performance and features despite being worked on by much smaller teams. I think it stands on its own as a measure of a well-made technology.

      In addition, you can look at source code and contribute yourself, 90% of what makes .NET run is below. Almost all development happens in the open:

          https://github.com/dotnet/runtime
          https://github.com/dotnet/installer
          https://github.com/dotnet/roslyn
          https://github.com/dotnet/aspnetcore
      
      Could Microsoft do a better job at making it even more community-facing and attempting to make the .NET foundation as a sole owner and steering committee of the language itself? Sure. But it's not that bad either today. Quick reminder - Oracle is not exactly a saint, perhaps even worse (MSFT has never gotten into any litigation even remotely related to .NET or C#).

      As for career opportunities, as other commenters would note, this is highly specific to a region and does not translate globally. Again, we are discussing the "how good the language/platform is" first and foremost. I don't see startups adopting Go because of the market or trusting Google not to rug pull them...so perhaps we can do a better job so the next language of choice they pick is C#, which has much higher ROI in the hands of the good developers (for example, it can be very easy to adopt as a second language if you are well versed in Rust).

      • catlover76 3 years ago

        I don't have as much experience or knowledge as others in this thread, but just taking the opportunity to chime in that C# is a great language, and pretty pleasant to work with. And it was a language to which I was introduced as a 24 year old at a venture-backed startup, not at like Boeing or the company Dilbert works at or something.

        It has features like LINQ. It has routinely had a lot of good updates, new features always coming out, increases in performance, etc. The primary thing lacking has been good support for developing and deploying on Linux, and a couple other devops-related things. It's a shame to see that holding it back, but at least MSFT actually opened up Linux support at all (nobody thought they would).

      • bbkane 3 years ago

        See https://isdotnetopen.com/ for why people think .NET has openness issues

    • Bognar 3 years ago

      Microsoft uses C# internally and has a vested interest in making it better for all of its own developers, as well as making it good to increase industry adoption so it has a larger pool of skilled developers to hire from. Your arguments about who backs the language don't hold water.

      • iopq 3 years ago

        Does it have a vested interest to make everything work cross-platform?

        • neonsunset 3 years ago

          Well, Linux has won the cloud meaning it is and will be a primary target for .NET.

          I'm not sure what vested interest MSFT had in some of the changes introduced for iOS in .NET 8, but now it can be targeted with NativeAOT too, so there is clear investment and dev effort both from community contributors and MSFT employees to support various platforms.

          Somewhat arbitrary example, there is also a project to support RISC-V (https://github.com/dotnet/runtime/issues/84834).

        • Bognar 3 years ago

          For both reasons mentioned above, yes. Even internally, many teams in Microsoft are shipping containers on Linux for prod services.

          Azure is also the big moneymaker, so these days they want all their technologies to have Linux support since that's the dominant cloud OS.

  • ahoka 3 years ago

    Both are horrible languages and while Java libraries are abundant, most are horribly over-engineered, archaic stuff from the 2000s, where everything was about forcing OOP on every problem. Log4j executed code from an ldap server. Insane.

  • paradite 3 years ago

    We live in bubbles.

    In my limited 6 years of professional experience as a software engineer, I have never met a single person who writes C# or .NET.

  • equasar 3 years ago

    Second this. But here in hacker news, C# is hated for no reason, just the old Microsoft mantra and NET Framework

  • romanovcode 3 years ago

    > C# keeps being the language people are looking for but don't know about.

    Every time I point out about C# most programmers are saying about evil Microsoft and being locked in the ecosystem. Most programmers I've met do not even know that .NET Core is MIT open-source and runs on any device.

    I really wish C# would be more widely used because it is amazing, and for sure 10 times better then Java.

  • devjab 3 years ago

    It’s because C# is only really nice on the surface. As soon as you actually do something with it that takes it beyond its cozy CRUD, it becomes such a nuisance to work with.

    We have an ODATA client that we build our selves to use in our React frontend. Now, this would obviously not have been something we also used on the backend if we knew what we know now, but it’s the perfect example to illustrate my decades of experience with C#. We had the client because we use a lot of Office365 and BC36 APIs and they are ODATA, and since we had the client we figured we might as well use ODATA on our internal APIs. Which was all well and good until we tried mixing EntityFramework, ASP versioning and ODATA together. These are all Microsoft packages mind you, and they just don’t work together. They each use the Model builder magic that C# comes with, but they each use it differently enough that things become a nightmare. Which basically sums up why C# has been a terrible language for its entire existence.

    If you never get to those breaking points, then C# is fine. But when you use it for what you’d assume it was intended for, well… At least the ODATA experience sort of triggered my C# PTSD from back when I wrote an admin system to maintain all the thousands of school printers and computers in a municipality, which was hefty Active Directy work and an absolute nightmare to the point where I literally had to either extend or rewrite half the Microsoft packages because they either weren’t finished or outright terrible (again likely because they weren’t finished). Similar to how the ODATA, ASP versioning and EntiryFramework packages aren’t really finished right now. I mean, I can look at the road map for EF and see some of our issues as planned fixes on who knows when. Anyway, since those days more than a decade ago, it’s become obvious that if you want to do anything AD related then you need to use PowerShell and not C#, really, C# doesn’t even run in Azure runbooks and Python does so it’s obvious that Microsoft themselves don’t really use a whole lot of C# for that part of IT operations internally. And I think it’s frankly the same with a lot of things. The ODATA package seems to fall in that same “not used by Microsoft” box. Because it appears to be some sort of “fork” that’s mostly maintained by a single employee in China.

    So yes, if you just use regular ASP and EF without versioning or ODATA to do very standard CRUD monolith APIs it’s a language that’s both fast and productive. Sure you’ll still need to do all sorts of silly things with your Azure DevOps pipelines to get EF migrations for Microsoft’s own SQL server to work, but hey, you can. But if you’re actually going to be doing things that takes it beyond it’s “basics” then no, C# is really not the language people are looking for but don’t know about.

    I’m also partly in the “Java is sort of 10 years late with 21” club, but it’s not like anyone has switched away from Java in those 10 years, and really, it’s not like it was a fun experience to go through the .Net -> .Net Core -> .Net, .Net Standard and .Net Core -> .Net years, so maybe Java did it right?

    • zigzag312 3 years ago

      Your issue seems to be with packages provided by Microsoft, not C# language itself. Model builder magic is part of those packages, not C# language. These types of libraries often make simple things quick and easy, but complex things (or just simple customization) much harder or even impossible.

      • devjab 3 years ago

        I've seen this response before, but why on earth would we be using C# if not for its included batteries? I can't imagine a world where we would have chosen C# to write an API unless there were some specific benefits, and while I may be wrong to assume this, I don't think I've ever met someone who would. Not so much because there is anything wrong with C# or .Net for that matter, it's okish, it's just well... Honestly, writing C# is a lot like writing typescript with bad linting rules, at least to me. It's not that bad, but it's also not something I'd ever really want to do.

        • zigzag312 3 years ago

          I agree with you that the choice of language should not be based solely on the language itself, but also on the ecosystem it provides for the task you need to complete.

          I was just pointing out that your critique was about the included batteries, not the language. Every language has some bad libraries in its ecosystem.

          • devjab 3 years ago

            The point I was trying to make was that C# has nothing but bad libraries in it's ecosystem. I've worked with quite a lot of languages and I've never experienced anything like it. Well, obviously Node has an "interesting" environment, but the flip-side is that it's very easy to work with what isn't there. C#'s libraries are like half-charged batteries that you won't realize are only half-charged until it's too late.

  • switch007 3 years ago

    Are you feigning ignorance about why people don’t like Microsoft?

    We all know C# exists

insanitybit 3 years ago

The problems with Java can't be fixed by adding new things, you can't undo decades of ecosystem development, training, and ideology built on top of the idea that inheritance is really good idea and belongs everywhere.

edit: I will say that as a Java developer I am grateful every day for the improvements to the language. Java is a very impressive language and I have a lot of respect for the people working on it.

  • matsemann 3 years ago

    I rarely see inheritance used in practice in java code bases. Except where I would use a union type or sealed class in other languages anyways. I don't feel what youre describing is a real issue.

    • tail_exchange 3 years ago

      You must be really lucky then. In my previous job, inheritance and abstract classes were everywhere. Coupled with dependency injection frameworks that "worked like magic", it was really hard to follow the code inside that big, monolithic app. It made me never want to work with Java ever again.

      • bb88 3 years ago

        I've never been a big fan of dependency injection. It solves a problem with unit testing in Java, sure, but the reality is that Java could have done some nifty things to help alleviate that as well.

        • jhaenchen 3 years ago

          Agreed. Java injection frameworks are opaque and accomplish what they need to with overly powerful mechanisms because of the nature of the language. You don't see that sort of nonsense in python.

          • kaba0 3 years ago

            Wtf, so what do you think Django is?

            • bb88 3 years ago

              I'm curious to understand what dependency injection is in Django that you're referring to?

              I know pytest does DI with fixtures, and trying to figure out what you're pulling into a test can be difficult.

              • matsemann 3 years ago

                In django you're importing a default cache, a default storage etc, and write your code to the interface. In settings.py you wire it all up. It's basically the same, for testing you would have to mock the import or provide some implementation.

                • raziel2p 3 years ago

                  technically that's not dependency injection, but a global service locator.

                  • bb88 3 years ago

                    Yeah I agree on that here.

                    The user doesn't write DI code for Django Class Based views. E.g. the view doesn't accept a Database upon instantiation.

          • za3faran 3 years ago

            Nothing to do with the nature of the language, but with the nature of the program.

            If you're writing a few line script, you don't need a DI container. Once your program gets large, it becomes extremely messy without one. It's no surprise projects like [1] exist.

            [1] https://github.com/ets-labs/python-dependency-injector

            • bb88 3 years ago

              That DI library is not pythonic at all.

              There's nothing wrong with this at all, say:

                  class MyClass:
              
                      def __init__(self, my_dep1=None):
                           if my_dep1 is None:
                               self.my_dep1 = get_my_dep1()  # Or potentially raise
                           else:
                               self.my_dep1 = my_dep1
              
                           [...]
              
              
              Then to test:

                  def test_my_class(): 
                      mocked_dep1 = MagicMock()
                      my_class = MyClass(my_dep1=mocked_dep1)
                      [...]
              • za3faran 3 years ago

                And if you want to configure the scope of `my_dep1` (singleton, transient, etc.)? What about nested dependencies? etc.

                • bb88 3 years ago

                  Why do I care about any of that while writing python? Those seem like artifacts of a Java based DI system.

                  • za3faran 3 years ago

                    It's a reality of any non-trivial program, regardless of the language.

                    • bb88 3 years ago

                      No. Some languages don't require you to play cat and mouse games to get around artificial limitations put there by the language designers.

                      There was a talk at PyCon a while back about that patterns commonly used in Java were non-existent in Python.

        • baka367 3 years ago

          If that’s the only thing it’s used for in the project, then you are most likely good with Autowired (in Sping) or something similar.

          Any complicated DI solution must have a reason for it being there and I’ve seen too many projects complicating themselves on buzzwords like DI or MSOA without really needing either that much

        • throwaway2990 3 years ago

          Sounds like you’re confusing DI with DI containers.

      • winrid 3 years ago

        I've seen the same craziness with NodeJS, and very simple Java services with minimal inheritance.

    • xxs 3 years ago

      Inheritance used to be extremely common, look at AWT/Swing - however more or less it finished there, e.g. more than 20y back.

      There are still lots of folks who love 'protected' and deep hierarchies, of course. There is stuff like spring that uses way too many interfaces with a single implementation, doing something a bit off the regular road ends up implementing tons of the said interfaces anew.

      However the 'hate' part is mostly the internet (well esp. Hacker news)warrior topic

      • sisve 3 years ago

        Great to hear. I used to program java in 2010 and inheritance was still beeing heavily used back then. But things change, if both the lang and the main community has change to focus more on simplicity its def worth looking at again. Coroutines and pattern matching is really good features

        • insanitybit 3 years ago

          Contrast that, I've seen numerous Java codebases, young and old, and inheritance is very much one of the core ways that people program.

          I strongly suspect that in a few cases some Java devs using net new systems and avoiding common frameworks will perhaps be able to avoid lots of inheritance but I find it insane to say that that's common or even easy.

        • umanwizard 3 years ago

          Inheritance is heavily used in Java in 2023, at least in projects I’ve had to look at.

    • insanitybit 3 years ago

      > I rarely see inheritance used in practice in java code bases.

      That seems absurd to me and I have a hard time understanding it, honestly.

      • Supermancho 3 years ago

        > I rarely see inheritance used in practice in java code bases.

        Without some specific call-out, it can be assumed that this is a very niche viewpoint that has no bearing on modern development.

        The vast majority of projects use inheritance, today.

        Does it use Spring? extends SpringBootServletInitializer

        Meaningful responses using values from a request? extends OncePerRequestFilter

        Formatting exception handling responses on web requests? extends ResponseEntityExceptionHandler

        Then there's all the interfaces you have to satisfy, because it's all tied into the standard library and popular libraries.

        • richardw 3 years ago

          You need to inherit to create anything that is a class. But the focus is on composition. You inherit from useful classes so you can build the solution using composition.

          I don’t like modern Java because there’s too much non-Java magic code. Layers of stuff that “helps” but removes me from the language. Entire programs written in config and special text wrapping classes and methods. How it works requires understanding multiple intersecting languages that happen to be strung together in .java files.

          Edit: when something is in config it’s not checked at compilation. Every environment from dev to prod can have its own config so when you compile in dev you don’t know what’ll happen in prod. I know: let’s add more tools and layers.

          • Supermancho 3 years ago

            > You need to inherit to create anything that is a class

            That's true of the Java compiler, for which the documentation is strewn around the intenet...but an example is here: https://medium.com/javarevisited/compiler-generated-classes-...

            The Java syntax doe not require extending Object explicitly.eg This is a valid, useless, class:

                public class App {}
            
            > I don’t like modern Java because there’s too much non-Java magic code

            It seems like this is the common path for popular languages. They develop their own library-backed DSL's for the most common use cases, which are often little more than macros (@data @getter, @notnull, etc). I am biased by what I've seen in the last 30 years though.

            • chii 3 years ago

              The OP/GP wasn't really complaining about inheritance, despite the fact that this is what they wrote.

              The OP is complaining about the difficulty of the API because it is _exposed_ through inheritance.

              The complaint about `SpringBootServletInitializer`, for example, is exactly this. There's nothing wrong with inheritance. In fact, SpringBootServletInitializer is exactly what you want to use inheritance for - because you need to build your app using the servlet api.

              There are http servers that aren't servlet api, such as https://vertx.io/docs/vertx-web/java/#_re_cap_on_vert_x_core... , which uses little to no inheritance (since the api surface is smaller).

        • kaba0 3 years ago

          Having a single level of inheritance (especially if it's an interface) is not a problem at all. Having deep inheritance trees can be a code smell.

        • matsemann 3 years ago

          While you have to extend some things in Spring, yes, the whole point of the DI in spring is so that you can often compose instead of extend.

      • wayfinder 3 years ago

        If you type everything with interfaces in your codebase, you are much less tied to inheritance. In fact, everyone could be written to be composed.

        However Java doesn’t support type union so you can get into some ugly and verbose situations but the JVM doesn’t really check type so this is more a compile-time issue and could be fixed in a future Java language revision.

        • logicchains 3 years ago

          >However Java doesn’t support type union so you can get into some ugly and verbose situations

          Isn't the "sealed interface" described in the OP blog post a type union? Or you mean anonymous unions?

          • wayfinder 3 years ago

            Definitely referring to anonymous unions too. Without them, there’s still friction sometimes which makes union types unnatural.

            I haven’t written Java in a while and I can’t remember if you could sometimes fake a type union using a generic type on a method, but if you can, it’s definitely super ugly and would raise eyebrows during any code review.

            • logicchains 3 years ago

              Anonymous unions are a relatively rare feature; Rust and Haskell don't have them, for instance.

    • sisve 3 years ago

      Sorry, what? Is not java toghether with Ruby maybe the most hardcore OOP enthusiasts that uses inheritance for "most stuff".

      Has the java culture move so far the last decade ?

      • EdwardDiego 3 years ago

        Effective Java, written by Joshua Bloch, and first published in 2001, had a very influential section called Favor composition over inheritance:

        https://books.google.co.nz/books?id=Ra9QAAAAMAAJ&q=inheritan...

        Why do you think DI is so prevalent in Java codebases? It's a great way of simplifying composition.

      • fiddlerwoaroof 3 years ago

        I’ve been writing OOP code and reading about it for a decade or two, and inheritance was identified as problematic pretty quickly. The problem today, imo, is more underuse now.

      • kaba0 3 years ago

        Funnily enough, it actually started from C++. And, Java is so large that it is simply meaningless to talk about a unified style -- sure, some Java EE behemoth will continue to run on a complicated Application Server for decades still, churning on its workload, but so will someone write a Micronaut microservice, or something for robotics, and these will all have distinct styles.

        With that said, even the Java EE/Spring complicated word has been moving towards a less inheritance-based future.

      • dragonwriter 3 years ago

        Even in Ruby, IME, deep inheritance is fairly uncommon.

        Wide inheritance through mixins is common, though.

    • rerdavies 3 years ago

      HtmlElement. AST. Socket. Stream. Window. Closable. Runnable.

      • fuzztester 3 years ago

        Your Point?

        Long:

        Please make your Point Understandable.

        • rerdavies 2 years ago

          Examples of classes where inheritance is indispensable. I cannot imagine what kind of programming you are doing where that pattern never comes up.

  • hutzlibu 3 years ago

    There is nothing wrong with inheritance. But sure, there is usually something wrong with deep inheritance or using it, where better solutions exist.

    • insanitybit 3 years ago

      No, there's a lot wrong with inheritance. It leads to all sorts of issues and while theoretically one can keep the tree 1 level deep, in practice it's too tempting to expand the hierarchy.

      This is one of Java's big issues. The other is reference equality as a default, pretty horrible. Records help but records are also limited in when they can be used.

      • hutzlibu 3 years ago

        "in practice it's too tempting to expand the hierarchy."

        Not anymore, if you got stuck, by doing that once too often. But 2-3 levels can be allright as well. It depends, what you are doing amd with whom.

      • palata 3 years ago

        > No, there's a lot wrong with inheritance.

        No, there is a lot wrong with bad code. No need to blame the language or any programming concept.

        Note that I say that for all programming languages, not just Java.

        • zelphirkalt 3 years ago

          That's a difference between a dangerously unsafe tool and a good tool. By unsafe I mean providing enough of footguns to shoot yourself in the foot. Java has a community of people that indulge in teaching about inheritance as the first thing after classes in their "OOP" lessons. This ingrains the habit in beginners.

          • palata 3 years ago

            > By unsafe I mean providing enough of footguns to shoot yourself in the foot.

            Just to play on the comparison: would you say that a gun is a "dangerously unsafe tool"? I would tend to think that guns have been very well optimized over time, and I don't know of a gun design that prevents me from shooting myself in the foot. Actually that would be a limitation of the gun.

            But we all agree that people who use guns need to learn how to use them properly. Why doesn't this apply to programming languages? How did we as an industry end up in a place where it's considered the norm that developers don't really know what they are doing and need some kind of child safety in order to not hurt themselves?

            • Mawr 3 years ago

              Yes, guns are dangerously unsafe, they're designed to cause harm. It's hard to reconcile that goal with the need for safety. That said, guns do have safeties - guarded trigger, safety switch, drop safety, etc. [1].

              The general principle is to design in as much safety as possible without compromising the intended purpose of the tool too much. The degree to which this is possible varies. Inherently complex and/or dangerous tools like guns, cars and aeroplanes require significant training before safe operation is possible. Most tools however can be made perfectly safe to use for anyone without any special training. Like plugs and outlets [2].

              Programming languages are no different. The history of PL design is defined by the ever increasing restrictions placed on what languages let programmers do in the pursuit of safety & correctness.

              But really, we humans, especially programmers, have no clue what we're doing and need all the help we can get.

              [1]: https://en.wikipedia.org/wiki/Safety_(firearms)

              [2]: https://youtu.be/139Q61ty4C0?t=42, https://youtu.be/139Q61ty4C0?t=105, https://youtu.be/139Q61ty4C0?t=205

          • hutzlibu 3 years ago

            It seems you conflate the tool and the education about the tool?

            Why is Java itself bad, because some people (maybe) teach it wrong?

            Also inheritance as a first lesson with OOP is not bad either, if the follow up is sound. But as far as I know, the concept composition > inheritance was already taught 15 years ago.

            • zelphirkalt 3 years ago

              If we look at other modern programming languages, some don't even have inheritance. Lets take Rust for example. The language from the get go avoids the trap of deep inheritance hierarchies, by ... not having classes and inheritance! Instead it has structs and traits you can implement for the structs. Behavior separated from structure. They learned from the mistakes or design flaws of the past. Sure, Rust is not perfect, but this aspect about it I really appreciate. I am sure though, that someone somewhere will implement something resembling inheritance and create footguns anew.

              Lets compare with Java. Java has forced everyone for decades to shoehorn everything into classes (sometimes an enum, sometimes an abstract class, whatever). Last time I checked it was still impossible to simply open a file, put a function (!) inside and be done. No, Java forces you to wrap that into a class or similar construct, as if a function in itself was not enough and not self-sufficient. There is a whole mindset behind this, that seems to come from an ideological "everything must be a class, because then I can instantiate and then I haz objects and can call methods". Other languages don't need classes to have objects.

              Decades fast-forward. Java learns, that lambda expressions are a nice idea. Java will offer structs. Java learns, that lightweight processes are very neat to have. And despite all that, the old footguns still remain and could only be undone at significant cost, because of backward compatibility. This is where programming language design sins really rear their head. PHP suffers from the same problem. Horrible standard library, but cannot be fixed, unless you break backward compatibility.

              On one hand you can state, that it is all on the programming, who is "holding it wrong" or needs more education. On the other hand, the programmer can choose a better designed tool, that doesn't cut their fingers every time they try to use it. Just because it is possible to do a good job with Java, that does not mean, that Java is a good tool for the job. It means you can only let the most experienced people work with the tool, instead of what we have now, every Billy knowing Java, writing classes and getting a kick out of inheriting from a super class.

              Good teaching will avoid weighing things one should avoid disproportional. There is no good reason to teach inheritance early on. It should be a thing taught on the side, something one quickly glances at and says: "Yeah, that also exists, but lets not get into that much, as we will not need it much ..."

              But in Java you probably can't avoid it for long, because you will want to make use of some library sooner or later and library authors might force you to make some class inheriting from their library's class, define a behavior and pass that in. But often that is not enough ... No no no, you need to pass in a factory for classes, that implement an interface, and their methods will implement the actual thing. I have seen this recently for logic of checking, whether a password is valid/acceptable. Why the heck do I need to implement a factory for that, when the actual task is simplest logic, checking whether the password has all required kinds of characters in it?

              Usually this is completely overblown, because you want to pass in some behavior, that could be expressed as a simple function. I shouldn't need to create some brimborium. All I should be required to do should be to implement the logic in a function and pass that as an argument to the library.

              The existing ecosystem forces its "OOP" on you. If you are not willing to throw out decades of ecosystem, which actually is the main advantage of the JVM, then you will need to deal with the cruft that has been created before.

              • hutzlibu 3 years ago

                Ok, you don't have to convince me that Java has many problems, as I intentionally avoided Java for some of those reasons for the last 15 years. But thanks for reminding me of some of them ..

                But the concept of inheritance I like. And I use it succesful allmost daily. And like I said, I am aware of how you can use it in the wrong way. And my code surely is not perfect either, but the flaws I have, do not come from inheritance. Those parts are actually very clear, solid and stable. And still flexible.

                And Rust is trendy I know. I have never used so far, so it was news to me, that they don't even have inheritance, but to convince me, that Rust has the superior concept, I would like to see it to be used as widely as inheritance languages first.

        • insanitybit 3 years ago

          [..] a programming language designer should be responsible for the mistakes that are made by the programmers using the language.

          It's very easy to persuade the customers of your language that everything that goes wrong is their fault and not yours. I rejected that...

          - Tony Hoare

          • palata 3 years ago

            I feel like it often goes in the other extreme: "if a 2 years old cannot use it, it's too hard".

            I am fine with requiring that professionals know their tools, even if I'm well aware that this is not the norm.

      • belter 3 years ago

        You don't like code reuse?

        • akavi 3 years ago

          Love it, and love using plain ol' functions for it

        • dgb23 3 years ago

          Inheritance is not necessary for code reuse.

          All you really need for that is named procedures. A way to combine modules and different files certainly helps too.

          Type hierarchies can even hinder code reuse, because you can’t just pick the stuff you actually need.

        • insanitybit 3 years ago

          That question seems blatantly disingenuous.

        • caconym_ 3 years ago

          Composition > inheritance.

  • wslh 3 years ago

    Please ELI5 what is wrong with inheritance and/or how Java have it wrong. Do we need to go back to a new object oriented undegraduate course? Genuinely asking.

    • nsajko 3 years ago

      "Prefer composition over inheritance" is actually a well-known mantra and appears in, for example, the Design Patterns book from 1994, which is basically the OOP bible. And this is within the OOP bubble, you won't even find inheritance outside of it.

      https://en.wikipedia.org/wiki/Design_Patterns

      Don't take undergraduate OOP courses seriously.

      • chii 3 years ago

        > a well-known mantra

        which isn't an explanation, but just the same as the OOP mantra that was taught in undergraduate courses.

        • zelphirkalt 3 years ago

          One reason is the unstable base class phenomenon. A some changes in the base class require you to constantly change all your derived classes.

    • ickyforce 3 years ago

      "What OOP users claim" -> https://i.imgur.com/KrZVDsP.png

    • preommr 3 years ago

      Inheritance is fine. It helps to avoid code duplication for logic that requires encapsulated data (private, protected fields).

      The problem is what if you have a class that needs to derive behavior that's in two (or more) classes? Multi-inheritance is terrible because it becomes a nightmare of which class overrides which.

      If there's a shallow level of inheritance (1-2 levels deep), then there's nothing wrong with it. Things like composition for most use cases has been common advice since forever.

      What happened with java was that there was a massive movement for enterprise code that way over-complicated everything based on ideas that didn't pan out. There were all these auxiliary patterns, and ideas that people had to learn to be onboarded onto projects, and so many people poorly understood them that it led to even more spaghetti code, too many people that developed using dogma instead of common sense.

    • sirk390 3 years ago

      With compositions A uses B but B can never use A. With inheritance Child can use the Parent, but Parent will also call the Child (virtual methods) which in turn can call the Parent again etc.., so the code can become difficult to follow. It can become very complicated with multiple inheritance and multiple levels.

      • mike_hearn 3 years ago

        Such code would be difficult to follow regardless of whether you use inheritance or not. Sometimes, two pieces of code developed independently just need to interact very closely with each other.

        Remember that OOP and inheritance to some extent came out of the need to develop GUI systems. Inheritance is still heavily used in GUI toolkits because it's a good fit for that problem space. You have graphs of objects that need to be treated at different levels of abstraction, and controls often need to customize (override) or implement some behavior that shouldn't itself be a part of the public API.

        Attempts to get rid of inheritance and OOP in UIs end up looking like Compose or React. I found very quickly when working with these that pure composition just wasn't sufficient and these approaches have their own issues; problems that OOP trivially solves become difficult to impossible to solve cleanly without it.

      • NickNameNick 3 years ago

        I've certainly done that in the past, but not since I changed jobs ... 7 years ago. Probably not for several years before then.

    • insanitybit 3 years ago

      Inheritance provides "is a" relationships between classes. At a time when people would spend months designing their software upfront, building big diagrams of classes, etc, this was not so bad. You'd have a very clean system design that maps directly to your class design.

      The problem is when things change. A simple example - you build a classification of all life and it is built upon the idea that everything "is a" plant or animal. And then one day it turns out there are fungi. This is not a fun situation to deal with and inheritance makes it a lot harder because the "is a" relationship is driving a ton of your logic.

      IDK I don't want to get to into it beyond that, many people have written quite a lot on the topic.

      • kaba0 3 years ago

        > you build a classification of all life and it is built upon the idea that everything "is a" plant or animal

        With all due respect, this and similar examples are just plain wrong, and I really can't take anyone seriously when that example is used. The point of programming, and its abstractions is to help you complete a task, and make the implementation maintainable and easy to reason about. I think grabbing the "is a" part is fundamentally bad -- there is no point in creating a taxonomy in and of itself, this is no database for that data. Inheritance sometimes is the correct abstraction and while it is definitely overused, when it's correctly applied there isn't really another abstraction that would fit better. E.g. see a graphics library's Node class as the stereotypical correct application.

        • insanitybit 3 years ago

          I think your post can be broken down into two main points.

          1. That my point is bad for some reason

          2. That inheritance is sometimes a great tool

          We agree on (2). Inheritance is pretty amazing, even if I think that it's ultimately a terrible feature to build so ingrained into a language and to expand in power to such a degree.

          As for (1), I don't really get your point. Abstractions help you complete a task - ok. Abstractions are to help you reason about stuff - ok. Something about "is a" being bad? None of that really explains why my example demonstrates the problems you run into when you try to build a classification of values using inheritance. But I also said that I wasn't going to really try to explain much, it's been written about plenty.

      • bb88 3 years ago

        > This is not a fun situation to deal with and inheritance makes it a lot harder because the "is a" relationship is driving a ton of your logic.

        Judicious OOP design allows others to change behavior based upon needs that perhaps the original coder never thought of.

        I would not call most Java OOP design judicious. The control in Java is owned by the library writers and the language devs -- not the people using it.

      • wayfinder 3 years ago

        This problem is partly a type system limitation however.

        In a more flexible type system with union types and other magical features, your example problem would be less of an issue.

        However Java has an extremely limited type system so there is no middle ground between composition and inheritance. Once you choose one way, there is no “middle step” to migrate over.

        • kaba0 3 years ago

          Union types are very rare (scala, typescript are the notable ones I can think of that implement it), most other languages only have sum types (which includes java as well, see sealed interface/classes), where you have to create each unique set of types you want to use separately, wrapping each option into a marker type basically.

      • inglor_cz 3 years ago

        In cases of refactoring, inheritance seriously sucks.

        But it is quite advantageous when, as you say, your model is well thought out and stable.

    • bbkane 3 years ago

      If you want to see how codebases work without inheritance in practice, I suggest checking out Go, which features polymorphism through interfaces, but not full-fledged inheritance

  • kaba0 3 years ago

    Prefer composition over inheritance has been a common mantra for at least a decade, if not more. Maybe you should undergo the last decade of development and training.

    There will always be shitty devs, and since java is one of the biggest languages, it definitely has more than some ultra niche academic language no one uses. I don't think it is the fault of the language though, or if that somehow were a reason to choose a different language. Should a decent BMW driver sell their car, because plenty assholes buy that car also?

    • insanitybit 3 years ago

      Just because everyone has been saying "composition over inheritance" doesn't mean that that's how things get done. Jump into any Java codebase and you're 99% likely to see inheritance used as one of the primary abstraction mechanisms.

      > Should a decent BMW driver sell their car, because plenty assholes buy that car also?

      A better analogy would be "Should you drive on the street where all of the shitty drivers do donuts and street races?"

    • mrkeen 3 years ago

      > Prefer composition over inheritance has been a common mantra for at least a decade, if not more. Maybe you should undergo the last decade of development and training.

      What are some other well known mantras? The null reference is a billion dollar mistake? Minimise mutability?

      Maybe the language designers and library writers could catch up too.

      • za3faran 3 years ago

        Records and value/primitive classes are immutable, not to mention https://openjdk.org/jeps/401

      • kaba0 3 years ago

        Inheritance is a useful feature, using bad abstractions is a user error.

        Nulls are an error in that no language feature solves them (though third-party tooling does), so far at least.

  • packetlost 3 years ago

    Yeah, I think this is the part that gets me. To be fair, I think well designed Java is flexible in exactly the right ways for an enterprise development. The trouble is that enterprises don't typically pay well enough to get people who are really good and the popular ways of building Java applications are not great.

  • lelanthran 3 years ago

    > ideology built on top of the idea that inheritance is really good idea and belongs everywhere.

    Those are two different ideas.

    • insanitybit 3 years ago

      I used the word "and" to indicate that, yes.

      • lelanthran 3 years ago

        I think a comma would make it less ambiguous.

        Starting that single though with "The" indicates to me that you don't think those are two different ideas.

        Compare:

            the idea that inheritance is really good idea and belongs everywhere.
        
        With:

            the idea that inheritance is really good idea. and belongs everywhere.
slotrans 3 years ago

> This set of changes allows Java to express one of the foundations of functional programming that the language never could before - Algebraic data types, along with idiomatic ways of using them.

And here I thought the foundation of functional programming was functions, which Java still doesn't have.

Seriously, functional programming is about functions, not types.

  • chii 3 years ago

    > functional programming is about functions

    different people mean different things when referring to functional programming.

    Some people believe that functional programming are using higher-order functions like `map`, `reduce`, `forEach`, etc, which takes a function as a parameter, instead of doing imperative loops.

    Some people, in addition to above, believe that functional programming is about creating functions that take a certain 'shaped' parameters, to allow for automatic checking.

    And lastly, the "real" functional programmers are people who believe in referential transparency in your functional program.

  • kaba0 3 years ago

    How is Math::sqrt not a function in Java? Sure, it’s called a static method and it lives in a class - but is it meaningfully different from the same being a function in a Math namespace in say, C++? You can static import it even and use it as a function. This is just needless hair splitting imo.

  • mrkeen 3 years ago

    > And here I thought the foundation of functional programming was functions, which Java still doesn't have.

    > Seriously, functional programming is about functions, not types.

    Well it does have methods and it does have "Functions" (not to mention "Bifunctions", whatever those are). And there's certainly nonsense around exceptions and referring to outer variables. And no currying.

    But if I understand you correctly, you real complaint is about not having effect-free functions, right? But then it becomes about the type system again, because that would be the mechanism to prevent effects.

Horffupolde 3 years ago

Can you convince me to use Java? I’ve never used it (only C++, Python, CL) but it feels bloated and dirty.

  • belter 3 years ago

    None of the memory problems of C++, the speed of C++ most of the time. Thousands of high quality libraries, a JVM that is a marvel of engineering after 20 years, tooling for development, monitoring and introspection of exceptional quality. Many of the internal tools at the largest Cloud developed in Java. Most enterprise level software. NASA extensive use of Java. A team behind the development who has stunning common sense in resisting the latest fads. Support for IEEE 754 that took years. AOT compilation...The infra behind most internet banking sites out there. Use in high speed trading.

    What else do you want from the ecosystem?

    • hutzlibu 3 years ago

      What would be a modern IDE for Java?

      I remember programming Java in Eclipse. And it was powerful for the time, but everytime I read bloated, I automatically think Eclipse since then..

    • gabereiser 3 years ago

      >” None of the memory problems of C++”

      I’m sorry, I’m calling BS here. You can still leak memory in Java.

      • vlovich123 3 years ago

        You can leak memory in any language. That’s an impossible bar. The problems op is referring to is obviously about memory safety.

        Java obviously isn’t thread safe like Rust is, but it’s typically safer than C++ on that front too.

        • gabereiser 3 years ago

          Rust isn’t thread safe either. It’s borrow checker will attempt to correct you but you can still run Rust unsafely.

          • laurencerowe 3 years ago

            As I understand it Rust's unsafe is designed so you can encapsulate unsafety behind a safe interface.

            It's up to the programmer to verify the safety of code using unsafe. But it they do so correctly then you can rely on the borrow checker to verify that everything else is safe.

            This means that when you run into a thread safety bug in Rust code you should only have to look at the unsafe blocks to find the culprit.

            • kaba0 3 years ago

              With that said, I think it is important to mention that if you go off the safe path in rust and you do hit such a bug, your current execution is no longer trustable, it could have corrupted the heap, introduce UB, and die with a segfault, etc.

              In java, race conditions can enter illegal application state, but their scope is much more limited. NPEs are 100% safely handled, etc. you can only get off the safe road with using Unsafe unsafe, and manipulating the JVM’s inner state which is not even allowed by default. Depending on application, this difference may matter a lot!

        • quickthrower2 3 years ago

          There are two kinds of leaks IMO. The one where your algorithm allocates gigabytes needlessly (and cannot be avoided by language design) and more insidious stuff like having to unsubscribe from an event handler for your object to be dereferenced.

      • c048 3 years ago

        Shitty code is shit in any language. What's your point?

      • ndr 3 years ago

        Isn't that true in any language that lets you allocate memory?

      • kaba0 3 years ago

        var list = [];

        while (true) { list.add(1); }

        Here you are, which language won't leak memory here?

        Also, which language will let you connect to a prod instance without a performance hit to get some stats on the heap and its allocated objects? Hell, you can even list every instance of a type as I've recently learned.

        • packetlost 3 years ago

          >var list = [];

          > while (true) { list.add(1); }

          idk, I don't think endlessly growing memory usage is really what a leak is, a leak is really when you have no way of accessing the allocated memory to free it (ex. dropping the last remaining pointer to a `alloc`'d block in C) or the opposite in garbage collected languages: accidentally holding onto a strong reference to objects that should be freed.

          • kaba0 3 years ago

            > the opposite in garbage collected languages: accidentally holding onto a strong reference to objects that should be freed

            So basically what I gave an easy example of. Sure, it won’t look like this in practice, you probably accidentally keep adding to a list, or a cache, but basically this is what happens. The former kind of leak can’t happen with tracing GCs.

      • EdwardDiego 3 years ago

        You can. But you have to try rather hard.

    • loxias 3 years ago

      > None of the memory problems of C++

      Every time I see something like this I roll my eyes... C++ doesn't have any "memory problems".

      There are sometimes human problems, such as thinking one is capable of coding without understanding the (basic programming) concept of a pointer. But that's because the human's dumb, not a language problem. (This argument also sometimes comes from those who do understand basic programming, but are only familiar with C++98.)

      > Thousands of high quality libraries a JVM that is a marvel of engineering after 20 years

      I reluctantly have to agree. :)

      • kaba0 3 years ago

        > Every time I see something like this I roll my eyes... C++ doesn't have any "memory problems".

        You can choose which report you would prefer: Microsoft's, Google's 65%, ... I'm sure they just hired bad developers that don't understand pointers.

        Sure, human problem, but if no human can use the tool correctly, then surely there is some problem with it. And no, that doesn't mean that memory unsafe languages don't have a place, but we really should have a very good reason for going down that road.

      • erik_seaberg 3 years ago

        I understand pointers, yet I can’t be trusted never to make a mistake with them. “Each mistake will go uncaught and become an unpredictable catastrophe” is a language problem when your target audience is made of meat.

      • inglor_cz 3 years ago

        "But that's because the human's dumb, not a language problem."

        If everything is the programmer's fault for being dumb, then Brainfuck is an excellent system language.

      • grumpyprole 3 years ago

        > C++ doesn't have any "memory problems"

        Well, every time I see someone claim this, I roll my eyes.

      • segfaltnh 3 years ago

        It must be hard being perfect. The rest of us will keep looking for solutions for mortals.

  • whartung 3 years ago

    I’m a fan, long time fan, but I can honestly say that I feel Java is one of the most pragmatic development systems on the planet.

    It can do most anything. It can do it most anywhere. And you can code in it using several different paradigms.

    It’s easy to install, it’s easy to be instal several versions, the footprint, by today’s standards, is not enormous.

    It’s easy to deploy, especially server side. While you can certainly do all of that modern stuff with containers and what not, it’s not really necessary for Java. Drag and drop a JDK install, anywhere. Plonk your Java server code, anywhere, and point it at your JDK, and. . .that’s it! Fire it up. The JDK is remarkably light on dependencies.

    And since most Java apps are “pure Java”, the apps rarely have a dependency outside of the JDK. And since Java apps routinely bundle their Java dependencies, the apps don’t stomp on each other either. Even SQLite bundles it’s binaries in the Java Jar file. So wherever that jar goes (again, and typically bundled with your app), SQLite goes. No floating dependencies.

    Desktop bundling requires a bit of search engine research, but it’s doable. And the runtimes can dwarf something like Electron installs.

    As a language is Java ELEGANT? Not particularly. It has its own elegance in some areas but that can break down or get overrun in others.

    But, boy howdy, it sure is practical. The ecosystem is so huge. It compiles really fast. I marvel at the stories folks tell about their dev cycles in other languages. How do they get anything done, besides sword fighting?

    I love Java, but I’m very comfortable in it. But the Maven based dependency system works, it’s huge, it makes use and reuse simple. The IDEs are powerful and mature.

    And, finally, Java’s not dead. Hardly. Oracle has been a surprisingly good steward (with warts, as always). The language has been on a rocket of development and shows no sign of slowing down. Server side is still very hot with all the frameworks and all the different approaches. Things like GraalVM taking the JVM in a whole new direction.

    And, yea, that. I’ve only been talking Java the language, not the JVM itself per se. That’s a whole other thread.

  • cbarrick 3 years ago

    Throughput in Java can be quite high, and latency can be quite low. You still occasionally get latency spikes from the GC, but these days that's not so bad. (If you are extremely latency sensitive, stick to C++).

    Dependency injection frameworks are your bread-and-butter in server-side Java, and some can take a while to grok, but Java can be very productive after the chosen framework "clicks" for you. Typically, this means you'll be writing constructors or factory classes that construct your dependencies per request. The way you wire your factories into the system differs by framework, but it often involves using Java's annotation syntax.

    Not having to worry about memory management is a huge win for productivity over C++. Likewise, constructors in Java are much more sane than in C++.

    Classical object-oriented programming is intuitive, and Java tends towards the "one obvious way to do something" paradigm. I find it pretty easy to hop into legacy code bases, if I already know the framework being used. The collections API in the standard library is one of the best classical OO APIs out there.

    The JVM provides great visibility into the performance of your system. A lot of instrumentation comes "for free".

    I'm not sure where you get the "dirty" and "bloated" feeling from. By any definition I can think of for those words, Python would be in the same bucket.

    • riku_iki 3 years ago

      > Java can be very productive after the chosen framework "clicks" for you.

      you can chose to not use DI frameworks at all..

      • cbarrick 3 years ago

        DI buys you maintainability.

        Without DI, there's too much flexibility in how objects get constructed. If you want to add new functionality to a legacy code base, it can be difficult to track down the different integration points and slow to plumb through your dependencies. These projects can turn into spaghetti very quickly.

        DI solves this with a simple recipe: define your functionality, define your dependencies, wire it up to the injector.

        The pattern is useful in all OO languages, Python and C++ included.

        • riku_iki 3 years ago

          the problem is that those DI frameworks are all adding substantial amount of complexity and brain load.

          I started using just static factories in my code, and abandoned all those DI and it works well enough.

          • andrekandre 3 years ago

              > I started using just static factories in my code, and abandoned all those DI and it works well enough.
            
            i have done this as well (though not in java), it makes knowing what gets initialized how and where much easier and faster to debug
    • Horffupolde 3 years ago

      Yes, I agree that Python can feel “dirty”, although not necessarily “bloated.”

      • cbarrick 3 years ago

        urllib... getopts...

        There's as much useless junk in Python's standard library as there is in Java's.

  • matsemann 3 years ago

    What's dirty is trying to get a python project reliably running on all dev computers. Pyenv, venv, wheels, suddenly you need a complete rust or c toolchain etc. With java I haven't had those kind of issues the last decade, it just works. With python it's still a big hassle and everything breaks every update.

    • jessekv 3 years ago

      To be fair, getting all those scientific library binaries compiled and installed was a huge pain even before python came around. Python's toolchain made it better, but only marginally in some cases.

      • TheFlyingFish 3 years ago

        Sadly this isn't just the case for scientific Python. E.g. some widely-used web library (I forget which) recently switched to using a Rust implementation of TLS, and suddenly you needed a working Rust tool chain available to install it. This caused a lot of grief.

        I love Python, and I've been experimenting with Rust and enjoying it so far, but this situation could have been better handled, I think.

        I agree 100% about scientific Python though. It's a whole new level of horrible when it comes to dependency management.

  • speed_spread 3 years ago

    Java itself is a nice language that can be lean and mean but has long been culturally bloated by early tooling and conventions. Since Java 8 (~10 years) the tide has reversed and it now mostly accepted to write terse code that is to the point.

    The language gets updated regularly and is managed very competently. Although it may seem to trail on some aspects vs other langs, it benefits from second mover advantage - new features are done right, for the right reasons.

    Any Java code ever written is essentially eternal, both in text and compiled bytecode form. Compiler and VM compatibility guarantees are unmatched. You can stumble upon 20 year old code and just use it.

    The platform is mature and robust. The JVM itself is a marvel of engineering.

    The ecosystem is extremely rich. There isn't a problem that wasn't addressed by a library or a stack overflow question.

    The tooling is unequalled. IDEs can reliably perform large code transformations because there is no preprocessor or macros and the type system is relatively sane.

    If you know Java you'll never be out of a job.

  • Blackthorn 3 years ago

    Bloat is a meaningless word. One person's bloat is another's essential.

  • justrealist 3 years ago

    How could you possibly like C++ but feel that Java is bloated?

    Like I academically understand disliking Java but this just makes no sense.

    • OJFord 3 years ago

      I think people are understanding 'bloated' differently.

      I agree C++ is bloated in a 'just make it a setting' / 'add this feature' / 'kitchen sink' sort of way.

      I agree Java is bloated in a boilerplate, empty directories, maybe except for another directory, 'oh god the boilerplate' sort of way.

      • loxias 3 years ago

        > I agree C++ is bloated in a 'just make it a setting' / 'add this feature' / 'kitchen sink' sort of way.

        Interesting. Can you expand on this, explain more? I honestly don't know what you mean or are referring to -- and I'm a heavy modern c++ advocate -- but suspect if I did it might expand my mindset/viewpoint a bit. :)

        • OJFord 3 years ago

          Honestly I haven't actually used it since C++14 was new, but it's a common complaint IME that each 'edition' (as Rust would call it, I don't know remember the term, standard?) adds too much, there's too many ways of doing things, variations of pointers, boost, and so on.

          I think a lot of people wish it had stayed at say C++7, a mature C superset, but that's enough now. I probably should have said 'I understand' rather than 'I agree' - I don't feel strongly, I don't use either of them.

          • loxias 3 years ago

            Ohhh, I get what you mean now, thank you! I understand (and mildly disagree). :)

            Yeah, C++ is a living language, I can respectfully see that bothering some people. I viewed c++98->c++11 as essentially a new language with c++14 and c++17 being "bug fixes" for the "new language" that is c++11. But certainly, it can require more learning about every decade now.

    • jjnoakes 3 years ago

      I think of Java as more bloated than C++ at runtime - with C++ I can make smaller executables that start up faster, use less memory, etc.

      But if you are talking about the source code itself, then things are quite different.

    • loxias 3 years ago

      ???

      I'll answer your question with a question: Have you seen https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpris... ? :)

      I'm guess that to those of us who remember when Java came out, "FizzBuzz: EE" is what we think of when we think of Java. :P

      In Java I have to type a bazillion characters to get anything done! And make all these useless directories and files and InterfaceClassFactoryProtocolStreamingSerializer BS. And worry about how that executes.

      C++? No bloat*, just speed

      *Yes, there's some _optional_ bloat. But compared to Java? no contest.

    • deaddodo 3 years ago

      I mean...Java is run through a VM while C++ is compiled to native code.

      I can see that being used as a reasonable argument for bloat.

      • kaba0 3 years ago

        > run through a VM

        This is just incorrect use/understanding of Java’s execution model. It does have a runtime, but it is definitely not a VirtualBox VM.

        • deaddodo 3 years ago

          What are you talking about? No one brought machine/platform virtualization into this conversation other than you.

          The bytecode interpreter for Java (and other similar languages) is literally called a Virtual Machine, due to the way it functions:

          https://en.m.wikipedia.org/wiki/Java_virtual_machine

          It would seem your understanding of the Java execution model is flawed.

    • Jensson 3 years ago

      C++ allows for much more terse code than java when you do small projects. It is popular in competitive programming for that reason, not just because it runs fast but also because it is really fast to write algorithms in it.

  • hmottestad 3 years ago

    You don’t have to use Java. All the languages you’ve mentioned are fine. If you think that using Java to solve a particular problem is a good idea, then you should definitely use Java.

  • zapnuk 3 years ago

    What feels bloated and dirty?

    Because there is plenty of bloated and dirty stuff in C++ and Python too.

  • signaru 3 years ago

    What convinced me to consider Java just recently is GraalVM. I don't know about the "dirty" part, but at least GraalVM might solve the "bloated" part. Compiling to native standalone executables makes a big difference to what Java is traditionally known for (portable bytecode but requiring the JVM). Been using C++ and C# for a long time now, and my pet peeves with these languages were also only just addressed relatively recently (C++ getting modules and native AOT for C#). Java being able to get natively compiled makes it worth considering among these. Now, for me, it's a matter of what other frameworks/libraries available for the respective languages would get the job done while I only have to rewrite little to switch among them if I try my best to stay within their syntax overlap.

  • EdwardDiego 3 years ago

    I work on a Python codebase now after years of JVM and here's what I miss, static typing taken as read.

    * Threads that can use more than one core.

    * The best approach to package management I've ever seen, no-one worries about typosquatting or "someone already registered all the cool crate names" because every package has at least two coördinates - a group id based on a DNS entry you must be able to prove you have access to, then the package name. So I can publish my malicious package gauva, but as I can't register it with the group id "com.google.guava" or even "com.google.gauva", no-one is going to mistakenly use my package.

    * No fucking dance of the C libs. Or Rust these days. I want to use a Python package that wraps a C lib, but there's no binary wheel built for my version of Python and/or platform arch, so build from source it is. Which I'll figure out when pip install -r breaks, and then I get to a) apt-get/brew/etc. install the lib and/or headers b) install any compiler toolchain needed buy not yet present c) export compiler flags and header locations d) all of the above, and then run my pip install again. Until the next library breaks.

    * Intersection types for generic bounds. I don't need it that often but when I do, I really miss being to say that for `def foo(ex: T) -> Z`, T must implement interfaces A and B.

    * Logging. Occasional horrible security holes aside, Java's logging story is one of the best I've ever worked with, compared to it, Go's sucks, Python sucks more, like how you can't set your preferred timestamp format AND include millis without writing a custom formatter (seriously, go look at the source code of logging.Formatter.formatTime...)

    * JMX and MBeans. Having detailed VM performance metrics and the ability to change exposed values or execute an exposed method at runtime built into the VM is amazing. Want to have a quick look at what's happening with the GC? JConsole in. Want to set one logger in particular to DEBUG to see what's going on in prod without having to restart anything? JConsole or jmxterm and away you go. Want to experiment with your batching parameters under prod load to find the sweet spot for throughput? Expose them via an MBean.

    * No need for pyenv, virtualenv, etc. Although being fair, if you're working with different incompatible JDK versions, you'll usually end up using SDKMan like Python uses pyenv, and Maven needs a little bit of additional configuration to locate your toolchains, but Gradle is smarter about finding your available JDKs.

    * Libraries with type signatures, makes for far easier code reading, and if you pass **kwargs 5 levels down, I hate you. Yes you, sentry-sdk...

    * Libraries with correct type signatures, looking at you confluent-kafka, either publish type stubs to typeshed, or update your goddamn doc-string type hints so my IDE doesn't think that confluent_kafka.Message.value() is missing a parameter.

    * The ecosystem. I really really really miss the ecosystem of JVM FOSS packages.

    * The speed, in general.

    I'm sure there's more, but these are the pain points I've been having of late.

  • wscp-devOP 3 years ago

    Id rather say use kotlin. It comes with a better type system with explicit nullable types, proper closures, and syntactic sugar to easily enavle beneficial programming patterns.

    Nd it is very compatible with Java itself, interop is dead simple

valenterry 3 years ago

Finally Java catching up with some basic features that Scala has for 10 years or so. Hoping that more good stuff from Scala will get into Java soon, maybe at some point I can try to use Java again. :-)

xyst 3 years ago

Big firms I have worked at still using Java 8.

Dead.

ArandomAccount2 3 years ago

Has anyone used virtual threads? I tried to migrate my app over to VT's and kept experiencing random deadlocks and I couldn't figure out what was causing them. I tried moving all the synchronized blocks to reentrant locks, but that didn't work. I also tried turning on the TV debugging system properties, but none of them printed the problem.

KillenBoek 3 years ago

The problem with Java is not Java. It is Oracle and no amount of new features is going to fix that.

  • kaba0 3 years ago

    Can this fkin FUD finally die? Java is pretty much the safest bet on a longevity, stability, risk aversion spectrum. Also, Oracle just has a particularly bad PR, but it is not at all worse than any other similarly sized company.

    • wscp-devOP 3 years ago

      Oracle has definjtely done bad things; mismanagement of java is not one of them. They got a pile of crap and turned it into something competent.

  • riku_iki 3 years ago

    I am wondering if Oracle is really playing significant role in Java evolution, they have some open process with many other companies contributing.

  • ant6n 3 years ago

    But, you know, Java too.

lakomen 3 years ago

The biggest problem with Java is... the walled garden, the snob society, the elitist, exclusive culture.

Go isn't like that, or at least wasn't when G+ was still around.

Nowadays I don't get in touch much with people, but when I create issues Go people are usually not as unfriendly as Java/JVM people.

  • xxs 3 years ago

    > The biggest problem with Java is... the walled garden, the snob society, the elitist, exclusive culture.

    No idea how you have managed to come to such a conclusion, or what kind of experienced you might have had. I have been part of some of the core JSR/groups, as rather independent/unaffiliated (not oracle/google/hp/ibm/twitter) - there was no gate keeping, elitism or anything alike.

    I'd consider mailing lists extremely professional, respectful, even nice.

    • gorjusborg 3 years ago

      Agreed, I have never seen a pattern of elitist behavior unique to the Java ecosystem.

      There are always people like that when groups get big enough.

      The thing I love about the JVM ecosystem is the engineering culture. The quality of the platform and most libraries is very high, and well designed.

      I don't love the Java language, but it can get the job done.

  • boxed 3 years ago

    Rudeness scales mostly with the size of the community. If you go to something like Nim you will immediately find them way more nice than Go, just from this.

  • raincole 3 years ago

    Java? Elitist...?

    Maybe it's true for Haskell or Rust. But Java?

  • bsdnoob 3 years ago

    Imo problem with Java is... JVM because it's quite a resource intensive application itself, memory usage is orders of time magnitude worse than most of the language I've used.

    • sz4kerto 3 years ago

      Interesting. A Spring Boot webapp (with the runtime dependency injection framework, etc. etc.) serving some static content and exposing some REST endpoints works fine with 32 MB RAM. Is it really orders of magnitude more than other languages, e.g. will a Go-based webapp consume less than 300 kBytes of RAM?

      • wscp-devOP 3 years ago

        I do believe that number will go down in the coming releases; things like valhalla will allow us to pack data representations much more efficiently after all. the only things that really benefit from object identity are behaviors, not data.

    • SpaghettiCthulu 3 years ago

      That's almost always a consequence of poor engineering. You need to consider the runtime when developing any program. With Java, that runtime is more than just your CPU and OS, it's the JVM too.

    • belfthrow 3 years ago

      Forgot that our computers were so resource constrained these days...

Keyboard Shortcuts

j
Next item
k
Previous item
o / Enter
Open selected item
?
Show this help
Esc
Close modal / clear selection