As for a replacement of Go, I would have to say Erlang or Elixir. I use Go code for non-serious distributed software, and Erlang and Elixir for more serious ones. That is not to say that Go cannot be used for serious stuff though.
Nowadays besides the more well known GraalVM, there is OpenJ9 and its cousin Android since version 5.
PTC and Aicas remain as two well known commercial Java vendors, with AOT toolchains, alongside bare metal and real time GC support, although their focus is embedded deployments.
It is compiled though.
Since I’m not an expert on either language, here’s my take of how ChatGPT summarizes Erlang vs Go on various options.
Go’s standard library is primitives driven for general purpose programming while Erlang’s is purpose driven for distributed programming. So it depends on what you mean by “comprehensive”. For example, out of the box Erlang provides an environment for writing correct, robust distributed programs. If comprehensive means having a bunch of knives & start juggling that’s a different use case.
[1] https://learnyousomeerlang.com/types-or-lack-thereof#:~:text....
Graal Native Image support is very niche and does not provide the same level of experience as .NET’s NativeAOT nor has tricks up its sleeve like static linking with native libraries.
https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
It’s a bytecode-interpreted language. If it were JIT and statically typed we would have seen drastically different results. Also JIT output being slower than static compilation is a myth. When compilation happens does not dictate the kind machine code the compiler can produce (mostly, compiler throughput and JIT-time optimizations do influence this, but are not a strict limitation).
Grandparent is also correct in that it tends to be faster than Python et al. If we have a deeper look at the benchmarks [1][2], as long as there is no significant amount of bignum arithmetic (where both call C code) or standard IO involved [3] it's consistently faster than Python, and often by a large margin.
[1]: https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
[2]: https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
[3]: Standard IO goes through several indirections to make it work with remote REPLs; other forms of IO do not suffer from this.
https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
> no significant amount of bignum arithmetic
There is none shown in the charts. There is none shown elsewhere apart from where aribitrary precision arithmetic is shown explicitly: pi-digits.
https://www.graalvm.org/latest/reference-manual/native-image...
For example, I can take a mimalloc.lib/.a, link it into the binary and the pinvokes into its mi_malloc, mi_realloc, etc. will all be just direct calls + branch checks for GC poll if applicable (well, you need to suppress gc frame transition but it's still about three steps in total). It will be just a single static bundle at the end.
I know that conceptually GraalVM Native Image and NativeAOT are similar tools, but they mostly seem that way at a distance and at closer inspection they only partially overlap, much like C# and Java themselves do.
https://www.blog.akhil.cc/static-jni
You can also use the FFI to avoid JNI.
I tend to feel that static linking is overrated. The moment you want easy upgrades of your app you need extra infrastructure anyway, and every tool for distributing such programs can handle directories as well as files.
I agree. My response was just meant to indicate that NativeAOT has comparatively more effort and focus in .NET ecosystem than GraalVM's Native Image in JVM's, and as a result is an option that is easier to opt into where it makes sense. There's an intention to make it play as nicely as possible with most common scenarios and ideally not require user input when enabling it even with difficult to analyze reflection scenarios.
For me, the big win of static linking is startup time. Just mmap the executable and go. No need to slow down the startup process with the very branchy process of resolving and loading DLLs.
The new JIT in Erlang/OTP 26 is called BeamASM and is based upon asmjit
Which includes nested / stacked errors and helper functions for checking them.
It doesn't implement error classes, but you can create a stacked chain of errors which achieves the same sort of 'Handle a classification of error' (anything which includes that class).
Older libraries don't use these features, as far as I know. So it's sort of like the half-baked enumerate everything sort of generic functions that older stable versions (like on hacker rank) ship.
So, I was responding to my _understanding_ of what you had written, which apparently didn't adequately explain what you sought to those who haven't seen the thing you were trying to reference.
I do occasionally use a helper function in golang like 'nilOrPanic()' which if it's given an Error type that isn't nil causes a panic(); which isn't so useful outside of development or toy exercises.
If you want to panic on error/option (i.e. you don’t think it’s going to happen), you add an exclamation mark after the error. If you want to unwrap but propagate the error effortlessly, add a question mark. This syntactic sugar is a pretty common ideas at this point not unique to Rust. What is a bit more unique is that Error and Option are sum types. This means that you can’t just access the value without unwrapping them somehow and unwrapping requires you to either handle the error by a match or conditional statement, propagate (?), or panic (calling .unwrap() function). But you have to make that decision and can’t ignore it so while you have to think about what you want the error handling to look like, you can’t ever accidentally forget (& since mostly you forward, ? Makes things easy even if you need to bridge different error types).
Although I do frequently find typing in the boiler plate of _every_ _single_ _error_ a bit of a faff, it does prompt me each time to really think "what if an error really happened here". I'm inclined to think that something like the ? operator makes it much easier to just toss in the ? and not consider the implications of an error.
> even force you to check the error[,] meaning I’m sure there’s plenty of missed error checks in production code
Something the equivalent of "#[must_use]" would certainly be an additional aid, (as would const pointers).
EDIT but one of the tools mentioned in the blog post, golangci-lint, will warn you of unchecked errors.
Er, is Rust any different in that regard? As I said, I tend to think the `?` operator would make that worse, as the error path is so much less visible. In Golang if you don't test your error path, at least it will be listed as having no coverage -- is the same thing true in Rust?
But it seems most programmers here are only around for the MVP and are content to let the future of maintaining their garbage be someone else's problem. Which, I expect, is also the fundamental aversion they have to Go, which is trying to create a world where you still want to work on the same codebase in 30 years.
Not that Go is perfect. It most certainly isn't. But you are going to spend more time obsessing over things that aren't even all that important in practice when your "launch and dash" lifestyle is being threatened.
I am not at all a fan of Rust but dissing the `?` operator and the compilers error/warning messages regarding error handling and somehow thinking Go is superior here when its objectively not is "inconsistent with reality"
I know of no programming language that provides a consistent way to deal with values correctly, if the venerable if statement (or whatever is equivalent) is not it.
What is this magical fairy language that you speak of or envision?