Hacker News new | past | comments | ask | show | jobs | submit login
Java for Everything (2014) (teamten.com)
172 points by ingve on April 25, 2021 | hide | past | favorite | 246 comments



As an experienced Java programmer , I decided to do a project in Golang to see for myself what the hype was all about. And it was...underwhelming. The Go plugin for VScode barely works - terribly slow, inconsistent autocomplete, hanging during debugging etc. I had to pay for Goland just to get a reasonable experience which is still worse than Java+IntelliJ community edition.

Language wise - you need for loops for everything, no maps or streams. Also where are the concurrent collections in the stdlib?

I wonder if all the Go love here is from people who never worked in earnest with Java ? Or only worked with dynamic languages before?


This comment is so hilarious to me. I was a Java programmer for 8+ years. Go throws all the boilerplate away. The multiple layers of abstraction. The AbstractFactorySingletonProxyFactoryBeans. All the singleton static classes, and builder patterns, and the stuff that just makes me shudder these days. Instead what you get is a balance between needed features and beautiful simplicity. The code is almost always understandable in Go. It's right there in front of you! Yes! Everything is a loop or a "for range"! It's the most beautiful part. It means I can read a page or two of code and understand 100% exactly whats going on. Contrast that with Java, where you often had to dig, on average, 8 layers deep to get to the root functionality, it's a breath of fresh air. The best part about Go arguably is it's a get shit done language, and it detracts the type of architecture astronaut types that love to overcomplicate and overengineer everything, if not sheerly by the lack of ability to do so (which is why so many who love Go today fear the incoming generics)

Anyways, just my two cents as a almost decade long "enterprise" java developer, who has used his fair share of netflix packages as well.


> Go throws all the boilerplate away

Wait, what?

I spend my life nowadays writing boilerplate in Go. The language and ecosystem is riddled with boilerplate and needing to repeat yourself. That said, I find the language plenty productive, but concise and reusable Go is not.

The rest of your post has nothing to do with the Java programming language and instead has to do with your frustration at the Java enterprise ecosystem, the desire to make things abstract for extendibility etc etc... considering Go is now being adopted heavily in those same enterprise shops and often being written by former Java developers I predict it will suffer a similar souring of public opinion by 2030 or so.

Enterprise Go is coming.


The idea often ignored is: Choose the abstraction, which is simplest, yet powerful enough to express what you need to express and still allows for simple modification / extensibility of the code.

In many cases, that is a function. Functions you can keep mostly on the same level of nested-ness. Occasionally you will have a higher-order thingy. A class, which gets instanciated but then the instance is not used? Well, that's a code smell. Probably not a real class you're dealing with, but someone had the urge to hammer it into a class thingy. Then the next person will come along and inherit from that and the one after that will write an adapter around it and so it goes on, until a degree of complexity is reached, that is mind-boggling.

A lot of classes also disappear when you simply create a struct and write the functions that deal with the struct's members, decoupling state and behavior. Of course this is not how it is done in mainstream OOP. Some language have adopted this kind of approach. For example Rust with structs and traits being implemented for a struct separately.


What prevents you from using classes as only namespaces with static functions?


Nothing really. It would be unnecessary though.

Hypothetically speaking, when using the concept of a class, one would expect an instance creation somewhere and that instance to be actually used. If it is not used after creation, then that means, that the constructor can probably be written as a function, saving one level of nesting and also using a simpler concept to express the same thing. When looking at a class, I might need to also consider what its base/super class is and might need to look at what members and methods that one has. I might have to look at what interfaces it implements. When I see a class, I expect some kind of state to be stored in it. If there is no state or only a single attribute, then that might be another sign, that I am not actually dealing with a thing, that needs to be a class.

A class is quite a complex thing, wherein one needs to look out for a lot of things.

Often making everything a class comes with another disadvantage when writing unit tests. You always have to instantiate (assuming not everything is static) and, if you hold state in member variables, you need to account for that in tests, covering various values of that member variable. Writing things as a class makes it easy to have side-effects updating your object internal state. This can make testing even more difficult.

There is complexity, which is inherent to a problem, and there is complexity created by people trying to solve problems with more complex than necessary means. Use a class when necessary and useful. Not for everything that does not hide on the count of 3.

For the use I take from your question, I would recommend simply using namespaces for implementing namespaces. If the language does not provide such, then see if there are modules, which serve as namespaces. Only as a last resort use a class to build a namespace. In that case I would already ask myself, why my language does not support something as basic as a namespace.


How is using Math any difficult? And I don’t see not having namespaces as a bad thing. In a class-used-as-namespace, there are basically no restrictions. What benefit would using the `namespace` keyword instead of `class` give? Especially that you have static imports.


Reverse peristalsis


I’m not saying that it’s necessarily a good thing, but what problem does Math have for example?


Implying to impressionable minds that a function can't exist without a class.


Well, it’s always good to known a few languages, so you don’t over generalize some features.

But viewed as a namespace, there is at least no global namespace pollution.


Difference between Go and Java, Java drives developers to write bloated code. Bunch of abstract classes, interfaces, fancy inheritance, getters/setters, OOP patterns, classes for anything and everything .. all in a different file. Normally, some code can fit in a single file, a logic can be a method but Java way of doing it in 20 files, 20 classes, 3 sub-classes, 3 interface implementations. I think this is the boilerplate that matters most.

I think Go will not ever be as bad as Enterprise Java because language and community culture which is shaped by language, don't give you as much opportunity to abuse it. If Go gets some new features that may enable abusing it, then yeah, history will repeat :)


> Difference between Go and Java, Java drives developers to write bloated code.

Nothing in Java drives you to write bloated code with tons of classes. javac will not throw an error if you write proper simple code.

If you chose, or were forced by bad team culture somewhere, to write 20 classes for what should've been one function, that's a people problem. Java didn't make you do it.

That team who loves complex overengineering so much will do the same thing in whatever language they switch to someday.


No. Nothing about Java drives developers to write bloated code. You can write simple and concise code in Java, and i do.


Unfortunately Spring is a de-facto part of the language, for most enterprise codebases.


In ~20 years of developing in Java, I've never used Spring. It's certainly not a de-facto part of the langauge.


> Difference between Go and Java, Java drives developers to write bloated code. Bunch of abstract classes, interfaces, fancy inheritance, getters/setters, OOP patterns, classes for anything and everything .. all in a different file.

Or you could just not do that. The Java culture is heavy on those things, but nothing forces you to participate in this if you're building from the ground-up.


There is a big legacy of spring/j2ee or pre-dependency injection apps which either look like a pile of needless factories, or a pile of XML.

Modern Java is a much more pleasant developer experience than that. For extremely large applications it also comes with the benefit of being able to remove the boilerplate and ceremony required to do basic things like call an internal service, internal service auth, rate limiting, circuit breaking etc.


I don’t get the no boilerplate aspect of your comment. For all that Golang has going for it, avoiding boilerplate isn’t one of them. I’m thinking specifically about multiple clauses at the beginning of functions passing up return values and copy pasting the same code (or auto generating it) to work around lack of generics.

Most of the criticism about Java seem to be about old codebases that overused Gang of Four patterns, when that used to be more of a thing. Don’t blame the hammer for the shoddy building, blame the hammerer.


No true scotsman, err modern Java developer would ever write Java like that. The language has better ways to do these things now and it's just a small matter of rewriting every project in existence with modern tooling. Of course modern Java moves the complexity to reflection magic so it's even more difficult to figure out what's happening when something breaks.

I'm happy I don't have to work with any kind of Java any more.


> Of course modern Java moves the complexity to reflection magic so it's even more difficult to figure out what's happening when something breaks.

Are you 10 years behind? Modern Java moves the complexity into compile time annotation processors, so it's even more difficult to figure out what's happening when something breaks.


It's some time since I last touched Java, and even back then the projects I was involved with took care to use only stable releases (i.e. either oldest supported or already EOL'd) of anything.


I'm having Micronaut flashbacks...


AbstractFactorySingletonProxyFactoryBeans 8 layer deep is really the anti-pattern of reusability, you can't just copy/paste that code into another project without also including hundreds of dependencies. It's like "proof of work" in cryptocurrencies, eg. you need 50 people to produce the code. Or some type of DRM to make sure no one else can use it.


Every for-range loop is noise, a missed opportunity to take what you're doing and factor it out to something reusable (filter, map, flatMap, groupBy, join, whatever) that nobody should have to read more than once per project (or ideally, ever). There's no beauty to be found in repeating yourself when the computer is much better at that.


"AbstractFactorySingletonProxyFactoryBeans" I don't think that this meme phenomenon is prevalent in modern java projects, and I would say that it is even less in the Kotlin ones.


It's a bit prevalent, not very, but more importantly Spring is built entirely around AbstractBeanFactoryFactoryInstantiators and we're all using them by proxy.


