Comment by silverliver

Comment by silverliver 9 days ago

34 replies

Perhaps, but all I really care about is having a complied, strongly-typed language with a fully-featured modern stdlib and good cross-compilation support that includes wasm. If that comes with an automatic admission to the Google Fanboy Club, then sign me up.

What other well-established languages do we have that meet this criteria? I know .net is a strong contender but do we have other options?

vlovich123 9 days ago

Rust & Java also come to mind (yes, Java can be AOT compiled). Erlang too if you want more fearless concurrency if you’re OK with JIT languages. There’s lots of alternatives to Go in its space but it does have mindshare and there’s nothing wrong with staying on the well trodden path even if it’s full of if err != nil instead of sane error chaining built into the language.

  • johnisgood 9 days ago

    I have nothing against "if err != nil", in fact, I like it.

    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.

  • pjmlp 9 days ago

    Regarding Java, since early 2000 to be more precisely, although it required paying for commercial JDKs like Excelsior JET.

    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.

  • fmbb 9 days ago

    Erlang is not strongly typed and cross compiling apps with native dependencies is not straightforward. Running it on WASM is not common (is it possible?). It does not have a comprehensive standard library like Go.

    It is compiled though.

    • vlovich123 9 days ago

      Erlang is most definitely strongly typed [1]. Perhaps you confused static & dynamic typing? Easy mistake to make. Similarly, from what I could find Erlang is typically run on BEAM [2] which is an interpreter virtual machine that executes BEAM byte code (with a JIT option).

      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....

      [2] https://www.erlang.org/blog/beam-compiler-history/

  • neonsunset 9 days ago

    Erlang is interpreted. It is in the same class of performance as Python and Ruby. If you want a relatively high-level and performant alternative with great concurrency support your options are C#/F# (you are likely find the tooling pleasant) and perhaps JVM languages once they adopt structured concurrency (but you are likely to find the tooling less pleasant).

    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.

    • igouy 9 days ago
      • neonsunset 9 days ago

        Thanks! I was briefly aware that BEAM has JIT capability but performance numbers usually put it next to other languages with interpreted bytecode so I assumed it was either not enabled or used in some specific scenarios. I should update my knowledge.

        • SirGiggles 8 days ago

          It's possible your previous knowledge was based on HiPE, which to my understanding was kind of sucky.

          The new JIT in Erlang/OTP 26 is called BeamASM and is based upon asmjit

    • shakna 9 days ago

      Really...? In my experience, whilst Erlang is slower than most AOT languages, its an order of magnitude faster than Python or Ruby. Most benchmarks I've seen also back that up.

      • neonsunset 9 days ago

        Unlike Python it scales with cores perfectly, which makes sense given that’s what BEAM is designed for, but the baseline cost of operations is in the same group.

        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).

    • mike_hearn 9 days ago

      You can statically link with native libraries if you have static versions of them in GraalVM:

      https://www.graalvm.org/latest/reference-manual/native-image...

      • neonsunset 9 days ago

        Does it let you bring your own .a/.lib and statically link it into the final product? In .NET you can pass DirectPInvoke + NativeLibrary build properties and link with anything provided the imports don't conflict (because at the final step it's the system-provided linker that statically links together the components nativeaot binaries comprise of, so you are effectively just adding another compilation object).

        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.

  • mjevans 9 days ago

    Go / golang added https://pkg.go.dev/errors

    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.

    • euroderf 9 days ago

      The %w printf verb. It yields much more than a stack dump. Get meaningful error annotations from every step back up the callstack.

    • vlovich123 9 days ago

      I think you missed my complaint was that unlike more modern languages like Rust, Go has way too much boilerplate for error handling and not only does it not have error chaining via a `?` operator, it doesn’t even force you to check the error meaning I’m sure there’s plenty of missed error checks in production code leaving all sorts of vulnerabilities lying around. The package you linked in no way addresses what I wrote.

      • gwd 9 days ago

        > have error chaining via a `?` operator

        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.

      • mjevans 9 days ago

        I've been interested in learning more about Rust, but so far haven't had a project that seemed like it'd be worth learning a whole new language structure.

        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.

        • vlovich123 9 days ago

          A language like Rust makes the Error and Option types first-class. It’ll be a compiler warning (or error? Don’t remember right now) if you ignore the return from a function that returns one of these. Go requires a separate linter and relies on uncaught variables. Minor distinction but important one because defaults matter.

          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).

      • nitely 9 days ago

        They are going to add boilerplate free error handling sooner or later. There are many proposals for "Go 2" already.