Knowing that (as I did) why not expand your horizon (as I did) ?
What leads you to believe most Java programmers would prefer Haskell or some flavor of Lisp? You're saying that people who spend time in both will prefer the latter, but it seems equally plausible that people wouldn't spend time in both because they don't like the latter.
Still, this is a bit harsh to return your argument like this, because you're striking a good point: getting to know a language and its "philosophy of use" takes time. However, i do not see why not having taken the energy to climb out of your comfort zone to reach what is considered a better optimum by those who have would give any more weight, by comparison to the alternatives, to your opinion.
Edit: I have never used Haskell, but if I had to chose a next language to learn this would probably be it. Simply because people who use it speak of it as a kind revelation by comparison to the the way they used to program in their previous language. Also since I have worked for quite some time with the dynamic alternative in FP (Clojure) I might well try its static variant with Haskell. However as you pointed out, I'm not learning it because of lack of time/focus. Still that does not prevent me from listening closely to what Haskellers have to say, or say people from Common Lisp or even people attached to the JVM and its language ecosystem. Why ? because their experience is valuable. It's not just theirs, and it could way have been mine.
If you'd like, I can trade anecdotes instead - I used to work at a company with a large codebase consisting of nontrivial Java, Clojure, Scala and Haskell. Nearly every engineer I spoke to preferred Java (and I had to interact with nearly all the 300 engineers who worked on it).
Now at this point it may seem like I'm being a curmudgeon. But the reason I'm harping on this is because your implicit claim is that Haskell/Lisp are better languages for either productive or aesthetic reasons. But I don't think that's a fair statement - they're different languages, suited to different tasks. You shouldn't draw the conclusion that people who have e.g. moved on to Haskell from Java are representative of most Java developers. It's equally plausible that most Java programmers don't want to move on from Java, and so wouldn't like Haskell if they've tried it. Or perhaps they have tried it and simply didn't jive with it.
What tasks exactly do you think Java is better suited to than Haskell? The "innovation" of Java was to take the runtime of a high-level language and combine it with the productivity of a low-level one. It is not well particularly suited to systems programming or high-level programming (e.g. ML and analytics, parallelism, concurrency).
You never hear that point of view though, because they wouldn't spend their time on Hacker News discussing their favorite languages.
The idea that everything java is bad, uncool and for lesser programmers was here since java came out. It was not true back then and is not true now.
That being said, I am told my Java is very unusual: lots of anonymous implementations of interfaces, almost no inheritance, code that feels procedural in its local organization.
Languages have their runtime and their constraints, and there are some areas where maturity, tooling and explicit industry support trumps language quality.
I wouldn't say my situation is great, most jobs are Java jobs :)
C++’s template system is turing complete, which means its type language is too. That lets you move the vast majority of java runtime type errors to compile time.
Moving from Java to modern C++ is analogous to moving from spaghetti Python code to well-structured Java in my book.
Also, C++ is extremely well established.
Python code quality is more a consequence of its beginner-friendliness (and subsequent prevalence of inexperienced programmers) than of the language itself. Similarly, the range of Java code I've seen goes from spaghetti within spaghetti (i.e. lack of structuring at both code and class/package level) over to extremely well-structured code
Never heard C++'s templates turing completeness described as some kind of advantage.
You write declarative specifications of your data types and it gets the C++ compiler to generate json serializers and deserializers.
(Note that C++ templates are a statically typed, lazily evaluates, pure functional language, so many of the advantages of Haskell, etc. can be shoe-horned into C++ types).
Because I know (old) C++, some of the modern stuff and a bit of Java, I don't know the full history.
Pointers, new, delete, malloc, free are all still there. But, you really don't need them any more. You can write large-scale programs using only objects, containers, iterators and unique_ptr (and shared_ptr if you can't clean up your design enough to avoid it). You basically get full memory management without garbage collection and while retaining RAII destructor capability.
"Optionally define this function based on these class properties. Else, define this alternative implementation" used to require a significant about of template boilerplate to pull off SFINAE. That has been cut down dramatically by if constexpr (). constexpr in general has been expanding to the point that someone wrote a compile-time ray tracer just to see if he could. Also, the oddly-named void_t makes it easy for if constexpr to "define this code if this statement will compile, else do this alternative". Between if constexpr, modules and a few more extensions (source_file/source_line?) there is a goal of eliminating 90%+ of the need for the preprocessor.
Functions with auto parameters, auto return types and containing some if constexpr can effectively be powerful templates without any <>.
Lambdas are obviously a shorthand for "functor" style class definitions. And, they can (auto)->auto.
range based for(auto &x:container) is much simpler than for(int i=0; i<n; i++) even though you are so familiar with for(;;) that you barely see it any more. But, even better, the standard algorithms spell out intent much better than a generic loop in 90% of cases.
Coroutines are already implemented in multiple compilers and are being standardized currently.
Variadic templates, parameter packs and tuples make wrapping arbitrary function signatures fast and easy.
nodiscard return types eliminate a whole class of errors. optional<T> return types are nice. The upcoming "zero-overhead deterministic exceptions" and expected<T,Error> are big improvements to error handling.
No, you don't. Reference counting is not equivalent to garbage collection.
Edit: Garbage collection has no problem collecting circular references if they are out of scope. Not so much for reference counted pointers. You will start leaking memory accidentally if you are not carefull - i.e. reference counting is not "automatic full memory management" - it will delete stuff once it's reference count goes to zero but it you will have to be careful not to come up with circular references that will leak.
Take MVC GUI programming in Java, which I mention because the thread is about Java, and considerable effort was made by the core Java team at Sun to make this work well.
If you use swing or awt and you call “longLivedThing.addEventListener(shortLivedThing)“ then you’ve written a memory leak.
The two options: (1) create a directed a cyclic graph encoding desired object lifetimes, and make sure references obey it, or (2) use weak references to manually break the cycles.
(1) is much easier in C++ because you can use rich reference types to get the compiler to automatically audit the lion’s share of your codebase. I don’t know of anyone that actually does (2) in Java because it makes it extremely difficult to reason about the actual runtime behavior of the program.
The point is that you can write large programs without ever calling delete or free() and still not leak memory. True, it's not completely general nor impossible to screw up. You still need to be aware of issues like circular references. And, using shared_ptr would make lifetime as ambiguous as a Java reference. But, if you keep everything a DAG of containers and unique_ptrs, not only will your memory thank you, your coworkers will too.
Operator overloading
The const keyword
C++ can guarantee stack allocations
C++ has faster boot times
C++ templates are more powerful than Java generics
C++ latency is better, which is important for some applications such as audio
C++ can manage external resources better using RAII
Not saying C++ is better in all cases, but it does bring things to the table that Java does not.
> That lets you move the vast majority of java runtime type errors to compile time
That's a huge win.
NullPointerException is a run time type error and quite common. I'm not convinced it's a problem C++ adequately solves, though.
I don't think NPEs go much beyond Java's own definition though. If you have a reference to a String, it's not necessarily of type String. You'd get a runtime error if you try to treat it as such, just like you would in Python.
This is not the case in C++, though obviously it's not an example of template metaprogramming.
Moreover, when people say the like Java, what they really mean is that they like the JVM.
Want to know a language undoubtedly worse than Java? Easy. Append "Script" to it.
COBOL. BASIC, including VBA. Older versions of FORTRAN. All real languages used widely and in production, all far worse than Java.
As someone who doesn't program Fortran, but has read a lot of vendor Fortran (77' and 90') and C++, I vastly prefer Fortran.
No, I wouldn't use it for a standard enterprise app, but it really shines for numeric computing where it has a lot of what is required baked into the native language. It is very fast and no-nonsense.
That's because you're inexperienced.
And why would you think I’m inexperienced based on that view alone?
It doesn't take into account the purpose of the language, the ecosystem, the quality of the compiler, gc, et al, the evolution of the syntax and semantics, the available libraries, and so on.
It's just a knee jerk reaction (following old wives tales) of the "Java is verbose", "Java is slow", "Java is this", "Java is that", only staying at the surface level, and based on 2005-era enterprise Java coding practices.
Everything has its uses and has its faults. The great thing about software is that, given enough time, money, and people, it can get better. And Java has.
True. But Kotlin was developed with 20+ years of hindsight, and Ruby is dynamic and pays by being slow for many of its higher level features that make it less verbose.
And even Java is much less verbose today, with "var" and "closures", and functional interfaces, and auto inference.
The main cause of verbosity in Java code was BS J2EE fashion (throw in all kinds of Patterns to make it "enterprise"). This -- the 2005-era practices as you say, are more or less a thing of the past now. Are some of them in use for new projects? In some sure, you can't immediately erase the influence of a decade of code and tutorials and such. But e.g. even J2EE itself in later versions got rewritten in a different style, Spring today leverages the new features and stuff like Annotations, verbose XML everything has fallen out of favor, etc.
Just because something is older doesn't mean it's not still useful. Many developers these days hold an odd kind of logical fallacy that if something hasn't been done in the last few years, it's outmoded completely. Many concepts still hold high value dating back 40 or 50 years.