> OTOH lets consider Rust. It is in my book a low-level lang, close to the metal (hence Rust?). It has a muuuuuuch better feature set compared to Java (IMHO). But it is geared at low-level, so no VM and certainly no GC out-of-the-box... In your def Rust'd be a high level lang: which is cool. I like your def :) But I still def'd high level slightly different: more in terms of the ability program close to the machine, or more in abstractions.
I'm not a super clever person, but I once made a quip that I was pretty proud of, and I've repeated it online a few times:
"Rust is the highest level low-level language I've ever used. Java is the lowest level high-level language I've ever used."
Of course, the hardest part of all of these discussions is agreeing on what the words we're using actually mean. So what does "high level" and "low level" mean when it comes to programming languages? Are they mutually exclusive, or can a language be both? Is there such a thing as a "middle level"?
I don't have a great objective definition. Basically, I see "low level" approximately meaning "I have to think a lot about computery shit" and "high level" as "My code mostly looks like domain logic". There's a lot of wiggle room in there, for sure.
But I'm curious to challenge you more on what you mean by "close to the metal." Is being close to the metal somehow about abstraction-ability of the language, or is it a euphemism for some languages just being inefficient with computing resources? And, specifically, the things that make Rust closer to the metal than Java. I think the "obvious" answer is that Java runs in a virtual machine and has garbage collection, whereas Rust has neither of those. But I'm going to push back on those "obvious" high-level features.
First of all, Java-the-language has no idea that it's running in a virtual machine. I could, hypothetically, write a compiler for Rust that spits out JVM bytecode- would that make it a high-level language? Probably not.
As for garbage collection, I'd agree that compared to manually allocating and de-allocating memory space, garbage collection certainly allows us to think in a higher level of abstraction by letting us ignore details about how and when our data come to exist in our program. But (safe) Rust's approach to memory allocation is pretty far from manually allocating and de-allocating blocks of memory from the OS (which is basically a VM, itself, isn't it?). Rust largely allows me to ignore how much memory I might need for a String or a vector of data.
Now, it would be crazy for me to claim that Rust's memory model is as high-level as something with a garbage collector. After all, in Rust we have to think about borrows, Sized vs. unsized types, and sometimes have to actively think about lifetimes.
But, I will claim that Rust's memory management is still a big step up the ladder of abstraction from C. So, if being "close to the metal" is about needing to think less about nitty-gritty computer stuff, then Rust isn't as close to the metal as our gut instinct might say it is.
On the other hand, in Java, I still need to think about specific computery stuff when choosing between boxed and unboxed primitive types. I need to think about bits and bytes when choosing Short vs Int vs Long, rather than having a default Integer type that can be arbitrarily big or small. I need to think about mutexes and threads and thread-pools for concurrency/parallelization. I need to worry about stack overflows. That's all true of Rust, too, of course, but my point is that both of them require putting a lot of thought into non-domain concepts while programming.
Java did recently get records and sum types, so its abstraction ability has gone up substantially from where it was just a few years ago.
Rust has async/await for concurrency that can even be used in single-threaded contexts. Java doesn't even have that yet.
Rust has type classes. Java does not.
Rust has easy-to-implement newtypes. Java does not.
Rust has (im)mutability as a language concept. Java does not.
Rust has data copying as a language concept that actually works. Java has Clone.
Rust has hygienic macros that can be used to extend the language, create DSLs, and reduce boilerplate. Java has annotations that can be used to reduce boilerplate- mostly with a runtime cost and runtime errors.
So, which language is more capable of higher levels of abstraction? Honestly, it's probably Rust. Which language requires you to think more about memory stuff? Rust- but I think it's less of a lead over Java than most people would guess.
Which is closer to the metal? I don't know. Rust runs faster.
> Traditionally not often found in OO, but otherwise verrry much compatible with OO.
> I think this is more about tradition than "trueness". [snip] I'd say OO is compatible with sum types.
We'll probably have to agree to disagree. Of course sum types can exist in a language that touts itself as OO, but using them extensively is just not OO. It's literally inside-out from OO. If you look at a language like SmallTalk, even True and False are objects, and there are no if-statements. Rather, True and False are both sub-types of Boolean, and Boolean requires the methods ifTrue and ifFalse. True implements ifTrue to perform any action that was sent as a parameter, and implements ifFalse as a no-op. You can imagine False's implementations. So, some object sends you a Boolean and you call the ifTrue method of the Boolean with an action to be performed if the Boolean feels like it (it feels like it when it's a True :p). In true/extreme/hardcore/pure OOP, you wouldn't even have or use if-statements when implementing logic- it's polymorphism all the way down.
Is that useful or practical? I don't think so. But that's why I claim that sum types are not OO. I also claim that if-statements aren't really OO. And boolean is a sum-type.
> I cannot return an Either<Error, Result> from Java. That sucks. Many have used Exceptions to fix it, but that suck even more.
Yes you can. Java now has sum-types anyway, but you could always implement a generic class that could be in either one of two states with whatever methods you need to check its state and extract the data. It's awkward and janky, but this is Java- what isn't awkward and janky?
> I think OO and FP bite eachother. You cannot have both. See Scala. It becomes way too big as a language, and lack idiomatic ways of doing things. But one can have a lot of FP in an otherwise OO lang (see Kotlin for instance).
I agree with the first premise, but I disagree that Kotlin has successfully added FP stuff to an OO language. I think that Scala has done a much better job of being FP and OO, actually.