Hacker News new | past | comments | ask | show | jobs | submit login

I cant help feeling it is a missed opportunity to add generics to Go this late. A mistake that is copied from earlier languages (C++, Java), a mistake similar to other mistakes Go chose not to solve at it's inception, like: having implicit nulls (C, C++, Java, JS, C#), lack of proper sum types (C, C++, Java, JS) and only one blessed concurrency model (JS).

While I think I get the reasons for these decision in theory, make a simple-to-fully-understand language that compiles blazingly fast, I still feel it's a pity (most) these issues where not addressed.




Go really should have learned 2 lessons from Java 5:

1. People will eventually want generics 2. Retrofitting generics onto an existing language is hard and leads to unusual problems

(edit: I'm glad Go is doing this, but...Java learned this in 2004.)


There's is a design document for Go generics.

If you see "unusual problems" with the design, then tell us what they are.

Otherwise it's just shallow pattern matching "Java added generics late, they had problems, Go added generics late therefore they'll have problems too".

Counterexample: C# added generics late and it's perfectly fine design.

The reason Go team is not rushing to implement generics is precisely so that the design makes sense, in the context of Go.

Over the years Ian Taylor wrote several designs for generics, all of which were found to not be good enough.

They are doing it the right way: not shipping until they have a good design and they didn't have good design when Go launched.


If this follows the monomorphic approach described in Featherweight Go [1][2], they will at least avoid problems caused by type erasure and avoid too much runtime overhead.

1. https://arxiv.org/abs/2005.11710 2. https://news.ycombinator.com/item?id=23368453


But then you have compile time overhead (an issue Rust and C++ have faced). One of Go's design goals was to have very fast compile times, which might be in doubt if they take the monomorphization approach.


Is rust's slow compile time because of poor LLVM IR generation or just because monomorphization? D has generics and compiles fast. I guess Nim compile times are okay, too..


Go is just Java repeated as farce. The histories are almost identical with ~10 years lag.

We all called this when Go was created, too.


Just without the "VM".


JAVA -> Go + WASM is conservation of MEMEs? :D

(Not to disparage WASM, which has some nice ideas both on the technical and ecosystem level.)


Thanks but I don't need another Java. Enjoy your full Java and keep Go doing things go-way. :)


Are you saying Go should have not launched in 2009, but shout have waited 10 years until generics were ready?


If they made it a priority they could have shipped in 2010 with generics. There is no new art in this design.


Go has the unfortunate circumstances of its birth being before widespread recognition of the value of generics and better type systems. Those ideas existed in many languages, and in the PL community, and they were starting to take hold in other languages, but the consensus for most software engineers was that "sum types" are hard and "generics" aren't necessary and the type system should stay out of the way.

I think TypeScript, Scala, Kotlin, C#, and various others I forget now proved that these things weren't a fad and could yield significant gains in productivity and code correctness.

Had Rob Pike been more forward looking (or hired Anders Hejlsberg or Guy Steele to design the language) or dipped further into the PL research, he might have been so bold himself. I don't think anyone can fault him for it, these were niche and minority views in 2010 and may not even be in the majority today.

I think at the same time, we see what happens when a new language has large corporate backing in more recent years. Swift more closely resembles Rust than Go in terms of its type system.


"Generics are useful" was not even remotely a niche view in 2010. That was already 6 years after Java got them, and the lack of generics in Go was a common criticism from day one.


Philip Wadler introduced generics into Java and had previously designed Haskell, so he must have been thinking about types for at least a further 15 years before Java (20 years before Go).


This is such a bullshit argument. Why is it that any go post on hacker news pulls out all the tropes. Lack of exceptions. Lack of generics. Would generics make go a better a language? Maybe. Does the lack of generics make go objectively bad? Hell no!

I've had a long career coding in C, C++, Java, Lisp, Python, Ruby... you name it I've done it. Go is my favorite most productive language by far for solving typical backend issues. My least favorite? Java by a HUGE mile.


> Why is it that any go post on hacker news pulls out all the tropes. Lack of exceptions. Lack of generics.

It's pretty simple -- those of us who use those feature regularly in other languages know how valuable they are, and we miss them when they aren't there.


> Lack of exceptions

Is that really a problem? I think proper sum types to allow Result types that can encode many success/error states are so much nicer than an exception hierarchy. Rust and Kotlin did not go with exceptions, and for good reasons.

> C, C++, Java, Lisp, Python, Ruby... you name it I've done it.

Let me name a few: Rust, Kotlin, OCaml/Reason, Haskell, Elm. These languages carefully selected a set of features, the all have: no implicit nulls and sum types. And in your list non of them have those features. I really wonder what you think of these features when you've worked with them.


> Kotlin

Kotlin very much did go with exceptions except for the Result type in coroutines which wraps a Throwable anyway and is only used for the border between the coroutine runner and the async functions.


Why do you dislike java so much?


It was a common criticism but I don't think it was a majority criticism. Hacker News is not representative of the internet at large, and the idea that Go doesn't need or might not even benefit from generics is still pervasive. (See the first person to reply to you.)


The Go authors acknowledged the usefulness of generics as far back as 2009, shortly after its public release: https://research.swtch.com/generic


If you copy most of your design from Pascal / Modula 2 / Oberon as a safe bet to use a time-proven approach, this is only natural. If you don't want to use a time-proven approach, you need to design your own, and it's a massively more complex and fraught enterprise than adding GC and channels (which are both old, time-proven designs, too, just from elsewhere).

You could say that one could maybe copy the time-proven OCaml. But OCaml doesn't have a proven concurrency story, unlike Oberon and Modula-2 (yes, it had working coroutines back in 1992).

I also wish all these design decisions would not have been made in a new language, like they haven't been made in Rust. Unfortunately, the constraints under which creators of Go operated likely did not allow for such a luxury. As a result, Go is a language with first-class concurrency which one can get a grip of in a weekend, quick to market, and fast to compile. Most "better" languages, like Rust, OCaml, or Haskell, don't have most of these qualities. Go just fills a different segment, and there's a lot of demand in that segment.


>As a result, Go is a language with first-class concurrency which one can get a grip of in a weekend

Which is a mess. Sending mutable objects over channels is anything but "proven concurrency story".

Both Rust and Haskell (and OCaml, if we talk about concurrency and not parallelism) have way better concurrency story than Go. I don't care how fast one could start to write concurrent and parallel code if this code is error prone.

The only difference between Rust/Haskell and Go is that the former force you to learn how to write the correct code, while the latter hides the rocks under the water, letting you hit them in production.


I used "first-class" here to denote "explicitly a feature, a thing you can operate on", like "first-class functions" [1]. I didn't mean to say "best in class". I don't even think we have a definite winner in this area.

[1]: https://en.wikipedia.org/wiki/First-class_function


> first-class concurrency

That's an overstatement.

Also implicit nulls are not beneficent to anyone. And sum types could have made results (error/success) so much nicer. I see no reason to go with nulls at Go's inception, hence I call it a mistake.


The flip side was on the top of HN yesterday:

Generics and Compile-Time in Rust

https://news.ycombinator.com/item?id=23534974

It's easy for spectators / bystanders to call something a mistake because you don't understand the tradeoffs. Try designing and implementing a language and you'll see the tradeoffs more clearly.


D has generics and compiles fast. There are probably other examples too.

The overlooked thing is rustc produces poor quality LLVM IR which is also mentioned in FAQ.

And generics reduce amount of manual for loop juggling code one has to write. I don't think adding generics makes much of a difference.


> The overlooked thing is rustc produces poor quality LLVM IR which is also mentioned in FAQ.

LLVM is also slow in general. If you use it, it's likely the thing that's bottlenecking your language's compile-time unless you've done something insane like templates and `#include`, etc..

Inevitably it's the case that even if your source language doesn't do nearly as badly at the design stage when it comes to generics as C++ does, if you use LLVM your build stage is probably going to be unacceptably slow.


> LLVM is also slow in general.

Agreed. But so is GCC. And I guess many of the 'zero cost' abstractions require some advanced optimizing compiler like LLVM to be zero cost (or move that complexity to compiler end).

They specifically mentioned the technical debt and poor LLVM IR Generation issue though. I wonder if it has yet gotten attention or fixed. Maybe @pcwalton knows.


OK sure, now write your own backend or use one other than LLVM (which one?). Now you're going to learn about a different set of tradeoffs.


Go and D made the tradeoff. And both have good compile times. Both of them have GCC and LLVM frontends as well as a homegrown one. And homegrown ones have fast compile times.

Edit: well fast compile times at the expense of optimization. But that kind of proves the point.


I feel the same way, but then again Rust (among others) exists so it's not like those of us who dislike this approach are "stuck" with Go. I think it's actually nice to have the choice, reading the comment in this thread it's pretty clear that there are people who don't feel like we do.

Go clearly values "simple and practical" over "elegant". It seems to be quite successful at that.


I have to refute this 'simple and practical' claim.

Not having generics and neither having very common tools doesn't seem very good. You will have to write a for loop for what is a simple function call in python or javascript or <insert modern language here>. Such detail easily interrupts reading / writing flow.


I agree with the spirit of what you are saying, but I'd nit pick and say that lack of generics and presence of implicit null types make Go not simple and not practical over other options in the same space.


As someone using Java which has null and hardly using any generics even though they are available in Java. I find Java immensely practical with huge number of libraries and other facilities of ecosystem.

Seems you are of the opinion if you do not find something practical no one else can.


And I find go immensely practical and Java immensely impractical. But I see its value. It's almost like we have different languages because people are myriad :)

Problem-space and learning styles play a huge role.


Having seen Java shortcomings up and close I can totally understand that. It is just that some folks think their subjective opinion about programing are some universal objective truths.


That's exactly it. There is Rust and Java already. Use it, please. Don't try to make another Java from Go. One Java is enough.


> having implicit nulls (C, C++, Java, JS, C#),

> lack of proper sum types (C, C++, Java, JS)

Incidentally, Java and C# have addressed (or are in the process of addressing) both issues. Both languages/platforms are superior to golang in almost every conceivable way.


I've used a lot of Java and C#, and a decent amount of Go. I'm not sure I would call Go inferior. The design goals were different. I'm also not a language wonk, so maybe that's why I enjoy the relative simplicity of Go. The developer loop of code, run, code is very fast, and the standard library is good out the box. I just want to write code and get stuff done. To that end, Go is another capable, workman type language (like Java or C#).


Neither have addressed it though - they do have works in progress. Same as the lack of decent threading in Java.

It's been a WIP for years. Lets judge based on status quo rather than being disingenious.


How does Java not have decent threading? Go doesn't even have actual threads.

I'm assuming you're talking about goroutines aka virtual threads/fibers whatever which are entirely different from actual threads.


apologies, but yes, you're correct - I was referring to green threads


Hopefully will preview in next release (6 months release cycle) http://cr.openjdk.java.net/~rpressler/loom/loom/sol1_part1.h...

EAP build - http://jdk.java.net/loom/


I'm not aware of any current Java project on Sum types. There is multi-catch for exceptions but no immediate plans I know to use elsewhere.


A form of pattern matching and switch expression has already made it to the language as of JDK 14. Those are paving the way for full blown pattern matching and sealed types:

https://cr.openjdk.java.net/~briangoetz/amber/datum.html

https://openjdk.java.net/jeps/360


Java aren't fixing nulls, IMHO. They are making it worse.


How are they making it worse?

In any case, there already exist solutions in place:

https://checkerframework.org/manual/#example-use

https://github.com/uber/NullAway


The code ends up looking like:

  Optional<Integer> foo;

  //....

  if (foo != null) {
      foo.and_then(new Consumer () {
            function accept(Integer foo) {

            }
      });
  }


I would never assign null to an Optional nor use a library that returned one.

To ensure assignment before use make it final.


Except for green threads.


That's true though Project Loom is working on fibers. There's already an early access release to test.


Minor point, they've settled on the name "virtual threads" instead at this point.


Sum types are not planned for C# 9, are they?


It has pattern matching, but not a full discriminated union implementation yet. That seems to be on the roadmap though:

https://github.com/dotnet/csharplang/issues/113

https://github.com/dotnet/csharplang/issues/485


Swift had generics in place from Day One. It also hides the generics when they don't need to be shown (like many collection types).

I think that most of the standard language features are based on generics, but you would never know it, as a user of those features.


To be fair, Swift have a bit strange generics implementation that forces programmer to jumps through hoops to achieve something quite common in similar programming languages. The whole standard library is peppered with AnyThis and AnyThat, the language doesn't have generators (yield) and I'm not sure they're possible with the current generics design and programmers needs to learn what is type erasure just because the core team decided that returning generic interface from a function is something nobody will want.

I like Swift a lot, for many reasons, but generics design isn't one of these reasons.


Fair 'nuff. I was always a fan of the way C++ did it, but it was a great deal more technical.

Swift is sort of "generics for the masses." C++ is a lot more powerful, but also a lot more "in your face." I really do like the way that Swift allows generics to have implicit types.


Can't get enough of those template errors.




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

Search: