RU version is available. Content is displayed in original English for accuracy.
Advertisement
Advertisement
⚡ Community Insights
Discussion Sentiment
49% Positive
Analyzed from 4166 words in the discussion.
Trending Topics
#generics#language#generic#methods#types#don#need#design#always#add

Discussion (216 Comments)Read Original on HackerNews
I don't really understand this argument. I read the discussion linked to[1], and yeah, monomorphization approaches (whether at compile time, link time, or runtime with JIT) are obviously going to be difficult or impossible, but the reason against using runtime reflection is mostly that it's slow. But that runtime reflection is exactly how you would work around it today.
For the Identity example, could the interface be compiled to be basically equivalent to:
Identity(any) any
and then at the callsite add a cast of the return type to T?
I suppose primative non-pointer types add a bit of a wrinkle but even if it generic methods was restricted to pointer types, that's better than nothing. And the number of those types is relatively small, so when the implementation is compiled it could just instantiate method implementations for all the primative types, if they apply, and then maybe remove them if they aren't needed at link time.
Of course it's also possible there is some detail I've missed.
[1]: https://go.googlesource.com/proposal/+/refs/heads/master/des...
More specifically, it is that it would introduce surprising performance cliffs – code becoming surprisingly slow due to seemingly unrelated changes.
Though BTQH I think an even more important argument is that you would need to have effectively two generics implementations, one working at runtime and one working at compile time. That's a lot of complexity, with surprising failure modes if these two are not bug-compatible.
> But that runtime reflection is exactly how you would work around it today.
I think the overwhelming majority of people will "work around it" by just not trying to use generic methods.
My understanding is that go already has a hybrid system works at compiletime and sometimes at runtime.
Can't speak too deeply for Go specifically, but I do know on .NET one of the big reasons generic methods where T is a structure gets monomorphized per type, is so that stack size is adjusted and potentially even arg passing (i.e. large struct) as far as the caller/callee.
This is nonsensical. Monads define a strict set of behaviors formalized as "monad laws"[0].
Perhaps what you want is a container which adheres to monad laws capable of abstracting exceptions. Two exemplars of same are Haskell's Data.Either[1] and Scala's Either[2].
0 - https://wiki.haskell.org/Monad_laws
1 - https://hackage-content.haskell.org/package/base-4.22.0.0/do...
2 - https://www.scala-lang.org/api/3.8.3/scala/util/Either.html
That is what I meant. Struggling to picture what the other "nonsensical" thing is.
https://wiki.haskell.org/index.php?title=All_About_Monads
No contributor to Go is responsible for "introducing monads to computer science", as the Monad concept is a member of (or defined by if you prefer) Category Theory[0].
0 - https://en.wikipedia.org/wiki/Category_theory
It is Apple's school of design, think different, ah, actually, there are reasons why the fence is in the middle of nowhere.
Then the design ends up half way there versus being done properly from the beginning.
Yeah very critically.
Still, in this case, half the feature is better than none at all, IMO.
[1]: https://doc.rust-lang.org/reference/items/traits.html#r-item...
Did you?
Dynamically typed/untyped languages finding that strict and visible typing is actually good is another
Debatable how much they have been "right", although this gets them somewhat closer. And I think they have not been "wrong" in the ways they wanted to avoid (they referenced some issues with Java generics as prior art, although I forget the details).
> The post quotes the Go FAQ as saying, "we do not anticipate that Go will ever add generic methods".
https://www.bible.com/bible/compare/MAT.21.28-31
¹ I would argue that it is really, really hard to add generics to a language after it has already matured, and still "do it right" than to add it in the beginning. At least if you care about backwards compatibility. Backwards compatibility adds a lot of constraints to your generics system that will almost certainly lead to a sub-optimal design. And you will be stuck with a standard library, and a lot of existing ecosystem code that would benefit from generics, but don't because generics didn't exist when they were written. This is a lesson I wish go had learned from Java's generics.
I respect that.
-- Greenspun's tenth rule
He had some lack of conviction to scope it so narrowly.
Objective-C in contrast was a very few additions thoughtfully added that composed cleanly and freed the programmer to actually get things done.
Of course adding generics is not something that every language needs to do. Scripting languages like Ruby don't really need this style of generics. It doesn't fit the design of the language, and it's not even clear what that would look like in Ruby.
But static typing with generics does solve a recurring problem, and we've seen some real convergence towards type hints and type systems even in staunchly dynamic scripting languages. Modern Javascript is now mostly Typescript, and they've successfully retrofitted a very advanced type system in the last place I would have expected 20 years ago.
They added enums, they added sealed classes. They're trying to get rid of null (apparently it's really hard). The problem is that in 2012, when go 1.0 was released, this should have been obvious to everyone.
Here's a famous discussion from 2009, three years before the 1.0 release (tldr: facepalm)
https://groups.google.com/g/golang-nuts/c/rvGTZSFU8sY
The impression I have always gotten from Go's designers is that they are rather arrogant and averse to the idea of using other people's work. They want to develop everything from first principles, but by so doing end up with poor reinventions of well-studied concepts.
They did use someone else's work, though. If you recall, Philip Wadler (of Haskell fame) designed Go's generics.
> but by so doing end up with poor reinventions of well-studied concepts.
Which is funny as there is probably nobody on earth that would be more capable than Wadler to get the job done. His pedigree in that area of work is pretty astounding. If he couldn't do more than create a poor reinvention, what hope did the laymen working on the Go core team have?
Answer: They had no hope. It's not like they weren't trying. Ian Lance Taylor, for instance, is well known for beginning work on generics in Go before it was even first released to the public. He, among others, quite simply, were unable to figure it out.
Everything looks easy and straightforward when observed comfortably from an armchair, I suppose.
Remember that the generics implementations in other languages (like Java) take up half the spec + implementation - that's not something that Go wanted.
> The post quotes the Go FAQ as saying, "we do not anticipate that Go will ever add generic methods".
> Go intentionally has a weak type system... Go in general encourages programming by writing code rather than programming by writing types...
https://github.com/golang/go/issues/29649#issuecomment-45482...
And it's not like Golang is some freshman student's hobby project; it was created by one of the world's largest tech companies, by people with a strong pedigree in programming language design.
As for the detractors, from the first generics proposal this was called out as a "not now", not never. There were questions of implementation. They aren't a super large team, and they try to do things incrementally and do them well.
What? The post quotes the Go FAQ as saying, "we do not anticipate that Go will ever add generic methods". There is also some similar discussion of the original generics proposal, with language like "then it's much less clear why we need methods at all". (I'm omitting some context, but I don't feel that it changes the meaning.) Those feel much closer to "never" than "not now".)
The post is also subtitled "A change of view".
Everyone also wanted and accepted the need for generics. It was always something they wanted to add to the language. Rob Pike never said that that kind of abstraction isn’t what golang is for. It was always just a matter of getting the design right.
Go has always been a systems language. It was one when we thought it was going to fit nicely for low-level, high performance use-cases. Given that the GC, runtime overhead, lack of control over memory layout, and other issues made it a poor fit for what we historically thought were systems language tasks, it’s still a systems language because we’ve grown to understand that the term “systems program” has always meant network middleware that shuttles around JSON and transforms it.
Dependency management too. Modules were something that nobody argued were unnecessary. None of the language developers ever claimed that “you should always build against HEAD, and if upstream breaks you, that’s a coordination problem to be solved socially”. The community didn’t need to independently invent godep, then glide, then govendor, then dep, before the core team finally shipped modules. That was just enthusiastic parallel exploration of a problem space that everyone agreed was a problem.
GOPATH was always understood to be an awkward temporary scaffold that everyone tolerated while the real solution was being designed. The single-workspace model was never defended as philosophically correct or a deliberate feature of the language. When modules arrived, everyone was simply relieved that this obvious stopgap was finally replaced.
The core team always intended to add builtins for min/max. Nobody ever told you to just write `if a > b { return a }; return b` yourself because it was “only two lines.” The fact that every Go codebase in existence had its own copy of this logic, typically buried in a file called util.go, was not evidence of anything being missing from the language.
Range was always a stopgap before iterators could be implemented. Nobody ever argued that iterators were needlessly complicated and went against the spirit of the language. The slices and maps packages provided important missing features that everyone using the language wanted.
Everyone agrees that errors were anemic from the outset. errors.Is/errors.As are nice additions but everything was Just Fine™ before they were added.
Speaking of errors, having two lines of error-handling boilerplate for every line of code is good, and right, and perfect. It’s not verbose; it’s “explicit”. But when that gets changed to be less verbose, we will all agree that it was always a pain and made reading code unnecessarily more difficult and that everyone always expected this to be fixed some day.
I personally can’t wait to see what next development will never have been “against the Go philosophy” and definitely not something that gophers argued was perfect the way it was any time misguided malcontents and rabble-rousers wrongly tried to suggest the language wasn’t perfect the way it was.
If I were uncharitable I might call the categories "people who are somewhat removed from reality" and "people who inhabit observable reality". Avoid the former, treasure the latter.
Languages evolve for a reason and nobody should give a shit about people who do not understand why.
The writing is on the wall for next development.
“For the foreseeable future, the Go team will stop pursuing syntactic language changes for error handling. We will also close all open and incoming proposals that concern themselves primarily with the syntax of error handling, without further investigation.”
And of course, it was replaced with a more correct implementation that was incompatible with that awful stopgap because semantic correctness trumps all. vendor/ trees and GOPATH were never meant to be remotely compatible, and don't you know -- the Go compatibility guarantee(TM) doesn't apply to misuse of GOPATH to work around shortcomings^Wwell-considered designs of Go, even if it breaks the largest Go project at the time!
(/s It still shocks me that they decided to drop "src" from vendor/src and break compatibility when they finally got around to supporting vendoring despite every tool using it. And symlinks don't work because Plan 9 is the future!!)
Who are we that has always defined that term that way. For any systems programmer golang has pretty much not been a solution.
Systems is below layer 4 of the network stack, it is building the network stack in the first place.
I really hope it is more ergonomic error handling. Or maybe sum types/discriminated unions.
Let's get this straight. I'll give you a long quote from Rob Pike's article where he describes the history of the go language:
""" One thing that is conspicuously absent is of course a type hierarchy. Allow me to be rude about that for a minute.
Early in the rollout of Go I was told by someone that he could not imagine working in a language without generic types. As I have reported elsewhere, I found that an odd remark.
To be fair he was probably saying in his own way that he really liked what the STL does for him in C++. For the purpose of argument, though, let's take his claim at face value.
What it says is that he finds writing containers like lists of ints and maps of strings an unbearable burden. I find that an odd claim. I spend very little of my programming time struggling with those issues, even in languages without generic types.
But more important, what it says is that types are the way to lift that burden. Types. Not polymorphic functions or language primitives or helpers of other kinds, but types.
That's the detail that sticks with me.
Programmers who come to Go from C++ and Java miss the idea of programming with types, particularly inheritance and subclassing and all that. Perhaps I'm a philistine about types but I've never found that model particularly expressive.
My late friend Alain Fournier once told me that he considered the lowest form of academic work to be taxonomy. And you know what? Type hierarchies are just taxonomy. You need to decide what piece goes in what box, every type's parent, whether A inherits from B or B from A. Is a sortable array an array that sorts or a sorter represented by an array? If you believe that types address all design issues you must make that decision.
I believe that's a preposterous way to think about programming. What matters isn't the ancestor relations between things but what they can do for you.
That, of course, is where interfaces come into Go. But they're part of a bigger picture, the true Go philosophy. """
Rob Pike, 2012
I can draw a few conclusions from this: firstly, he didn't want to add generics at all because he didn't think they were useful, and secondly, he doesn't understand programming very well and doesn't know what generics are and confuses them with inheritance.
The slow turtle wins the race against the overly eager rabbit... so I'm okay with that
Like what?
nah I'm kidding
<after 55 seconds>
Seriously, what's wrong with `#define`?