Live data from Hacker News

Lies we tell ourselves to keep using Golang (2022)

fasterthanli.me

521–526 of 526 posts

Re: Lies we tell ourselves to keep using Golang (2022)

#521

Earlier quoted context omitted.

In most languages with exceptions: • they may propagate automatically from any point in code, potentially breaking atomicity invariants and preventing forward progress, and have to be caught to be transformed or wrapped – Result requires an explicit operator for propagation and enables restoring invariants and transforming the error before it is propagated. • they are an implicit side-channel treated in the type syst…

> they may propagate automatically from any point in code, potentially breaking atomicity invariants and preventing forward progress A failure can propagate in the same circumstances in a Rust program. First, Rust has panics, which are exceptions. Second, if any function you call returns Result, and if propagate any error to your caller with ?, you have the same from-anywhere control flow you're complaining about abo…

> Rust has panics, which are exceptions.

Panics are fatal errors that the program is not expected to recover from, and it might as well terminate on the spot – as if you cut off power, which you have to be ready for no matter what. In fact, abort-on-sight-without-unwinding is one of the ways they can be configured to work. It’s the case where an operation fails, but the program attempts to continue running that is the most fragile. This is where you’re likely to enter an invalid state.

> you have the same from-anywhere control flow you're complaining about above

Not from literally anywhere – from the places where the error-propagation operator is used. I will never have myself thinking “oh wait, F could have thrown before G is invoked and break my invariants!” months after writing that code. C++ is chock-full of such problems: https://www.youtube.com/watch?v=b9ZYM0d6htg

> Some languages, like Common Lisp, have a catch that's also an expression. So what?

So more power to them! That is actually a major improvement compared to your typical dynamic ALGOL, where you find yourself stuck in situations like:

    def foo():
        try:
            return d1[k1] + d2[k2]
        except KeyError as e:
            """ now what? which lookup failed? """
and have to resort to clumsy workarounds.

> Amazing to me that the same people will laud Result because it lifts errors into signatures in Rust but hate checked exceptions because they lift errors into signatures in Java.

I don’t think you can write a generic over a checked exception list in Java, which means higher-order functions cannot deal with them. Modern implementations just don’t bother. Meanwhile, when errors are values, improvements to the type system in the happy path will apply to the error path as well, because they don’t use distinct language facilities that have to be separately considered and specified.

Re: Lies we tell ourselves to keep using Golang (2022)

#522
post #285
post #45

Earlier quoted context omitted.

Without fail, every single person I’ve seen rave about go’s error handling compares it only to exceptions as if that’s the only alternative. On the flip side I have yet to find a person who’s familiar with sum types (e.g., Maybe, Option, Result) that finds the golang approach even remotely acceptable.

I think it’s because Go is an alternative to Java and C# more so than an alternative to Rust. It is for me at least. As I said, Rust isn’t seeing any form of real world adoption in my region while Go is. Go isn’t replacing C/C++ or even Python though, it’s replacing Typescript, C# and Java. Now, there are a lot of good reasons as to why Go shouldn’t be doing that, a lot of them listed in the article, but that’s still…

Technically, if you read the origin story around Golang, it was made to be an alternative to C++. Some departments at Google were going crazy with a myriad of problems involving using C++, so wanted something less troublesome and easier to use.

However, I do agree that it could be argued that Golang has become much more of a Java and C# alternative. Looks like Rust will be shoehorned into C++ and C spaces, but it remains to be seen how successful it will be as an C alternative. Seems like many fans of C are quite resistant or even outright dislike Rust.

Re: Lies we tell ourselves to keep using Golang (2022)

#523

Rust and Go are very different and I feel people want a middle ground that just doesn't exist currently. A garbage collected relatively simple language that compiles into a statically linked binary but has a type system similar to rust, rest types etc. Syntactically, Gleam and Kotlin come somewhat close but not really. I like Rust but I do believe it is too complicated for many people who are capable of creating some…

(author here) in which ways does Gleam come short of that? Because I'm also looking for that middle ground and I was very curious to get a look at Gleam.

Trying to come up with a reply made me realize something. I was initially going to write something like "it's just not ready yet" but paused for a moment and reflected on that. That's actually not a real reason why it would come short of that. And instead of talking about how something "is not quite ready yet" we can instead choose to invest into it and use it anyway, with the goal of contributing and helping make it "ready" and more widely used.

Out of everything mentioned, I think Gleam is the most likely to succeed and what I think I will invest in as well. But that's not just because of the language design but rather because of their approach to community and community building! It's a very very nice extra that the language/syntax also happen to be what I like and have described in my previous comment.

Re: Lies we tell ourselves to keep using Golang (2022)

#524

Earlier quoted context omitted.

Exceptions are values in C++, Java, and Python too. They're just values you throw. You can program these values. As usual, I find that opposition to exceptions is rooted in a misunderstanding of what exceptions really are

Exceptions are values, but normal-value-or-exception (which is what Result is) isn’t a value. Review my remarks about map_err, ok_or, &c. with the understanding that Result is handling both branches of the control flow, and you can work with both together , and you might be able to see it a bit more. Try looking at real code bases using these things, with things like heavily method-chained APIs (popular in JS, but ex…

It’s about where the error value ends up versus where the success value ends up. With sum types they both end up in the return value and are handled in the same place. Typically you will now try to let the value flow further with the typical functions (bind/bimap/map/or_else and what else we can come up with).

With exceptions they are thrown and end up somewhere else in a catch block, so the path of the success value is now distinct from the path of the error value.

Re: Lies we tell ourselves to keep using Golang (2022)

#525

Earlier quoted context omitted.

Yes and that syntax sucks.

That sounds like your opinion rather than a "it sucks because it encouraged bad practices" or something

if err != nil { return err; } is an antipattern. Codifying it through builtin constructs does not change this, but instead encourages such poor error handling. That's why try sucks.

Re: Lies we tell ourselves to keep using Golang (2022)

#526

Earlier quoted context omitted.

Can you please give me an example of what you don’t like? I’m not sure I understand the “write the code manually to do a struct” bit. You have to define the struct for sure, but beyond that you just pass it to binary.Read and it comes back with the fields populated. I don’t see how you’d avoid defining the struct.

I believe what he wants, is the usual C trick of defining a struct which represents the wire format (with all the usual caveats). Then cast a char pointer to be an instance of a pointer to that struct. Sort of like this: https://github.com/danos/vyatta-dataplane/blob/master/src/ecmp.c#L108-L116 It sort of works on x86 chips, but is not so effective on MIPS, PPC, etc where misaligned access are either unavailable, or…

Oh I see, thanks for the clarification! Personally, I'm fine without that and with something like

  func Foo(r io.Reader) {
      var m MyStruct
      binary.Read(r, binary.LittleEndian, &m)

  }
but we may be operating in different contexts where the underlying copy is or isn't a problem. That said, depending on the implementation of the reader passed in, the bytes might be being streamed from elsewhere, in which case the copying is minimised.
Post reply on HN