Lol wut, why is there two factories in there? and an instantiator as well?


Every factory needs a factory, and the Instantiator design pattern is highly ergonomic compared to using "new".


haha ok I'm staying with Rails


Right. Who cares what class names the implementation uses? This is the downside of hacker news. Everything has to be implemented in rust or go or it's a bloated piece of crap


Please don't willfully misconstrue what GP commenter said.


I sympathize with the general sentiment of your argument, which is what initially drew me towards Go (in addition to the hype).

For better or worse, Go is where all the energy is in terms of OSS, so I do hope I see the light some day, but for now, the dev x for me is pretty underwhelming compared to Java


I don't see how enterprise culture has anything to do with language. You're implying that you can't do Go style programming with Java. Except you can, and it will be prettier and easier to read with streams.


if you think this way about go, you probably have a REALLY good team that can design in a really proper, DDD-ish way (in that case, go en masse to google asking for your hard earned 500k TC, since even google has confusion on the best way to structure go projects) or you simply program toy stuff/basic integrations which boils up to a map from a type to another. go doesn't scale to huge codebases in normal teams.

otoh, you are totally right about the 8 layers deep root functionality, but that IMHO reduces to mindless application of textbook oop patterns to applications (I still have to see a company randomly "changing databases" so the 8 layers of abstraction over the db are correct).

still, I adhere to a lost standard these days, which is less code as possible. golang is automatically disqualified since it thinks that a 8 LoC for loop with temp variables is "simpler" than a .map(fn) (so much for "throwing boilerplate away"). it likes to introduce point of failures, and I dislike point of failures


> The multiple layers of abstraction. The AbstractFactorySingletonProxyFactoryBeans. All the singleton static classes, and builder patterns, and the stuff that just makes me shudder these days.

If you chose to write that kind of code and then hate it, that's all on you. Neither the Java language spec nor the JDK make any effort to steer you into such baroque complexity. Keep it simple, best Java code is very simple.

I wrote Java for about 20 years (many of them at Sun) and have never written a AbstractFactorySingletonProxyFactoryBeans or anything like it. Don't do it.


By "throws away the boiler plate" you mean sets yeah?

And before the inevitable, a map[T]interface{} only provides part of what a real set does. The rest is for loops.


Totally agree. Except I went from Java to Scala to Go, so coming from Scala Go was even more underwhelming. Scala had just as simple aync sugar and doesn’t have stereotypical Java boilerplate, and had powerful collections functions. Golang felt like an antique.


> Golang felt like an antique.

And, IMHO, no implicit nulls, proper sum types, pattern matching was all it needed be considered modern. If left the last 40 years of compiler/language research outcomes on the table. Such a pity.

And give that the std lib is not riddled with implicit nulls that mean all kinds of things (like any kind of error, or absence), this will not be fixed in the next decade. What a waste.


Omg, implicit nils and "nil values" really bugged me.


> I wonder if all the Go love here is from people who never worked in earnest with Java ? Or only worked with dynamic languages before?

This is the type of non-constructive statement I’m used to seeing on programming forums elsewhere on the Internet. The thing is, it’s just dismissive and irritating. All it says is, “I don’t understand why this thing is popular. Could it be that all of the proponents are simply inexperienced and don’t know any better?” — of course it’s possible, the same way that it’s possible that everyone who says my cooking is terrible just has bad taste and doesn’t understand good cuisine.

It could just be that your experience of Go was not very complete. There are certainly sore spots in Go. Maybe gopls was broken when you tried (I just tested and VSCode Go is faster than Goland on my machine, so I actually suspect something was wrong.) Maybe you picked use cases that it was just not very good for, or possibly you missed some of its utility in the time that you used it. There’s no way for me to know. I’m sure you have enough Java experience to see how someone fiddling with Maven, Eclipse, Spring, Hibernate, Guice... and running into problems could spoil them on the language or its ecosystem early on.

And yet, what disappoints me more is that when I saw this comment, it was the second highest on the page. Meaning the statement seems to have resonated rather than raising red flags.

I kind of get it. Go is one of the trendiest languages to hate now. I would guess it is in third behind Perl and PHP. Don’t get me wrong — many people unfairly hated Java too, but let’s face it, it hasn’t been trendy to baselessly hate Java in a long time. Especially not with how much it has changed and improved. I still don’t like that people do this. It feels like on at minimum a weekly basis I get chastised or see others get chastised for expressing our satisfaction with Go. Thankfully it is uncommon here, but in other online programming circles it is common enough.

Imagine you’re a beginner who is learning Go as a first programming language and they read your message. What message is it really sending?

Perhaps you did not mean for this to come off this way, but to me this is the language of condescension.


What disappoints me upon seeing your comment is that someone chose to write nearly 400 words to complain about how irritating the parent's one-question was without answering the said question in the slightest.


I certainly did actually address the question:

> of course it’s possible, the same way that it’s possible that everyone who says my cooking is terrible just has bad taste and doesn’t understand good cuisine.

I could’ve answered anecdotally about my experience with Java, thus proving or at least claiming at least one person has earnestly used Java and still likes Go. I have no idea what value that could bring to this discussion. Does anyone actually believe there is a possibility that not even a small amount of users of Go, the ~14th most popular language according to TIOBE, have not used in earnest the ~2nd most popular language according to TIOBE?

I dislike the question. I repeat my own question and now ask you to answer it:

> Imagine you’re a beginner who is learning Go as a first programming language and they read your message. What message is it really sending?


>I could’ve answered anecdotally about my experience with Java, thus proving or at least claiming at least one person has earnestly used Java and still likes Go. I have no idea what value that could bring to this discussion.

The value would be highlighting the upsides of using Go for people who're comfortable with Java, in spite of the disadvantages mentioned in the parent comment.

That information is valuable to people considering picking up their Nth language.

What value does the comment that you ended up writing add to the discussion?

>I dislike the question. I repeat my own question and now ask you to answer it

I dislike the question. I repeat my own question and now ask you to answer it:

What value does the comment that you ended up writing add to the discussion?


Sorry, I didn’t mean to come off condescending at all, it was a genuine question! At the end of the day, these are all just tools and people have their preferences. I try not to get too attached to any of them personally.

Also, if it wasn’t clear I was addressing programmers with experience in more than 1 language, not absolute beginners. If someone who is learning Go as their first language, I wholeheartedly endorse learning it! (Although Python would be better :-))


Well, I apologize for taking it the wrong way. I hope that others who agreed with you read it the way it was intended and not the way that I did. I still think the answer to the question is a bit obvious; plenty of Go devs used Java before Go. That said, I would guess that most people who have migrated away from Java did so before it became more modernized.


> it’s just dismissive and irritating

It's not dismissive. I have worked in Java and Go, and i ask the same question, entirely genuinely. It's up to you if you find it irritating.

> it hasn’t been trendy to baselessly hate Java in a long time

It's happening on this page, today, my friend.


> Language wise - you need for loops for everything, no maps or streams.

I think that's library wise.

Language-wise I wish I could write a map interface in Java. But soon Go will get half-arsed generics and I won't be able to write a map interface in that either!


> Also where are the concurrent collections in the stdlib?

I think this is the crux of your issues with Go. If you're going to learn a new language, learn the new language. Don't try to recreate your existing language with a different syntax.

Java and Go have different strengths and weaknesses, and they are not used to build software with the same architecture. Java is useful for writing big monolithic servers while Go is better at building smaller independent modules communicating with each other, but there is much more to them than this.

I work with Java but still prefer to use Go for my hobby projects because it makes concurrent processing much easier to reason about. Also it's far less tedious than Java to install and use, but the bar isn't very high to start with.


> Java is useful for writing big monolithic servers while Go is better at building smaller independent modules communicating with each other, but there is much more to them than this.

There's nothing that makes Java any less suited than golang for writing small independent cross communicating modules.

For all the hype in golang about it being useful for concurrency, the fact that it lacks a concurrent collections library sticks out to anyone who used it.


It's interesting that you chose VSCode + Go plugin rather than IntelliJ Community + Go plugin?


Right, I wanted to have the “modern development experience” as much as possible. Most tutorials out there still recommend VSCode to get started with Go.


hmm, I even use VS Code for Java


Sure - OP seemed like they were implying they're already comfortable with IntelliJ. If you're trying a new language, and then also trying new tools to learn that language, it sounds like you're taking on too much at once.

If you're already comfortable with IntelliJ, you can continue to use IntelliJ.


Yup many migrated from node js


