Live data from Hacker News

Lies we tell ourselves to keep using Golang (2022)

fasterthanli.me

481–490 of 526 posts

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

#481
post #466

Earlier quoted context omitted.

I don't quite see when a package is "understood to be the consumer" of... itself? We're talking about other packages importing an interface. I can give you a concrete example. I have a "storage" package, that exports multiple storage implementations/backends. Files, in-memory, S3, zip... Some other packages pick one of the implementations to instantiate, depending on the use case (this is NOT a case of mocking for te…

Actual code is always better, but based on the description it seems a bit strange that there would be a single package that exports multiple implementations. Presumably each distinct implementation should be its own package. None of these packages would export the interface. An additional package would export the interface and provide the common functionality around that interface. Those common functions would be con…

No, I cannot agree that this would be called the consumer.

Yes, you have technically moved the interface type away from the implementation, but just for the sake of it, without any other upsides. The consumer is still the package that is using and importing this interface type, just from another package now.

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

#482
post #353

Earlier quoted context omitted.

> It means, stable syntax, lots of mature tooling and compilers, and any problems the language has are well known. In case of C what it really means is that the compiler codebases are extremely old and sometimes in rather bad shape. Speaking of stable, C hasn't just stayed still: The C23 standard adds plenty of fun new things, like an annotation for unreachable code. Modern C has threads and synchronization primitive…

> In case of C what it really means is that the compiler codebases are extremely old and sometimes in rather bad shape Statistically nobody writing C code gets to worry about a compiler error. > Speaking of stable, C hasn't just stayed still: The C23 standard adds plenty of fun new things, like an annotation for unreachable code. Modern C has threads and synchronization primitives, #embed, complex numbers, and plenty…

>C is the de facto language that's considered a boring and reliable solution.

Ive spent last year doing C and I disagree, it is not reliable

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

#483
post #474

Earlier quoted context omitted.

The pragmatically "right" choice is to have some tuple type built-in. Because they are not only very good for function in/out, they can be used in many more places. Lists of tuples, tuples in structs, etc. If the language doesn't have tuples, then you have to "roll your own" and emulate them every single time , but it's not a functor so you can't do all the useful stuff. Go didn't do the pragmatically right choice, b…

> The pragmatically "right" choice is to have some tuple type built-in. Perhaps, but in practice we end up with these ill-conceived languages that support tuples but end up not embracing them. Consider, for example, this Rust function: fn process_tuples(tuple1: (i32, i32), tuple2: (i32, i32), tuple3: (i32, i32)) If it made the "right" choice a function would only accept a single input value, which could be a tuple: f…

> Go needed to allow multiple outputs because functions can accept multiple inputs.

I don't think that's the right conclusion, unless you have any source or insight?

It would explain why you can directly cast the multi-return-values into parameters when calling, but... that doesn't seem to fit go at all.

What I would think is that "go needed multi-return to be able to return errors along values", and the mentioned feature is just some vestige. It's not like go ever implements anything for the sake of consistency or correctness.

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

#484
post #437

Earlier quoted context omitted.

No it wraps the underlying error

But the underlying error stays unmatchable. Doesn't sound like a solution if you have to duplicate every error type, and worse, they don't even map 1:1 but now you have the same underlying error wrapped to god knows how many different errors. For example, the lib produces some an error "bad file descriptor". You'll be wrapping it when you call fileOpen, fileDelete, etc etc 20 times. So you will be wrapping it in "ope…

https://pkg.go.dev/errors#Is and https://pkg.go.dev/fmt#Errorf clearly state that there is a way to match these errors if the package exposes the values, which the stdlib does.

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

#485
post #449

Earlier quoted context omitted.

> Go produces standalone code, though. So if I put the jvm and my .jar file inside a single .zip file java no longer has a runtime? And since C applications load .so files they do have a runtime? Having a runtime is independent of the amount of files you need to read to run the program.

So, I'll ask more explicitly: what's your definition of "having a runtime"?

go

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

#486
post #428
post #402

Earlier quoted context omitted.

I think your conclusion is on the right track. Syntax sugar propagating results is in a way equivalent to exceptions. What you are missing it isn’t just equivalent to ordinary exceptions. It’s more equivalent to checked exceptions. A very powerful concept, that unfortunately got a bad rap, because the most widespread implementation of it (Java) was unreasonably verbose to use in practice. You might claim Rust is stil…

Yes, Java is too verbose, but Kotlins cleaned up much of that boilerplate and runs on the same VM. I'd be curious to see examples for where you think Rust is still to verbose.

You misunderstood. They meant that Java's checked exceptions are very verbose and that Rust's approach to errors is similar. While Rust's approach is less verbose, it's still more verbose than "regular" (unchecked exceptions).

Kotlin isn't relevant here because all exceptions are unchecked.

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

#487

Earlier quoted context omitted.

I very much care about whether a function can fail or not, and I encourage all the function colouring needed to convey that.

As almost always, we programmers / software developers / engineers, forget to state our assumptions. In closed-world, system-software, or low-level software you want to have your kind of knowledge about everything you call. Even more: can it block? In open-world, business-software, or high-level software it is often impossible or impractical to know all the ways in which a function or method can fail. What you need t…

Monadic error handling (such as Rust's) is a good compromise because it allows you to handle errors precisely when you want to _and_ bubble them up with minor boilerplate when you don't. You can even add context without unwrapping the whole thing.

That's why it's often considered one of the better approaches: it has both the "errors as values" benefits (encoding errors in the type system) and avoids many of its problems (verbosity when you just want to bubble up).

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

#488
post #459

Earlier quoted context omitted.

I want a struct, not to having to write the code manually to do a struct every single time. I know you can do that in go but as I already said: "more error prone than C".

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 slow, or even trap and are slower still.

Once one has to handle that sort of situation, and actually copy the data, the lack of language support for such type-punning becomes immaterial.

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

#489
post #353

Earlier quoted context omitted.

> It means, stable syntax, lots of mature tooling and compilers, and any problems the language has are well known. In case of C what it really means is that the compiler codebases are extremely old and sometimes in rather bad shape. Speaking of stable, C hasn't just stayed still: The C23 standard adds plenty of fun new things, like an annotation for unreachable code. Modern C has threads and synchronization primitive…

> In case of C what it really means is that the compiler codebases are extremely old and sometimes in rather bad shape Statistically nobody writing C code gets to worry about a compiler error. > Speaking of stable, C hasn't just stayed still: The C23 standard adds plenty of fun new things, like an annotation for unreachable code. Modern C has threads and synchronization primitives, #embed, complex numbers, and plenty…

> Statistically nobody writing C code gets to worry about a compiler error.

lol. (Hello, it is me, I am the statistical nobody.)

> C is the de facto language that's considered a boring and reliable solution.

De facto? Yes. Boring? Citation needed.

> The points made are less substance and more pedantic nit picking ("yeah, it's a language with the most mature and relied upon compilers, but the code is old dawg", "yeah, it's one of the most convervative languages to change, and you can compile decades old code just fine, but they added some stuff in C99, C23, etc").

Incredible. You missed some of the most important points while adding new points that neither of us were talking about. Are you alright?

> yeah, it's a language with the most mature and relied upon compilers, but the code is old dawg

I'm not guessing that the code is bad. You go read GCC code.

> it's one of the most convervative [sic] languages to change, and you can compile decades old code just fine

I don't think you even made this point in the first place, but that just means the changes are all backwards compatible. They have to make almost every change backwards compatible because C doesn't have a versioning mechanism.

However, all of the changes were not backwards compatible. You may find that you actually can't compile code that uses variable length arrays. They were made optional and several compilers never implemented them or no longer support them. Granted, it's good they're dead, but it's something that real codebases really used, including for a long time the Linux kernel, only really removed from it to support compiling with LLVM.

In other cases, compiler updates break things that were never standard but were relied on anyways. For example, if you go and compile old code from the 90s and 2000s, you'll often find they either refuse to compile or crash because they were never actually compliant to standard C in the first place. Because the compilers are buggy. They still are, but they used to be, too.

> And Rust is still very niche, single compiler, quickly changing affair. Compared to C and C++ adoption (which is a big yardstick of a tech being "boring") it doesn't even register.

Something being commonplace doesn't make it boring. You missed the most "exciting" part of C, what I consider the magnum opus of why it is never boring and never will be: Undefined behavior.

(And the standard library. Seriously, fuck C's string manipulation functions.)

--

Addendum: Until recently, I actually had a C project where I was using the OpenWatcom 2 fork of OpenWatcom as the primary compiler, due to needing a weird target. While it definitely generally worked, it also gave me a brand new perspective on which to appreciate the stability and reliability of even GCC and MSVC, which I will openly admit rarely run into incorrect compilations.

That said, in my many years of doing C and C++ code, I've run into countless situations where the compiler was, in fact, wrong. Either it refused to compile valid code (MSVC usually, but all of them at times), or it ICE'd during compilation (GCC usually), or it did in fact compile, but did the wrong thing (GCC and LLVM, especially with -O3.) Every time I debugged these down enough to actually report them, someone else was already on top of it, and usually it was even already patched, if not released yet.

I understand that big projects like GCC and LLVM are tricky to maintain, especially since they're dealing with standards as broken and stupid as C. But still, it doesn't change the reality that it's not literally that hard to run into a new compiler bug. The truth is that a lot of us just run into a compiler bug, shrug and make a quick workaround, and then go on our merry way.

There are also some bugs that are kind of bugs and kind of not. For example, the old pointer provenance bug: a comparison of two pointers, which are in fact equal at runtime, can constant fold to being false; it's a valid compilation.

There are many write-ups talking about strange C behaviors, some of which may technically be standards-compliant but are anything but obvious (or boring.)

https://www.ralfj.de/blog/2020/12/14/provenance.html

And sure. It is possible that you never run into any of this fun stuff, of course, but it's extremely easy to experience the degrees to which C is not boring. Just accidentally store a pointer beyond its lifetime (especially a pointer to the stack.) Engage in some undefined behavior of some kind. Suddenly, C becomes... very exciting.

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

#490
post #466

Earlier quoted context omitted.

Actual code is always better, but based on the description it seems a bit strange that there would be a single package that exports multiple implementations. Presumably each distinct implementation should be its own package. None of these packages would export the interface. An additional package would export the interface and provide the common functionality around that interface. Those common functions would be con…

No, I cannot agree that this would be called the consumer. Yes, you have technically moved the interface type away from the implementation, but just for the sake of it, without any other upsides. The consumer is still the package that is using and importing this interface type, just from another package now.

That is the beauty of engineering: There is no universal truth, just different tradeoffs. Meaning that you don't need to agree, nor should you even seek agreement. You can and should forge your own path if different tradeoffs are warranted for your unique needs.

But, this is the "idiomatic" approach. The upside is consistency for future readers. Code is for humans to read, after all. Most codebases follow this pattern, so it will be familiar when the next person encounters it. If you have a reason to do things differently, go for it. Nobody knows your problem better than you, so you cannot listen to others anyway.

I am quite curious about what you see in the different tradeoffs you are accepting, though! What has you weighing them in favour?

Post reply on HN