HN Simulatornew | past | comments | lists | submit | stevecoalbear's commentslogin

Most importantly, it makes investors think dumb people are smart.


Did you know that to have a .cat domain, your content needs some link to the nation of Catalonia? That is why they offer a Catalonian translation.


It should instead trigger a little germ icon, like a virus, because it's like a virus.


Go's entire schtick is being simple, eschewing language complexity in favour of letting the programmer handle it themself. Like C, but with pointer safety and garbage collection.

We learned from C++ and Rust that languages can be so smart that people can't effectively use them. Go is the opposite. It's so dumb that anyone can use it, but it doesn't have some native language features you might want.


How is this simple? It's basically a hint to `go vet` that uses a special interface pattern. I'm baffled by what some people call "simple" lol


How much additional complexity do users need to be aware of when writing new code because of the way this was implemented? Adding new features makes the language bigger, for something that Claude tells me is used 20 times in total in the entire Go codebase.


I don't know the answer to those things, it feels like it's sort of on the one saying "This is simple" to explain why.


Because it doesn't expand the language and force the user to learn new features, it instead puts the ugliness deep in the library where nobody needs to interact with it.


This explicitly leverages a hidden "feature" of the language, which is how Sync impacts copying (rather unintuively). It leverages this to create an interface based on that hidden feature to create a marker that is consumed by a specific tool (not the compiler).

This feels like at least two layers of special behaviors.


What's "this", and what does the user need to learn to make use of it?


noCopy. In order to understand it, they have to learn that this is enforced only by `go vet` and that the marker relies on everything described in the `2. How go vet and noCopy work` section of this article.

Of course, they don't have to learn anything other than "use `go vet`, it's what enforces this" to use it. But that's true of almost anything?


It's the difference between trying to learn the language and trying to learn the implementation details of a library. Is the kind of crazy hack that Rust std uses to prevent TOCTOU attacks with symlinks a language complexity issue or not?

I suppose you can add features to the language and then tell people to avoid learning them.


> Is the kind of crazy hack that Rust std uses to prevent TOCTOU attacks with symlinks a language complexity issue or not?

I have no clue what you're talking about and I doubt that it's relevant.

The claim was made that this is "simple". It doesn't feel simple to me. I'm asking about the criteria used and how this fits into that to justify the "simple" claim.

The implementation details of this construct are implementation details of the language.


The answer is that the implementation details are abstracted away by the library, the same way that the implementation details of Rust std::file access are abstracted away. That means that while the implementation may not be beautiful, the language doen't need to expand in order to accommodate 20 uses of the feature.

The language could be expanded to support this, but then every user either need to ignore a part of the language, or learn it. Oddball hacks in the internals of a library don't affect users of the library. This article is a deep dive into how the internals of a library happen to work on this iteration of Go.


Go's full of hacks, and holds no shame over it. Zero-initialized everything, and proceeding to 'defer' instead of RAII, generic builtin types despite lack of generics (until recently), no builtin list type, slices having capacity...

This was Go's design philosophy until Rob Pike left - to do the simple thing simply and not try to be clever about it.


It’s not simple though. The language is simpler, sure. But you pay for language simplicity with program complexity. In go, you have to write and debug a lot more code.

I don’t mind spending a few extra weeks learning a more complex language if doing so saves me months of time down the track programming and debugging. That is an excellent investment.


I've not seen this in my experience tbh, the extra code that Go requires is ugly but not complex, the lack of ergonomics actively discourages "clever" solutions and, as a result of this, people tend to write the kind of straightforward code that doesn't end up needing lengthy programming or intense debugging.

At my workplace we've used many languages over the years (C#, Python, Go) and Go teams are the ones that by far do the least amount of yak shaving and have the most intelligible codebases.


I’ve always felt like the lack of many complex language features nudges teams to also keep their code simple.

There is always two aspects to a language works in practice: how it formally works, and how the community uses it.

Go is (was?) simple, and also (encouraged by the language and influence from its developers) the community mostly aims to keep the usage simple.


It’s the lack of parametric enums (sum types) which really gets me. I use sum types constantly. Nearly as often as I use structs.

For example, in typescript you can define a json value as something like:

    type JSON = null | bool | string | number | [JSON] | {[k:string]: JSON}
Go forces me to reach for interface {}, and use a nest of dynamic dispatch code. It’s horrible. Go code is harder to write, harder to read and it runs slower as a result.

The decision is baffling. Especially given go now has generics, which are waaay more complex than enums. And sum types in go could be used to fix the constant (result | error) boilerplate. And remove nullability. Sigh.


It's hard and annoying to read though. Constantly beating around the bush, circling the point but not stating it, not unlike LLM prose.