Upvoted not because I agree, but genuinely want to read discussion on this. I used to agree, when I first started doing Android development and "relearned" Java since playing with Applets at age 14, but threading made me seriously reconsider. These days I make a living writing TypeScript ( nearly exclusively ), and although the tsc says it works, I always have a suspicion it could not work. Whereas with Java if it compiles it definitely works unless you have some R build issue. I think TypeScript is a nice middle ground, but I do wish there were some lower level semantics for backend TypeScript development. I've looked into Rust and it looks very complex and unfriendly ( I would need to rewrite nearly my entire backend libraries e.g. db drivers and ORM generators ). Anyway, it's a decent take, but I wish the same could be said of TypeScript.


You may already know, but C#/.NET and TypeScript are closely related and C#/.NET gets a lot of praise for building kind of a more ergonomic Java. It might be worth checking out if you enjoy TypeScript and also Java. FWIW they've come far from the "Microsoft means Windows development" era of C#, if that's a concern of yours.


I agree. I am very curious how the .NET environment develops. The CLR is much more embeddable. Unity3D chose C# for a reason. Blazor is another interesting promising .NET technology. Considering Microsoft's engagement in Open Source I can imagine they are able to overtake the role of Java in the long run.


I'll echo this sentiment; I did full-time C# development for work for two years and it was a dream. Nowadays I do a combo of Java and TypeScript and find myself constantly wishing I was just back in C# land where it takes the best bits of each language.


I read the point of the article more in terms of "one language for everything" rather than something about Java in particular.

I think it is a fair point. Staying within a language and an eco-system of libraries, tools etec. makes sense so you can get profiency and just know how things work without too much thinking about it.

However it only holds to an extent as many languages are tied to or are native to a particular platform. I.e. JavaScript in a web browser, Java on the JVM, Java in Android, Objective-C in iOS etc. And some are definately not mature when you go outside their habitat. Try to compile Java into JavaScript (using GWT or whatever), or into a binary. You can do it however it doesn't really makes sense, so much of a language is really its libraries and way doing things. You are not going to get HSQLDB and JPA running inside a web browser for any reasonable application.


You don't need to run literally everything in the browser, we had web applications since the invention of CGI.


You might like Scala - it's a first-class backend language but also has a great development experience on the frontend (better than TypeScript in some ways) via Scala.js.


> and although the tsc _says it works_, I always have a suspicion it could _not work_

TypeScript fails me almost exclusively due to `!`. The association is so strong that whenever I encounter an error, I am excited to see if it's due to `!`. In the absence of non-null type assertions, TS feels very safe to me, largely due to experience of not seeing it fail.


Throw in an eslint rule to disallow ! outside of tests, you won't regret it


Unfortunately I have some spots where it’s unavoidable due to generated types that I can’t control being not quite right. It’s sad! Yes, otherwise I’d never use it, or far more sparingly (sometimes it is “correct”, though with effort it can be avoided)


I have a utility function that I use for cases where I know for sure that a value is defined:

    export function assertIsDefined<V>(
      value: V,
      buildMessage = defaultAssertIsDefinedMessage
    ): asserts value is NonNullable<V> {
      if (value === undefined || value === null) {
        throw new Error(buildMessage(value));
      }
    }
It would prevent follow up errors if the value in fact was not defined.


Yeah I could definitely do this, and maybe should. But the issue is so systemic due to the bad generated types that this would cloud the code without much added benefit.


I had my own share of problems with generated code, so I feel you.

I often use that utility when I have some type where under certain condition a value will always be defined, but a union type would make it too complex to be useful.


Yeah in my case I am using Postgres via Hasura, which exposes the Postgres DB via a GraphQL API, which in turn can be used to generate types. Unfortunately the nullability of fields in a Postgres view cannot be determined, so all fields in the corresponding types are nullable [0], even if they aren’t in the actual underlying table. So I end up using ! a lot because I know the field is non null in Postgres. It’s a unfortunate.

[0] https://github.com/hasura/graphql-engine/issues/1965


What do you mean, could you explain / give an example?


TypeScript has the ! operator [0], which can be used to override the type system’s null check.

For example, suppose I have a variable of type

  type Name = string | null
  const name : Name = null
and I pass it to a function that expects just a string (not null),

  function len(str: string) {
    return str.length;
  }
Then

  len(name);

will fail type checking, but

  len(name!);
will not fail type checking, but will fail at runtime.

[0] https://stackoverflow.com/questions/38874928/operator-in-typ...


Oh wow, I did not know that this existed. Definitely gonna need a linter to make sure it's never used.

Do you know why it was added? Ive used an annotation that disables type checking on a couple unit tests, but this seems much harder to notice


Definitely not a TS expert but I think it’s for cases where you know something “better” than it is known to the type system.

An example that pops to mind is how React’s createContext() typings for some reason require a non-bill default value, but you may not have such a value at the time the call is made. Personally I think it’s totally legit to just do createContext<T>(null!). I don’t think this leads to errors that won’t get quickly noticed.

But if you get carried away, it’ll bite you for sure, especially in code that has more going on than define a React context.


I write TypeScript every day, and sometimes it can be pretty useful.

Like, if you have an interface...

   interface MyInterface {
      someValue?: string;

      /** Let's say this only exists if `someValue` exists */
      someOtherValue?: string;
   }
And then in some code later...

   const myFunction = (someParam: MyInterface) => {
      if (someParam.someValue) {
         myOtherFunction(someParam);
      }
   }

   // let's say this function is only EVER called if `someValue` exists
   // we know more than the type checker in this case
   const myOtherFunction = (someParam: MyInterface) => {
      console.log(someParam.someValue!.length);
      console.log(someParam.someOtherValue!.length);
   }
There are definitely more "correct" ways to do this (i.e. using `Partial` or re-casting to another type) but sometimes there are edge cases that aren't worth doing things more correctly (like, if this is only happening in one spot)

Lots of folks make the mistake of assuming the TypeScript is strongly typed, but it's not really... I like to think of its type system as "squishy" in that you can very very easily fake things or trick it into compiling. I think of the types more as comments and hints about the code and not there to ensure program correctness.

This is actually one of my favorite features of TypeScript; it's not as strict as, say, Java or Scala, and it lets you get away with some things without having to rework all of your types. This can be a bit of a footgun, BUT if you're also writing unit tests and integration tests then you'll have all of your bases covered.


> but sometimes there are edge cases that aren't worth doing things more correctly (like, if this is only happening in one spot)

Yep!

> Lots of folks make the mistake of assuming the TypeScript is strongly typed, but it's not really... I like to think of its type system as "squishy"

Totally! That’s what makes it so nice. Great way to describe it.


You should take a look at Kotlin then. I'm surprised that no one mentioned this so far.


Try Kotlin! Android development had become much better for having moved to Kotlin, and I prefer it to Java for backend development as well.


> although the tsc says it works, I always have a suspicion it could not work. Whereas with Java if it compiles it definitely works unless you have some R build issue

That's not true, right? AFAIK, the Java type system is broken and any type might silently be another type which doesn't support any of the methods the static type would indicate. It's basically as type safe as C in my eyes.


It's not that bad. Sure I'd call parts of it broken, but this isn't it:

> any type might silently be another type which doesn't support any of the methods the static type would indicate

When an object is typed differently from its actual runtime type, it's usually because it's hidden behind an interface type. So it indicates fewer methods than it supports. Safe, but unergonomic!


No, every object can be null, which just doesn't support any of the advertised method. You can have a `Frobnicator frobnicator` variable where `frobnicator.frobnicate()` blows up at runtime because its runtime type wasn't what you expected.


Oh, I agree that null is fucked.


Variables being nullable is not "as type safe as C". Please don't waste people's time with hyperbole like this.


I don't see why not?

In Java, every access of an object variable can blow up your program even though the type checker is happy. In C, every access of a pointer variable can blow up your program. This seems very similar. Neither language provides type safety.

EDIT: To be clear, Java is definitely safer than C. When Java "blows up" due to a null variable access, it throws an exception in a well-defined way. When C blows up due to a null pointer dereference, anything can happen, and if you're lucky your program terminates unconditionally. It's just that neither error is caught by the type system.


It's not just nulls. In C, you can compile and execute this without warning:

    int square(char* string) {
        int *number = (int*)(void*)string;
        return *number * *number;
    }
It's UB, so in principle it can do anything, and in practice, the best thing it might do is return gibberish.

The Java version of this would throw a ClassCastException on the first line.


I already said Java is safer than C. But neither language would catch that error _in the typesystem_; it's a runtime error in both languages.


And `head []` will explode at runtime in Haskell. How is it relevant? Type systems can never prove every interesting property of a problem. Yeah, nulls suck, but there is very good static analysis for Java.


The point is that Java doesn't seem that much more type safe than C.

I don't see how external static analysis tools are that relevant when we're talking about type safety.


I just don’t feel that it would be fair criticism, since by that definition, none of the following languages are safer than C: C++, C#, Java, JS, Go, even Scala. So basically the litany of languages having null..


All of those languages (possibly except for C++) are safer, in general, than C. But C#, Java, JS and Go aren't more type safe than C. I don't know how it works in Scala.

I just don't consider the language to be "type safe" when every single variable (except for primitives) can explode at runtime with no warning from the type system. At least with C++ you can have references which you know won't be null.

The fact that you bring up JS, a language with _literally no static type checking_, confuses me. Are we even talking about the same thing? Maybe I should've used the phrase static type safety rather than type safety? I thought it was clear from context (as a response to "with Java if it compiles it definitely works"), but maybe not.


> aren't more type safe than C

That’s just false. C has really “random” implicit casts everywhere, not having is already great.

And I agree with you that nulls are a huge mistake, but that’s one aspect of type safety.

> At least with C++ you can have references which you know won't be null.

Yeah, they are just uninitialized.


Java, if coded properly, ensures that a NullPointerException means that something went really, really wrong - in which case you're better off terminating than doing anything else. For variables that are expected to be missing occasionally, there are the Optional types or Collections/Lists, which I use extensively.


It’s an exception not an error, you can easily catch that, which may make sense eg. when you run third party extensions that should not bring down your whole program.


> Java’s a pretty nice language, and when my code compiles, which is often the first time, it’ll usually also run correctly.

This is the exact opposite experience for me.

I find Java's type system to be extremely lacking (e.g. nullability, no discriminated unions, etc.), such that I write plenty of application code to mimic what a robust type system would enforce. Unfortunately, since it's not a compile time check, if you do it wrong, you get errors in production. In this way, it is the same as a fully dynamic language—what compiles has loose guarantees about correctness.

Excuse me for a moment, but I'm going to be that annoying guy—but once you get some experience with an ML style language (e.g. Haskell, OCaml, SML, etc.) it's painful to go back to these class name based type systems.


> when my code compiles, which is often the first time, it’ll usually also run correctly.

I don't understand this, this is extreme hyperbole. Even when I used one of the strictest JVM languages where almost everything was a compiler error I still only had the guarantee that 99% of the time it is not going to crash, not that the code is correct. Of course, Java crashed all the time, groovy crashes a lot of the time, but it's a dynamic language that is supposed to fail like that. Once the code compiled, the business logic could still be wrong but getting the business logic correct is my job, not the machine's and the benefits of avoiding machine errors cannot be understated.


> discriminated unions

Java now has sealed classes/interfaces. They are sum types, not sure what is actually the difference between discriminated unions. And with records, you have named tuples, basically product types. As far as I know, Haskell also only has algebraic datatypes.

The syntax is like so:

``` sealed interface Expression permits Add, Multiply {}

record Add(Expression a, Expression b) implements Expression {} ```

(written on phone so it may not actually compile)

And you also have switch expressions enforcing that you have used up every possibility (even null!), and with the coming better pattern matching, Java will become quite an expressive language.


Thanks for bringing this up. I am actually very excited about these features, but they are still not quite available for most of us Java devs yet. The LTS version that contains them doesn't release until September, and it will take months (if not years) for many shops to upgrade.

My critique was more targeted to the Java of the time period this article was written in (2014), but these new additions are another point for the "Just write it in Java" folks.


F# might be a great compromise. A HM type system plus a Java-like platform with excellent libraries and support.


just as a heads up, as someone who's worked as an F# dev for the last three years: it's HM, but compared to the other languages mentioned (Haskell, OCaml, SML), it still tends to feel C#-y when doing fairly complex things. Also some things don't quite feel right: indentation is sometimes finnicky, type inference only really works left-to-right (might only be a problem for me, I do a lot of Haskell in my free time so right to left feels more natural), still has all the baggage from other .NET languages, which helps interop, but also means that when you try to bend the type system a bit you end up with method overloading. Even for simple things like optional or named parameters (which can only be done on uncurried instance and static methods, but not on functions). Type providers feel great until you have enough that they break your editor and they slow compilation down massively. editor tooling also feels pretty immature (it didn't work well at all on my machine, but YMMV). I think if you want to use an HM language, go with OCaml/Haskell, don't bother with F#, unless you specifically need the ecosystem. OCaml/Haskell's ecosystems are smaller compared to .NET, but you can still get by a lot of the time, and IMHO you get a more polished language + an ecosystem that was designed for it, as opposed to getting a language that at points feels dodgy + a big ecosystem that (for the most part) wasn't at all designed for the language you're using.

TL;DR: F# is only worth it if you need to take advantage of the .NET ecosystem, otherwise just go with SML/Haskell/OCaml


Scala is similar, with a somewhat nicer type system (full HKT) and an even more Java-like platform.


Do you know anywhere that actually use it? I've heard Walmart Labs, but that's about the only place I know about.


I like Java but I think the right job for all jobs, if you're going to pick one, is TypeScript:

- At this point you can say TypeScript is mainstream. It's not Java, but it's definitely not a niche toy.

- Many companies stand behind it and use it in production.

- It is widely supported by tooling.

- With TypeScript, every element of your stack can not only share code, but can share types, too. This has been a huge boon for me.

- The type system is really, really flexible. It seems possible to specify the exact degree of safety that you want for any given situation. I never feel bound by the type system. It's very liberating. Not so with Java or C#.

- It compiles to JavaScript, so it can run anywhere. On the backend you can run it natively with Deno. I haven't tried this yet, but am looking forward.


> - The type system is really, really flexible. It seems possible to specify the exact degree of safety that you want for any given situation. I never feel bound by the type system. It's very liberating. Not so with Java or C#.

Personally this is why I believe all languages will converge into the structural, gradual typing model of Typescript.


As a hardcore fan of static typing, how would you convince me to use a gradual typing model?


Gradual typing gives you the option. You can be as statically typed as you want. Dart is gradually typed. So when I'm writing some flutter code, I may not know when types I need in the moment, I can omit type signatures until I work that out then write my types and go back to update the code.


I wouldn’t. My experience with Flow and Typescript is that the incremental adoption bit is misleading. It’s a hook. It’s possible, but you’ll quickly come to resent your JS code and go all in. That process will get you through most of the learning curve and that’ll be that.


How do you type something like the groupBy function in TS?


Which language do you work in? I can promise you that Typescript can type things way more strictly than your language, unless it's Julia.

Typescript allows you to not make typing very strict when it's not important, but also allows you to define things stricter than your average Haskell codebase.

Most other languages have only 1 option about how strict a piece of code is typed.


My situation is: I statically know the types of things at compile time. I'm not sure how to 'define things stricter than that'.

My question was: what benefits would I get from sometimes not knowing the types at compile time (which is what I guess gradual typing is)?


Sure if you are happy to struggle with V8 performance.


Yeah I hear you, but I think the pros outweigh the cons. For one thing, I have never run a stateful V8 container, which makes scaling trivial (if the performance issue is actually just V8 and not some greater architectural defect). V8 performance issues can be overcome, and it’s not like the JVM is trivial to tune. Every workload has a learning curve.


I hardly ever had to tune JVM, and would never put the single threaded V8, with a dynamic language, under similar workloads.


Consuming more and more energy to do the same computation isn't environmentally friendly either. Just because you can scale by throwing more CPUs at the problem doesn't mean we should.


Assuming problems are worth the energy usage in the first place :)

How many Java apps do you think are out there that are not even worth the energy that they're using to run? How many absolutely asinine startups selling DRM-controlled juicers or internet connected water bottles or NFTs?

I'm not saying that every project that runs on Node or Python or whatever is worth the extra energy it uses, but this is kind of a silly argument to make with the kind of stuff coming out of the tech industry these days.


The JVM is actually the most “eco-friendly” out of the high level language platforms.


Did you ever try Scala? It has great client-side support (likely better than TypeScript's server-side support), and the type system has the soundness of Java/C# but is flexible enough to cover all the reasonable use cases (at least once you include shapeless), as can be seen by the fact that even enterprisey Scala code doesn't have to rely on magic annotations anywhere.


Scala tries to do too many things: both Haskell and Java, both backward compatible and radically new...

It just does not fit together. Want functional? Go with Haskell/OCaml/ReScript/etc. Want JVM compatibility-and-thus-OO-at-the-core (possibly with some functional goodness on top)? Go with Kotlin.


All popular languages seem to try to do too many things. Scala just seems to have achieved more than the others and has became infamous for it.

Just like any language, just use the bits you need for your project and apply KISS (Keep It Simple, Stupid) liberally! :)


Nope! What magic annotations are you referring to? In Java?


Yeah, I've found that any large Java codebase tends to use a lot of annotations (e.g. Spring, JPA, JTA, AspectJ, JAX-RS) to do things that would be too cumbersome to do within Java proper - the annotations tend to be "magic" in the sense of doing something that breaks the normal rules of the Java language.


according to Dice, TypeScript projected to do well in 10 years with increase pay and trending up.

https://visualstudiomagazine.com/articles/2021/04/01/typescr...


The world doesn't end with web apps. I use Java a lot for event based simulations and for heavy math and it works like a charm. I don't think I can easily replace it with Typescript to be honest...


> every element of your stack can not only share code, but can share types, too

We have auto-published types generated from OpenAPI specifications that we use in a lot of different projects and it's been really awesome.


Yep, I am doing the same w/ types from a GraphQL API. It's wonderful. The entire stack's types are coupled to the Postgres schema. Postgres -> Hasura -> GraphQL -> generated types. <3


I'd love to go all in on something like TypeScript but as long as it's backed by a runtime without true concurrency it can never be "the right tool for all jobs". Same problem with Python which I would also like to embrace but ultimately always have to complement with something that can do real multithreading.


"The problem is that programmers perceive mindless work as painful and time-consuming, but the reality is never so bad."

No, that is the actual problem. Your feelings don't care about the facts. You don't want to filter developers for their tolerance for mindless, time-consuming and painful work. If you do that, Parkinson's law will strike you so hard you'll turn out like IBM.

Of course, you also don't want to end up at the other extreme, where all the parts of your stack are so exotic that only one person on the planet is qualified to deal with it - and they just left the company.


So here's a controversial opinion: use whatever language you're comfortable with and use the time you'd spend in flame wars about Java to make something useful instead.


Agree with this, except I think C# is better than Java. I write everything in C#: desktop apps, mobile apps, frontend, backend

I think the language is very similar to Java but some advantages present themselves 1.it has more modern features than Java, 2. it has mobile (including IOS) and frontend support 3. (possibly not true, but my impression anyway) it has better support for writing close the metal, high performance code

It really is very nice to write everything in the same language.


This article could mostly be summarized as "invest in ONE language". The arguments for that language to be Java aren't very strong compared to the arguments for ONE language.


I see some arguments for static typed languages as well. And some notes on performance, but mainly static types.


Once you combine those into "use one statically typed language" it narrows down the field to just a handful of languages, though. The "use one language" stipulation requires that the language is actually appropriate in a wide variety of situations, and has libraries to back it up in all of those. Like, you can't use Rust as an everything-language, it has limited libraries and is designed for a specific domain.

Between the two requirements, I think Java, C#, and TypeScript might be the only languages that qualify.


> Between the two requirements, I think Java, C#, and TypeScript might be the only languages that qualify.

says jtolmar in a browser written in C++


Although C++ is statically typed, all of the article's arguments in favor of static typing equally apply against C++.

Also, the way you phrased your comment is needlessly rude, to the point I almost didn't bother replying. If you actually want to learn why people have the opinions they do, you should consider being more polite.


“ the language is actually appropriate in a wide variety of situations, and has libraries to back it up in all of those”


..yes ? if you can write a whole KDE (https://kde.org/) in C++ what is it not appropriate for and what libraries is it lacking


There is a very real distinction between high and low level languages. And C++ is a nice low level language, but you wouldn’t write a CRUD app in it that changes requirements multiple times a week, because it is simply non-trivial to refactor, due to low level details leaking.


Are there any good full-featured C++ web frameworks? Comparable with Rails, Django, Spring, .net, etc?



Since 2014, when this was written, (gradually) typed versions of several major formerly 100% dynamic languages have become mainstream, primarily Python and JavsScript (TypeScript)


Yeah, there is an equivalent article that could be written for Rust as the one language (which is slightly more plausible than Java)


I think there’s a very strong argument for trying to have only one language at your company, or at least one backend language. Of course you’re still going to have some scripts, and some config-based programming for infrastructure and whatnot, but otherwise you should basically aim for a single (backend) language IMO.

Assuming you’re doing reasonably high level work (like building a typical SaaS product, not a database), I also think you’re probably best off choosing a language with the following properties:

- statically typed

- garbage collected

- reasonably performant

- reasonably easy to hire for, or at least pretty quick to learn

- compiles pretty fast

- has a strong ecosystem, great libraries/frameworks/tooling

Java fits, but so do Go, C# and TypeScript. This article says Go is too new, C# not cross platform enough - both true in 2014, but not 2021. And it doesn’t mention TypeScript, but it was VERY new in 2014, so understandable. It’s performance isn’t as good as the other 3, but has the major advantage of letting you have a single FE and BE language for a lot of projects. My current company is full stack TS (RESTful services with TS/React on the web, TS/React Native on mobile), and it’s very convenient/productive most of the time.

Scala is my personal favourite language, but I’ll agree it’s too hard to hire/train for to be a practical choice. But Java has plenty of competition from Go, C# and TypeScript.


> I think there’s a very strong argument for trying to have only one language at your company, or at least one backend language. Of course you’re still going to have some scripts, and some config-based programming for infrastructure and whatnot, but otherwise you should basically aim for a single (backend) language IMO.

Perhaps the real kernel of the advice in the article is "try to use your primary language as much as you can, even for things it is not traditionally used for".

My team mostly writes Java. We do write Python for a lot of little scripts - collecting and munging data, dashboards, etc. I have come to think that we should just do those in Java as well.


This should be tagged 2014. Most Java in use was 7 with 8 only getting released in early 2014. So any comparisons to Typescript or Kotlin or var usage in Java are newer constructs than the context with which this is written.

My favorite language to develop in is Typescript/JavaScript, but daily use Java 8 due to legacy application and would love to upgrade.


>> @spolsky Digg: 200MM page views, 500 servers. Stack Overflow: 60MM page views, 5 servers. What am I missing? << That's the PHP factor

That tweet was from 2010. Modern Day StackOverflow

1.3 BILLION page views per month, ~20X! 23 Servers including Redis, SQL and Elasticsearch. ~5x.

Although Stackoverflow is pretty much a read heavy site.

And while people can have an opinion on Java the language, the JVM and its ecosystem is often overlooked and under appreciated. Look at GraalVM.


If you're a millennial and involved in SW-development then its likely Java has touched your life in some way.

Java was the magic pill in late 90s in India and every Engineering graduate irrespective of their domain was told to get certified in it for a job. My sister(ECE) was one of them, my father got our first computer (Pentium-III ~900 MHz)to help with it in 2000 (which was a big deal for a middle-income family in India) and unfortunately the Dot-Com bubble crash hit its peak with absolutely no recruitment for java developers. My sister struggled for a while, fortunately was able to switch domain(non-SW) and has a great career now.

Fast forward to 2005, it's my turn in the Engineering college - CSE (A premium one, so job was pretty much guaranteed). Our 2nd year has introduction to programming with Java, No C, no low level languages, straight up Java. Since meritorious, Many in my college are from very poor backgrounds who never had access to computers, taking in Java directly was very tough for them. So almost everyone went for C-programming training outside our college run by one of our alumni(He has now started his own Engineering college, one of the largest in the city!) all of them studied C, so they could understand Java(programming) better!

In late 2000s it was common to define your job as a 'Java developer' and it was understood in even rural India. Famous movies were made where a character goes from rags to riches because of Java. Then in 2008 during my placements recession happened, only fraction got placed(mostly in java dev), I was into J2ME and so waited for a mobile development job. Then Android happened, got a android development job and of course Java development background helped me a lot(Worked with other major languages every now and then).

Fast forward 2019, I've shutdown my startup due to health issues. I'm not writing android applications or java-back ends anymore. Wanted to switch to some other language as primary language partly because of java fatigue, partly because learning new language could help me divert my attention from the ongoing issues, but mainly because I have less time to code(Any time saved is a time I can put for my health) .

I chose Go, because I've been burned before by Python when the application scaled up requiring expensive optimizations. Luckily Go was everything I wanted from a new language although it wanted me to empty my cup(pun intended). Now, most of my code is in Go be it production applications or home automation scripts. I don't think I'll be able to touch Java again(perhaps maybe it brings back memories I don't really cherish) or may be I'm just adamant.

If you have made it so far, Thanks for reading.


> Famous movies were made where a character goes from rags to riches because of Java.

Is this really true? I would love to know more. Could you give any examples?

I'm glad to hear you're enjoying life again.


>Is this really true? I would love to know more. Could you give any examples?

Glad that you asked. The character name is 'Java Sunderasan' from the Tamil movie 'Arai en 305il kadavul'(2008). Here's a clip[1] from that movie it shows another character explaining how Sundersan went from rag to riches within 2 years because of Java while others stayed/became poorer. Couldn't find one with subtitles but the visuals are clear enough to understand what's happening.

[1] https://www.youtube.com/watch?v=CMtp7PI8gbA


Are Indian product based companies using modern tech i.e NodeJS / Go or older tech (PHP, Python, Java) in general? By S.O developer survey, Go is one of well paid languages IIRC. Is it true in India as well?


I think Go adoption is still limited to bleeding edge startups in India. Go libraries from top Indian startups on GitHub doesn't seem to be maintained or seems volunteer work.

Where as Python did pay really well, I myself paid a fortune to my python devs working on computer-networking projects in my startup between 2014-19 as there weren't many python devs doing computer-networking in India. I guess most python devs are working on Datascience/ML and it sure does pay really well considering cost-of-living in India.

Java is still pretty much the staple in enterprise software and in large outsourcing companies(Which I believe is because of legacy products in U.S. companies/Govt. which provide projects for them). Even in India large Govt. infrastructure SW projects use Java.


You wouldn't write a web frontend in Java (not anymore), you wouldn't write your Tensorflow code in Java, nor your kernel module or device driver.

You still use the right tool for the job. Java is not always that. Also "right" should factor in your existing expertise, team culture, organizational roadmaps, etc.


Perhaps implicit in the advice to use a single language is the assumption that the set of things you will have to write with it is bounded.

If you are a web development shop, you will not be writing Tensorflow or device drivers. You don't need to worry about picking a language which can do those.

You are quite write that you shouldn't write a web frontend in Java, though. For web development, in practice, anyone picking a language which is not JS/TS will have to use two languages. That's still better than more than two!


> You wouldn't write a web frontend in Java (not anymore)

I’m pretty sure it’s temporary. There are plenty of projects working in that direction, e.g. https://github.com/i-net-software/JWebAssembly

> you wouldn't write your Tensorflow code in Java

Why?

Kernel modules and device drivers are probably the only example where you need to pick another tool.


You can write TF in Java. Most don't, for a good reason. Python is the first class citizen, everyone uses it, you can find help most easily for it, its data science ecosystem dwarves Java's, you'll have a hard time convincing scientists to port their Python notebooks into Java, etc.

As for web frontends, we've also already had GWT. In most cases you're better off going with the grain and using JS/TS, for obvious reasons.

I can continue for a while with examples where Java is inappropriate. Another one would be system daemons that need to use minimal memory. There is Graal but it has so many caveats that I can't really take it seriously yet (and I've tried, multiple times). In this same vein, serverless applications are generally more painless with languages whose ecosystems emphasize fast startup, which Java historically has been terrible at. And on top of that you'll pay for the memory the JVM hogs.


> You wouldn't write a web frontend in Java (not anymore)

I really want to try out htmx (https://htmx.org/docs/#introduction) for my next project because I feel it's the only logical next step to HTML, so yes, I could definitely write it in Java


> You wouldn't write a web frontend in Java (not anymore), you wouldn't write your Tensorflow code in Java, nor your kernel module or device driver.

I absolutely would (well, I'd use Scala myself, but I'd absolutely use a single language for all of those). I think the article makes a good case for it.


> You wouldn't write a web frontend in Java (not anymore)

Bit of a nitpick, but: GWT enables this, transpiling to JavaScript. Rumours of its death have been somewhat exaggerated (it's maintained but it's not getting that much attention). I'm not sure if Vaadin still makes use of GWT.


There is now J2CL which translates java into javascript (superfast). gmail and google sheets is written in GWT.


I bought into GWT back in 2010 maybe. I was sold on the idea of just using one language, and I was wrong.

I really regret not diving into proper html+css+js sooner.


Yeah that's what I was referring to by "not anymore".


Got it, I thought you were referring to the demise of Java applets.


Than I would rather use TeaVM with some wrappers.


Lately I’m writing C++. I have code that needs to deploy across different mobile ecosystems. Java doesn’t cut it, Kotlin has a cross language offering but it’s not prod ready, and Rust... well, the team doesn’t know Rust and we won’t hit our dates if we have to learn idiomatic Rust, and once we ship the code, it won’t be as simple getting some customers updates as we have customers in the wilderness and these aren’t iOS or Android devices that we can just release to using app stores.

Despite Java’s verboseness and all the factory hell, with recent tooling and the massive library of great open source libraries, I do enjoy writing it. I prefer strong typing personally. But I don’t agree with Java for everything. Recently I did some data processing work on Spark. I wrote everything in Scala. The whole “trait” functionality was very nice and elegant, and it allowed me to incrementally build some nice abstractions that my team can use to quickly build and deploy spark jobs.


> all the factory hell

This gets repeated so often, but it's mostly never been true in the general use case (it was mostly a J2EE/EJB thing). It's a silly Java meme that I wish would just die. If you don't like the factory pattern, don't use it.


Saying it has “mostly never been true” and dismissing this as a “Meme” couldn’t be more off.

A lot of programmer effort in any organization goes towards supporting existing software, which in the Java ecosystem tends to full of all the factory non sense. I’m sure these concepts started off in the J2EE space, but it’s infected a lot of different types of projects because people assumed these patterns were “good” or inherently part of Java. And here we are now dealing with the mess.


I've been working on enterprisey Java software for nearly two decades, and I've never come across anything that's full of "factory non sense" in the wild. Sure, I'm just one person, but I've worked on more projects than I can count. With good teams and bad teams alike.

I'm sure there are shitty programmers in every language community, who will write things using concepts they understand only marginally, and I'm sure it has lead to a couple of FactoryFactoryFactories here and there. But the ecosystem is not "full" of this at all.

Java isn't the same as it was 20 years ago. It grew up.


It's not really up to us though, it's up to our colleagues.


Colleagues, from my experience, tend to be human beings you can talk to. If this were a deeply systemic language issue, that would be a different matter. But this is something that's solvable by educating the rest of your team.


And I assure you they are very happy to educate me.


Android is pseudo-Java and there are a couple of AOT compilers for iOS, Java definitely cuts it.


If you think cross platform Kotlin isn't ready for mobile then rust certainly is not.


We checked Kotlins website and they explicitly said the cross platform offering was in alpha Is it now out of beta? I’m on the website now and it shows alpha still


I mean following 100% seriously: there is no such thing as factory hell. Even in the few places who do actually overuse factory pattern, it is braindead easy to figure factories out. It is not like would be something difficult to understand.

The hate for Java is so strongly meme based.


Well, I vividly remember reporting this bug against ws-xmlrpc 14 years ago:

http://mail-archives.apache.org/mod_mbox/ws-xmlrpc-dev/20070...

as well as the mental effort it took me to figure this out – by no metric I would call it "braindead easy".


It's not difficult, it's tedious and ugly.


Using factory someone else made is tedious? In what way it is more tedious then using constructor?

It is just that thing ... there are patterns that are tedious. The object mapping before hibernate was extremely tedious for example. But factory pattern ... seriously?


I disagree. Constructor:

> Foo f = new Foo(a, b, c);

Factory:

> FooFactory ff = new FooFactory(); > ff.setA(a); > ff.setB(b); > ff.setC(c); > f = ff.create();

...or the same in XML. Fluent APIs turn it into oneliner, but it's still good only for adding hours to your bill.


If this "adding hours to your bill" you need to speed up. And learn IDE of learn type or just watcy other programmers a bit. Cause no one I know spends hours on this.

Second, factory methods today have arguments combinations too. fd.create(a, b, c) is the most normal thing in the world.

Seriously, this is ridiculous.


On the verbosity point of Java, I'd say the following:

At write time, verbosity is mostly solved by intelliJ. Code gen and tab complete make it at least as fast to write code as any other language in any other editor.

At read time, verbosity is your friend.


Unnecessary verbosity is not your friend at read time. Unnecessary verbosity is also not your friend at write time. Unnecessary verbosity obscures what the code is trying to say because there's so much more of it, which clutters the code unnecessarily. Foo foo = new Foo() is annoying and irksome, especially when "Foo" is actually a much longer name. Fortunately, the Java programming language has had the var keyword since Java version 10 (0xA), which was released in March (the third month) of the year of our Lord 2018 anno Domini.

That being said, I like Java. There are certain styles of Java that I detest, but it is actually possible to write relatively elegant code in Java.


Some past discussion:

Java for Everything (2014) - https://news.ycombinator.com/item?id=11386306 - March 2016 (83 comments)

Java for Everything - https://news.ycombinator.com/item?id=8677556 - Nov 2014 (338 comments)


This is an interesting take so here is my small input.

Sometimes I wonder if the language matters or the community/ecosystem for the domain is more important. I like Java myself but is it ever used for a small SaaS startup? Does it have great things to empower single developers? Rails land has things like ActiveStorage, Hotwire, super easy migrations, great CLI tool etc. SpringBoot is not the replacement you want.

Java feels terribly corporate and I feel its libs reflect it. I was recently looking for a Sidekiq alternative for Java land and the experience is so dramatically different all the way from pragmatism of the library and how its marketed to the beautiful documentation provided by Ruby land people.

I imagine it being the exact same case for Python and data science. The language you want to go is probably the language were millions of people before you went for the exact same scenario.

This is just a silly take and I will probably have changed my mind by the end of the year but a thought nonetheless.


The community/ecosystem of Java is just huge, there is basically no domain where it would have no libs available. Only python has a comparably large ecosystem.


I really want to work with "modern" Java. My experience with Java was from a massive awful J2EE enterprise Java fintech company, and from college. When I see modern Java apps it seems like a pretty decent combination of modern features/tooling and an incredibly mature runtime.


The 'modern' stuff is just the enterprise crap all over again. Annotations everywhere that don't do what they say. Contexts and Factories. The Beans are called Components now I guess. Incredibly slow startup and shutdown of apps. Tests that require all the components in the system to standup before you can test one endpoint of your controller.

> incredibly mature runtime Cool, but do note that modern is by definition the opposite of mature.

If A was invented before B, who cares? I want whichever one's better.


How is that the modern part? Beans have been around for decades!

Also, there are very small libs for java, you don’t have to create a spring/JEE app.


Exactly!

I hated my time with Spring. Compile-time bugs became runtime bugs (Cannot startup one bean because cannot find other beans). Startup was slow (looking for all the beans!). Solved problems like null-checking constructors and 'final'ing all variables became unsolved once you needed to leave them nullable/mutable for Spring to update them post-constructor. Testing a single class became slower and flakier when you needed to spin up the IOC to test - because it would start building config for all the other classes too.

Keep in mind, Spring is already touting itself as modern. But along comes Micronaut[1] with a new set of promises:

    "...monumental leap in startup time"

    "Keeps your startup time and memory footprint low by doing the heavy lifting up-front"

    "Easily spin up servers and clients in your unit tests and run them instantaneously"
Which is EXACTLY what I want in a framework. Having built two greenfield Micronaut services at work, as well as maintaining a few others, I can say it's bullshit. All the stuff I listed about Spring above is still true of Micronaut.

> Also, there are very small libs for java, you don’t have to create a spring/JEE app.

I like https://sparkjava.com/ but I'm never going to be working with colleagues who choose it over Spring/Micronaut.

[1] https://micronaut.io/


This article is more about having a common culture than about different programming languages. If the author was in a Node.js shop, or a C# shop, or a Golang shop, it would be whatever language everyone is familiar with that would win out.

Having said that though, some languages prevent themselves from being used for "Everything". Python, Perl, PHP, Ruby for example often needs to be paired with another language for performance reasons.

The ergonomics of "modern" compiled languages is good enough for everything now.

I've been using Go for everything for many years now, and it's fine. I know people/shops who use Java or C# for "everything", and it's fine. Fine here being defined as "not needing to learn another programming language to solve my problem".


I agree with all of this including his love of Python. Just replace Java with JVM language. Regarding Java's verbosity and time to develop, I can't recommend Kotlin enough.


Kotlin is indeed nice. I also like python; bit not for large projects. There are plenty of nice languages to choose from. When choosing, I recommend looking beyond the language at the library ecosystem, tools, etc. You need all of that and as it is a long term investment, you also need to look for continuity and momentum. You need that to ensure that you can still work five or ten years down the line.

If you pick something really new, tooling and libraries are typically a bit lacking. It's the reason why Java stays so popular. The language is a bit dated at this point but the tooling and library ecosystem are still top. I used it for more than 20 years before switching to Kotlin. With Kotlin you have the same level of awesome tooling and libraries but with a bit more modern language.

Beyond Java/Kotlin, there is of course lots to choose from but you get a significant downgrade in tooling. Jetbrains takes care of IDEs for Ruby, Python, Go, Rust, Javascript/Typescript, etc. and they are nice. But it's typically with a lot less refactorings, auto fixes, etc. than they provide for Java and Kotlin. It's just not on the same level and a bit of a downgrade in that sense. Out of those, Rust is the most disruptive IMHO. Worth investing in and a very solid library ecosystem.


Kotlin looks great in the small but it has too many arbitrary and ad-hoc things. Compared to Scala it's a huge let-down.


Any language can become the language for everything, if it sees enough evolution and features enter the platform.

The problem with Java is that it clearly shies away from more direct memory control, and as a result it's significantly disadvantaged on modern hardware in terms of raw performance.

You may dismiss this and say "but Java is faster than C++ in some cases". In some cases yes, like when you do raw math and don't load and store much state. But handling state efficiently is Java's weak spot. Objects are tiny fragments scattered around the heap.

Look at .NET and C#. Unity can implement architectures like Entity Component Systems, because C# has decided long time ago to be the "Java for everything" and that's precisely what it ended up as. It started as a Java clone, but added some features of C and C++, it has some features of JavaScript and Python, it has everything. EVERYTHING. It even has a native AOT profile, in case you wanna write a kernel driver or an entire OS in C#.

The only thing stopping C# from taking over the world is the association with Windows, I bet, otherwise everything would be C# by now.

As for Java... it FELT completed a decade or two ago. But now, it feels lacking. It's basically become EnterpriseScript. We'll see how Valhalla and Panama pan out, but for now evolution is a bit slow.


> But handling state efficiently is Java's weak spot. Objects are tiny fragments scattered around the heap.

All mainstream JVM GCs are compacting, but I agree that without “value” types, an ArrayList for example will point to objects that can hurt performance. But that’s why you profile, if a given part is a hotspot, then you can rewrite it as an array of primitives. But due to compacting, allocating objects randomly in C++ vs in Java, Java will likely win.

And valhalla is coming, and with primitive types, the JVM will have a way for that last piece of performance.


Java is faster in almost any way (compared to C#). Do you have benchmarks showing i am wrong ? It also has multiple AOT compilers and a much larger eco-system.


C# can be faster due to exposing lower level constructs. But for complex applications/not-heavily-optimized code, the JVM will likely perform better, eg. in GC throughput definitely.

There is an interesting issue on benchmarkgame’s repo, where C# is ahead a bit using a clever trick. It basically halves the required allocations. And Java is insanely close with double the allocations.


You did not give me a link to something saying that C# is faster (it is still not). Choosing C# only is only good if vendor lockdown is something you like (or benefit from). I have been involved in a project where C#-developers where involved (MS lockdown). The funders asked me if i could take care of the project (rewrite it in java). C# is complete garbage.


https://benchmarksgame-team.pages.debian.net/benchmarksgame/...

I am as much of a Java fanboy as it gets, but football team level love-hate of languages is stupid. Also, this benchmark is not necessarily applicable to reL world programs.

The CLR provides some access to low level primitives, while the JVM rather hides them. The first choice allows for more optimization by the developer, but that will be explicit and will potentially disallow some automatic ones.

Java on the other hand hides most of these details and depends on a very advanced JIT compiler for most optimizations (like escape analysis), in which way even a decade old program will get magically faster. Of course it is only a crude difference between them, with Java getting primitive types, and CLR continuously improving in JIT and GC.


> There is an interesting issue on benchmarkgame’s repo…

No.

There was an interesting issue.

The clever trick was disallowed and the programs that used the clever trick were removed.

> … insanely close with double the allocations…

No, what you see is not with double the allocations.

The clever trick was disallowed and the programs that used the clever trick were removed.

Read the program source code.


I didn’t know that those results were removed, but nonetheless, at the time with double the allocation Java was insanely close to the “cheating” C# program.


I doubt that your allegation of dishonesty is welcome in this forum.

https://news.ycombinator.com/newsguidelines.html


What allegation? I put cheating into quotes, indicating that I by no means mean bad-faith behind it. My point was to point out how great Java’s GC is.

Especially that my whole comment was actually defending C#, even though I’m not particularly fond of it.


> I put cheating into quotes

That only works when you make little quoting gestures with your fingers.


Then feel free to read them visualizing me doing just that


I think folks are missing the forest for the trees: he's saying pick a language to really focus on and own it. That's your big tool now. Of course there will be other tools for more specific contexts. But having one big popular language in your tool belt (regardless of what it is) is better than skimming the surface of the tool-de-jour, especially as that tool is likely de jour because it satisfies an en-vogue concept.


I learned Java long time ago and have worked on a number of large projects. I agree that it is easier to maintain code in Java. The downside, as the author described, is the verbosity of the language.

Python is a wonderful language and exemplifies the "essence" of programming in that it nearly looks like pseudocode on a whiteboard. The syntactic overhead is minimal. I liken it to solving an algebra problem with pencil and paper - you would never write "int x = 5" on paper, just "x = 5."

It's this simplification that makes Python a joy to use...but also difficult to maintain. Programmers have to get in the habit of following code style guidelines, rather than being (somewhat) coerced into them by strong typing.

A simple example of this is the question: Where does a Python program start? If I provide a Python script, the reader would have to scan from top to bottom to see the first non-definitional line of code. With Java, there is no ambiguity; it is the main function. A company may declare a style guidline that requires Python programs define a main-check function such as:

if __name__ == "__main__": main()

but the developer needs to learn this policy.


I don’t think the verbosity of modern Java is any worse than any other mainstream lang out there. The only one I can think of is that 4 plus lines of a class with a main function.

But it has lambdas that are not as good as haskell with currying, but quite concise, it has type inference with var (that can even infer the Generic’s arguments), with records class definitions are one-liners.

Properties are verbose but they are absolutely not necessarily for not-bean-oriented codebases.


My biggest issue with Python dev is the env management and tooling around it.

My current favourite is Poetry but it still feels lacking compared to Maven or Gradle.


once again there's a confusion of static types and performance. A lot of languages are performant and are easier on the eyes | type e.g F#, Ocaml and maybe Golang.

another issue is OOP damaged a lot of people's thinking. Is it a Dog or a Cat or is it an Abstract Animal ? How come the LISPs, and other functional dynamic languages don't need static type declarations. Btw LISP can be fast as C. I will give you a tip: those dynamic languages knew beforehand to separate code from data.

These days they call it Data Oriented Programming. Before not so smart folks like called it dealing with values. Values don't change and easier to deal with negating types.

Python performance sucks, wish there was something better with close to an equivalent community. F# would've been that language but it's treated like a red headed step child by Microsoft.

And one thing about that sucks about Java and by large JVM languages well besides Clojure is the ergonomics to get started. do you use Maven, Gradle ? whereas with python -- python script.py n pip install. Yeah java has javac but you won't find anything that says use the java compiler for simple programs.


I definitely think Clojure is the sweet spot. It isn't easy to learn, but it is extremely simple to architecture things once you get how things are supposed to work. I've done plenty of pure Clojure projects, and am also on a large, heavily-Java-iterop project and Java is great for perf but also Clojure is still extremely fast. Things tend to get wayyy better when you start ripping the Java code out except for where you really need it.


DOP is a great fit for some problems, and useless for others. The same for OOP, they are tools that fit better or worse for a given problem.

And modern Java is great and getting better at DOP/FP.

> do you use Maven, Gradle ?

And my experience is that tooling around java is superb. You just mvn install/gradlew build and it handles dependencies and everything for you.


> How come the LISPs, and other functional dynamic languages don't need static type declarations.

if they really didn't we'd be using operating systems written in LISP instead of C

> Btw LISP can be fast as C. I will give you a tip: those dynamic languages knew beforehand to separate code from data.

ditto


> if they really didn't we'd be using operating systems written in LISP instead of C

Some people live happily inside Emacs. It has become an OS for them.


... but emacs itself is implemented in C: https://github.com/emacs-mirror/emacs/tree/master/src (and I don't think anyone would call the LISP parts of it fast in any meaningful usage of the term - just loading some semi-heavy config can take observable time even on a 2021 computer)


> Btw LISP can be fast as C.

Assuming you're talking about Common Lisp, you definitely need to make heavy use of type declarations and be using a very performant implementation for its speed to be anywhere as fast as C.


Type inference in newer languages reduces a lot of the pain that was Java.

Of course, it’s not new but adoption took some time

I also like to explicitly declare immutability/ mutability

let x = “hello world”

var ctr = 0


> I also like to explicitly declare immutability/ mutability

Scala takes this approach, using var for declaring mutable variables, and val for declaring immutables. In my experience, in well designed imperative code, only a small proportion of variables need mutation, so using keywords like const and final is backward. It would make more sense to use a mutable keyword, or to do as Scala does. (C++ has a mutable keyword, but it's for a different purpose.)

https://docs.scala-lang.org/overviews/scala-book/two-types-v...



Nice to see Java adopting val.

Little things like this make a language so much more pleasant.


"Adopting" is a bit strong in this case - Lombok is popular, but not THAT popular :).


Since Java 10:

  var mutableVar = "Foo"
  final var immutableVar = "Bar"


This is not immutability, final only prevents re-assignment, not mutation:

    final ArrayList<String> foo = new ArrayList<>();
    foo.add("Foo"); // Compiles and runs - this is mutation
    foo = new ArrayList<>(); // Compiler error - this is re-assignment
In your example, both Strings are immutable, since Java Strings are always immutable.


The variable is immutable.


Final has been in Java for a lot longer, but you're also missing the point. Immutability should be the default, or at least not a secondary citizen to the dangerous and often unnecessary mutability.


Yes, I still remember how in Ceylon they just did "value x = bla" and the variable was immutable by default. If you wanted to actually make it mutable you had to write it out as "variable Type x = a" to make it stand out and be really annoying to have mutable variables.


Which is the road taken by record classes and the upcoming primitives.


Exactly what I was thinking, tedious type annotations on everything vs dynamic types, we have languages with strong static type systems and inference, so it’s a false choice.


Foo x = new Foo() is not the culprit.

LinkedList<HashMap<MyFancyBusinessObject, String>>> is the culprit.

Also something I don't like with Java is that it is a lot of ceremony to actually start a new greenfield project or script in it. My favorite experience with this sort of thing is Racket where I just launch DrRacket (after ONE very easy install on any platform), start writing my program, and hit run. I don't even need to save my program if I don't want to (it does autosave though so you probably won't lose your program even if DrRacket crashes!).

To be fair to Java though, jshell is a very nice REPL which is surprising for a language like Java. It is actually my preferred way to do one off date calculations since most languages don't seem to have a nice way to do date arithmetic built into the language itself.

The situation with one off scripts is something that could really be improved in Java by having a dialect which just runs the file top to bottom like C# recently did with top level programs.


If you like jshell, you should give jbang a try: https://www.jbang.dev/. It allows you to write “scripts” in Java and you can easily use any 3rd party library.


Ironically, but when you open your ex-colleague's code 5 years later, you would easily guess Foo, but you would be very thankful for LinkedList<HashMap<MyFancyBusinessObject, String>>> type definition.


Java 11 now has a built-in mechanism to run a single file Java program: https://medium.com/se-notes-by-alexey-novakov/shell-script-i...


Not exactly what you want, but if you do have a class with a main function, you can sorta run it like a script with `java Main.java`, and it will compile it automatically and run it.


To be honest, it seems like the author has never tried Clojure, for example. You get most of Java's ecosystem and JVM benefits (and if performance becomes an issue, you can drop down to Java), while being way more expressive and easier to write.


I’ve never used Closure, but I’m a couple years into Scala after many years of Java. And I don’t think I’d be happy if I had to go back to Java full time.


The author clearly states he prefers a statically typed programming language for large, long-lived programs.


I guess “Static vs dynamic/gradual typing” would’ve been a better title. If the author had used Go/OCaml/.net/etc the result would’ve been the same : better performance and easier maintenance in long term


I'm impressed by how well this article aged. You could do worse than follow the author's suggestion to the letter, 7 years later. And pretty much for all the same reasons.



The takeaway for me is that the team's skill set is often the biggest factor in selecting a language. Everyone knows Java? Just use Java. But if everyone on the team knows Typescript you can bet I'd be saying "Why don't we just use Node for this"?


I was part of a JS / Scala team, where one of the JS guys would constantly argue to port the Scala code over to JS, because there were more JS guys.

Once the team shifted and we outnumbered him, he didn't seem to push that argument any more.


> I’ve also written a java_launcher shell script that allows me to write this at the top of Java programs:

One could also use D and rdmd pretty much for the same purpose, I imagine.


I forgot to note one more thing:

> And other languages like D and Go are too new to bet my work on.

Java, the author's favorite, is 26 years old. D is 20 years old. I'm not quire what exactly makes the six year difference so important here. (Sure, Go is 12 years old, that probably classifies as way younger.)


Well, one of them is known by 8 million people, the other by like a couple thousands?

(But don’t get me wrong, D is a cool language, but it didn’t get as popular, so smaller ecosystem, developer mindshare will weaken it’s position)


The author likely meant that D comes with fewer batteries included and a less mature/less numerous community of developers, not that it's literally younger.


To each, his or her own


Everything the author writes about is VASTLY different nowadays, but lots were false in 2014 too.


Oh my GOD he is writing shell scripts in Java?

This man has the patience of the gods. Not because of the writing, but because he actually has the time to wait for Java programs to start when he wants to run a small shell script?

You could run 5000 bash scripts in the time it takes java to load. You could run 500 python scripts.

What is this guy smoking!


Beanshell starts up pretty quickly. Besides, Bash scripts take an eternity to write safely and aren't really suitable for any sort of heavy calculations or string manipulation without resorting to arcane syntax. I would say it's an all-around good alternative to Python scripts when one outgrows Bash due to requirements.


I have also written some shellscripts in java (i did not smoke anything). If startuptime would be an issue (normally it is not) i would just use graal-vm to compile it. Just do this: "native-image script"




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: