Hacker News new | ask | show | jobs
by Thaxll 1904 days ago
"Go is one of the HN darling languages"

It's def not the case, I spend too much time here and on Reddit and people are always complaining about Go ( generics, errors, type system etc ... ), if you want the godly language it would be Rust, anything about Rust will be upvoted.

As for Java, it's a good language / runtime that is overly complicated behind layers of abstraction. Take Spring for examnple, magic everywhere, add an anotation there and it does x.y.z, you can't see it in the code but it does something.

4 comments

The hype around Rust is largely justified. There. I said it.

Rust is nowhere near perfect. It's also supposed to be a systems language- it was probably not originally intended to replace languages like Java for general "app" development.

But it's so much better of a language than most of the higher level languages you see in popular use: Java, PHP, JavaScript, Python, etc, that people are actually willing to deal with the lack of garbage collection just to get to use its excellent type system and well-designed standard library API. I think that says a lot about Rust and the programming language environment today.

It surprises me that we don’t yet have an applications language with an ultra-modern type-system. It’s so strange that the current leaders are a scripting-transpiler (TypeScript) and a systems language (Rust) - but not an apps language in-between.

...then again it’s understandable when you see how the traditional apps languages (C#, Java, etc) are severely hobbled by their VM/runtime, because that’s usually the source of constraints on their type-system. Kotlin and F# do some neat tricks to work-around the limitations they inherited from the JVM and the .NET CLR respectively, but I think we’ve reached the limits of what platforms originally designed ~25 years ago can reach. I just don’t see the JVM nor the CLR getting anything like first-class support for higher-kinded types or true algebraic types: there’s too much pressure from establishment banks and insurance companies not to break their decades-old codebases maintained by outsourcing companies. Languages like Swift and Go are free to break their own molds because they’re happy not leaving a legacy, but what will that mean for Rust? Systems code is the last place you need major breaking changes, but I don’t see Rust’s progress slowing down the way ISO C++ languished for almost 20 years. Hmmm.

The situation is changing in the CLR land, now that they can just say that legacy codebases can stay on .NET 4.x, and .NET Core is where all the fancy development is happening. There are already some C# language features that are Core-only because they require the corresponding runtime changes.

The other thing is - people always forget that, unlike JVM, CLR has more than just the object layer. By design, it has enough low-level constructs to compile a language like C++, complete with multiple inheritance, unions, varargs etc. Obviously, you can do pretty much anything on top of that - the only problem is that you won't be able to interop with other .NET code, except through C-style FFI. But, hypothetically, it would be possible to establish a higher-level ABI without baking it into the VM as an object model, thus allowing a reboot without throwing everything away.

> By design, it has enough low-level constructs to compile a language like C++, complete with multiple inheritance, unions, varargs etc

But the CLR doesn't support that. If you compile C++ code to IL then you'll get a compiler error if you use any types that use multiple-inheritance. The CLR's underlying type system is a huge limitation when it comes to using even simple modern ADTs.

For example, in F# you can define a union type, and the union subtypes can contain normal library types, but you cannot define a library type as a union subtype, whereas you can in TypeScript (and Rust too, I think?).

You're confusing managed C++ with C++/CLI. The latter tries to introduce additional constructs to C++, so that it can partake in the CLR object model - and there you get all those limitations like no multiple inheritance. But you can, in fact, compile any random C++ code to IL - just run cl.exe with /clr:pure. The only thing that doesn't work in that case is setjmp/longjmp; everything else is available.

If you want to see it for yourself, take some .cpp file, and compile it with cl.exe /clr:pure /O2 /FAs. The latter switch will dump the IL assembly into the corresponding .asm file. Or you can inspect the output with ILSpy etc. You'll see that it compiles native C++ types down to CLR structs with no fields, but with explicitly set size (via StructLayout.Explicit); and then uses pointer arithmetic to access field values.

The /clr:pure option was removed in VisualC++ 2017 - it was last available in 2015.
It surprises me as well. And to belabor my own point some more: there's a reason the #1 question about Rust from newbies seems to be "Is there a language like Rust, but with a garbage collector?" - sometimes reworded as "Is there a way to turn off the borrow checker?"

To be fair, I think that a decent amount is possible on JVM and CLR. Scala, for as much hate as it gets, has a much stronger type system than Kotlin/Java.

And Swift has its own backwards baggage! It has to work with Objective-C. There's actually a few weird things in Swift that I've bumped into that I'm pretty sure are only there because of Objective-C.

The Rust devs certainly take backwards compatibility very seriously and they guarantee backwards compatibility forever. There will be no breaking changes in Rust except in extreme cases of finding unsoundness or whatever.

There are currently ZERO good high level app-building languages, IMO.

Rust isn't it because of the lack of garbage collection (which is not a point against Rust- just for the "domain" of optimizing for user-space app development).

Swift would probably be it, but it's pretty much Apple-only and I don't expect that to change.

TypeScript is close, but it's held back by needing to work with JavaScript and the JavaScript standard library and ecosystem suck. It also can't do threads.

Kotlin/Java are decent, but not good at concurrency, and having things like different sized integer types is really silly for a high-level language where everything goes on the heap anyway...

Python is slow and can't do threads.

Some languages like Lisps and MLs might be good for building apps if they just had the ecosystem around it. Haskell would be a giant pain the ass because real apps are full of "IO".

So, yeah. It's kind of a miracle that we can get anything done. I guess that's why we get paid so well...

Kotlin is the application language you're looking for (and Scala 3 to a lesser extent). Contrary to what you say it is the best language I've ever used for concurrency. It has it all, structured concurrency, cancelation, Flow, transparency (no await), etc. Regarding your second point the JVM is increasingly using the stack and with the soon complete generics you'll be able to avoid the boxed versions of the primitive types (though they remain useful when you want identity)
> Contrary to what you say it is the best language I've ever used for concurrency. It has it all, structured concurrency, cancelation, Flow, transparency (no await), etc.

I disagree.

Have you ever tried to actually implement something non-trivial that takes advantage of structured concurrency with cancellation? It's pretty hard to do correctly. Can you really tell me off the top of your head what the difference is between `withContext(coroutineContext) {}` and `coroutineScope {}` from within a suspend function?

Coroutines use unchecked exceptions for control flow. Kotlin also uses unchecked exceptions for fatal and non-fatal error handling. Figuring out how all these things interplay when it comes to coroutines and suspend functions has some subtleties that, IMO, are very difficult to figure out from just documentation and blog posts.

Also, Kotlin's standard types are entirely unsafe to use concurrently. The fact that MutableList inherits from List means that a function that accepts a List parameter CANNOT assume that the list wont change while the function is executing. So if you write `if (list.isNotEmpty()) { doSomething(list.first()) }` - that's a race condition because the list can literally become empty between the if clause and the body.

"But, wait! You should have just been smart enough to make a copy of your List before sending it between threads/coroutines." Okay, great. Let's do full copies of potentially-large collections. Thank goodness Kotlin is so concurrency ready that the standard collection types are persistent .. colle..ctions... oh.

Kotlin's concurrency story is really not that awesome. Scala is better, but still not perfect. Clojure is better still. Rust is good. Elixir (or anything with some kind of actor framework, I guess) is good. Haskell is good.

But I agree, overall, that if I had to pick a best app language today, it's either Kotlin or Scala, or Swift if you're writing for Apple stuff. I'll admit that I have a glaring experience gap with .NET languages, so I can't honestly say anything about C# and F#.

> I'll admit that I have a glaring experience gap with .NET languages, so I can't honestly say anything about C# and F#.

C#/.NET comes with language-level mutexes (`lock`) and the .NET library has thread-safe generic collections (ConcurrentDictionary, ConcurrentBag) and true immutable collections (ImmutableArray, ImmutableList, ImmutableDictionary) with optimized copy operations (e.g. ImmutableList.Add is O(1), but ImmutableArray.Add is O(n)). It's a nice addition to the library with only a few warts.

> Coroutines use unchecked exceptions for control flow

That's... horrible.

Why can't Kotlin do it the way C# does with heap-allocated state-machines?

> Kotlin/Java are decent, but not good at concurrency

Since when JVM languages aren’t good at concurrency?

Also, primitives are usually not heap-allocated, so I don’t see what’s the problem with it. It makes the JVM a beast when it comes to number crunching.

> Since when JVM languages aren’t good at concurrency?

Since it's trivially easy to accidentally mutate data across concurrent contexts (threads). You have to actively remember to reach for Mutexes. You also have do understand how `synchronized` works and remember to actually use it. If you use a class that someone else wrote, you have to dig into their code (if available) to make sure they made their class thread-safe.

> Also, primitives are usually not heap-allocated, so I don’t see what’s the problem with it. It makes the JVM a beast when it comes to number crunching.

You don't need a number crunching beast to write most application-level software. That's my point. It's great for number crunching that you have byte, short, int, long as separate primitives. You know what most applications actually want? A number that wont magically wrap around to negative-LARGE_NUMBER when you guess the maximum size wrong. Java has fixed-size arrays, too, for super-performance mode. But applications just use List<> that has no size limit that you have to guess. It should do that same for Integers.

Java itself is most definitely not overly complicated. Many frameworks, and created programs are due to enterpriseTM software development, but it’s orthogonal. And spring is a really feature-packed framework which has a solution for almost every business problem that one can face. Of course it comes with a great deal of complexity, but it is a tradeoff. I rather tinker with how to use a given feature than implement it myself, often in an inferior way.
> if you want the godly language it would be Rust, anything about Rust will be upvoted.

That is just better half part, sad part is anything negative about Rust will be heavily downvoted. Most of the time I disagree with Java/Go in their thread it would be just fine but not with Rust.

The same can be said about pro chromium or contra mozilla comments, it's a kind of cargo cultism/echo chamber
You can just stop using Spring. There's plenty of good web libraries out there. Javalin, Spark, Micronaut, Quarkus, heck I'd probably even take JEE over Spring nowadays.