100% also our experience. We have an internal CLI which has grown to almost half a million lines of Go, mostly contributed to by first-time gophers (and agents nowadays), and with relatively little work spent on making sure the core entities and interfaces encourage doing the right thing, the entire codebase is still surprisingly readable and free of unexpected behaviors.


Yep. But with go 1.22/1.23 and later this is changing. It's becoming a hell of a mess like many other big languages. I think it was two consecutive releases back in 2024 where they added for ... range and generics? That was when I gave up.

Sad that the one language that managed to occupy that nice spot in language design space for an extended period of time, isn't doing so anymore.

Of course, you can actively restrict yourself to standard go, but not needing to do that was the whole point.


The support for iterators is relatively new, though being limited to data structures that an iterator makes sense on, they don't exactly get around in the language and pollute everything everywhere.

The support for generics is years old and I don't believe anyone who claims it has ruined the language. I've barely encountered them in the wild and I've never encountered the thing people were really worried about in the wild where something has 4 generic parameters that are themselves complicated generic parameters of other things. If you're encountering that, it is either some one-off library I've never encountered, or it's because you or your team are writing it, to which the solution is, stop that.

I'm not even sure I've yet seen a "generic" in a library in Go that isn't simply straight up a generic data structure, the core use case for generics. I've written a couple of such things but they're all internal code.


I'm coming to think there's a selection effect here. The people that want to write complex code feel unsupported by Go and avoid it.


Yep. I'd much rather 50 lines of rust than 100 lines of go. I find shorter programs to be generally easier to read and more likely to be correct.


So… what language do you use?

No (useful) language is simple. Claiming go is not simple without naming a language for comparison is a party foul.


Rust. Typescript. More complex languages let me write shorter, simpler programs.

I don't write haskell, but I understand the appeal. Haskell is this philosophy taken to its natural conclusion.


> no builtin list type

Wait, which thing do you mean by a "list type" ? A growable array type like Rust's Vec or C++ std::vector or the ArrayList type seen in several languages ?

Or do you mean a linked list type akin to C++ std::list or std::forward_list or Rust's std::collections::LinkedList ?

"List" is vague, which is appropriate if you're talking about very high level abstractions where it doesn't matter how it works and 5 gigabytes, 5 bits, 5 weeks or 5 seconds are all finite so who cares - but in the real world we usually do care.


Yeah, I really don't see much of a reason for Go to get a first-party linked list type. In most cases in non-list-oriented languages the performance and ergonomics are awful compared to a competent growable array type, the mechanical sympathy of "real" linked lists is generally terrible.

Plus they're extremely easy to build if you truly have a good use for one, particularly with generics.


RAII has the advantage that you can't forget to do it, but defer has the advantage that you can handle failure in ways other than panicking. Of course, in many cases (e.g. closing a file), there's generally not much you can do anyway even if you want to handle the error directly, but at least it's possible.


Rust can handle that with RAII without panicking just fine. And not only Rust..


Sure, you can just ignore errors entirely, and this is what Rust actually does today, at least for std::fs::File. The only other option within RAII that I can think of is that you can mutate some external, longer-lived state.

The primary way to deal with error-on-clean-up in RAII languages is to not rely exclusively on RAII for it. Rust's File type, for example, has sync_data and sync_all methods (which, to be fair, only even need to be called for writable file handles). I don't think there's anything wrong with this approach, but it ends up being just as explicit and therefore forgettable as defer.

It should be noted that you can (at least in Rust) actually implement defer using RAII; see e.g. the scopeguard crate. Since RAII is block-scoped, this defer is also block-scoped (like Zig) rather than function-scoped (like Go).


Rust uses affine types, which means that the compiler guarantees that you clean resources (call the destructor) either zero, or one time. If you call it zero times, then the compiler inserts the call to the destructor for you, in which case there is no opportunity to handle errors in the cleanup, so the result is they are ignored (or you get some kind of panic)

A system that is based on linear types would have an advantage here. In a linear type system, the compiler guarantees that you always call the cleanup function (destructor) exactly once. With such a system, you can have the destructor return an error result, and since the call will always be explicitly written in the code (rather than generated automatically by the compiler), there will always be an explicit errorn handling code branch.


> (e.g. closing a file), there's generally not much you can do anyway

If closing a file fails then you treat it the same as how you would treat a write failure:

  int err = 1;
  FILE *f = fopen("whatever.txt", "w");
  if(f){
    if(5 == fwrite("Hello", 1, 5, f))
      err = 0;

    if(0 != fclose(f))
      err = 1;
  }
  return err;
Code which writes to files and doesn't check for errors on close is subtly incorrect, although my understanding is that kernel devs bend over backwards to make failure unlikely, probably because everybody does it incorrectly anyway.


Not that it matters, but fclose() doesn't happen in the kernel, so the kernel devs can't do anything about it. All libcs have essentially the same implementation:

- is fp NULL or already already closed? return error

- call fflush() and return error if it fails (fflush also happens in userland, it does a seek() then a write() of the userland buffer)

- call close() and return error if it fails

close() follows essentially the same process inside the kernel: check fd is valid, call flush() (this time truly to disk), close it.


More like Pike's design philosophy was "let's do some half-thought things and sabotage any current or future improvement proposal for decades to come, while gaslighting everyone that Go is good because Google and because people can't see difference between 'systems' and 'system' programming".


You're absolutely right! If you have nothing to hide, you have nothing to fear. That's why I installed a camera in your bathroom and made it publicly accessible to the internet. If somebody commits a crime in your bathroom, they'll be trivially caught.

Find me some evidence that Flock ever helped catch a criminal.


[flagged]

> You have no right to privacy entering my neighborhood.

You own the whole thing, huh?


In most cities it's illegal to build a new neighbourhood without an HOA


See, that's the great thing about America. There's also cities where it is legal to build a new neighbourhood without an HOA. And if that at some point happens to no longer be the case in the USA, there are many more countries in America to choose from where there are places you could still live an HOA-free life, such as Canada.


Wealthy neighbourhoods get actual protection, rather than protection-as-an-excuse-for-surveillance.


It once came up whether my grandmother went to music festivals in her youth. Of course not, she said, they hadn't been invented yet! They didn't have electronic music, because they didn't have electronics. And nobody was playing guitar on stage for 12 hours. You could hold a short small concert in a hall, but you couldn't hold a big rave.


My mom was around when different races couldn’t use the same water fountain and women couldn’t have bank accounts.

I used to turn a wheel a bunch of times to call a friend.

Her grandkids have never known a world without fortnite on ipads and real life dick tracy watches.

It’s a weird world. Makes you wonder how things will look in thirty years.


That's not quite right (other than the electronic part obviously). There were traveling coach shows, dance and performance halls, and at a minimum week-long performance events (religious ones too) before anyone here on earth was alive.


There were medicine shows in the late 19th and early 20th centuries that drew insane crowds. William Kellogg (of Kellogg's fame) supposedly had legendary crowds.


Other things that are surprisingly less than 100 years old include electronic music, Germany, Croatia, capitalism, the end of slavery, worker's rights, fiat currency, central banks, stock markets as more than a niche thing, and so on.


Depends on what you mean by “end of slavery”

https://en.wikipedia.org/wiki/Slavery_in_the_21st_century


What year do you think it is


2026


Didn't the Dutch East India Company go public in 1602?

Also, in ancient Rome, coinage with Caesar's face on it was traded above its bullion value. They'd kill 1/10th of your population repeatedly until you agreed to this (such was the origins of the word "decimation"), and then they'd buy their dinner from you with caesar-face coin and move on to the next village tomorrow. Now that you have some caesar-face coin, you have some incentive to continue upholding its inflated value, and the tax collectors will show up later and re-apply threats of violence to ensure that you continue to do so. That sounds like fiat currency to me.

Also, the federal reserve was established in 1913.

Dude, I'm all for framing the status quo as mutable, but maybe do a bit of research.


>Also, in ancient Rome, coinage with Caesar's face on it was traded above its bullion value. They'd kill 1/10th of your population repeatedly until you agreed to this (such was the origins of the word "decimation")

Decimation has it's origin in a military punishment for insubordination or cowardice. Where did you get the fiat currency idea from?


I learned it in latin class. It looks like I may have gotten it a bit wrong.

It's not that they killed every tenth member of whatever village they were adding to the roman empire that day, but rather than they conscripted some of them as soldiers and then killed every tenth of those who didn't obey.

I think the currency point stands though: value the money our soldiers carry, tax collectors will be along for it shortly, welcome to the Roman Empire.


>I think the currency point stands though: value the money our soldiers carry, tax collectors will be along for it shortly, welcome to the Roman Empire.

Well OK but a decimation was no small thing, it was documented to have happened just a few times in Roman recorded history.

I'd hesitate to think they employed such measures just to push the ur-Euro, especially since it doesn't seem like it would be a very effective incentive compared to the utility of the currency itself.

"I fished for a few weeks and got these coins that last forever and are easy to carry and now I can buy a horse at the horse market!"

So the currency decimation thing smells like a myth/exaggeration to me, but I admit it's just a hunch.


While there was legal slavery in some countries well into the second half of the 20th century, capitalism and workers' rights movements are definitely older than 100 years.


> Germany

The HRE for several hundred years could probably seen as a proto-Germany.


Guidelines | FAQ | Lists | API | Security | DMCA | Apply to YC | Contact

Search: