[HN Gopher] Trying Out Generics in Go
       ___________________________________________________________________
        
       Trying Out Generics in Go
        
       Author : bullcitydev
       Score  : 143 points
       Date   : 2021-12-16 17:41 UTC (5 hours ago)
        
 (HTM) web link (markphelps.me)
 (TXT) w3m dump (markphelps.me)
        
       | Smaug123 wrote:
       | I think you're making it easy on yourself by choosing "a library
       | whose sole purpose is to stamp out the boilerplate needed to work
       | around Go's lack of generic algebraic data types" to demonstrate
       | how good generics are :P
        
         | bullcitydev wrote:
         | haha for sure. but still better than code generation IMO ;)
        
       | xyst wrote:
       | person deleted 95% of code, but what about performance? is it
       | more or less the same as the non-generic implementation?
        
       | amelius wrote:
       | Side question: Are there any languages that transpile to Go?
        
       | jaytaylor wrote:
       | Honest question:
       | 
       | Do you think Generics will be an overall win for the Go language,
       | or will they be overused / end up making code harder to read /
       | harder reason about?
       | 
       | I kind of hate looking at Go code containing generics. What
       | previously was elegant and easy on the eyes is now annoying and
       | muddled by the additional layer of abstraction. I'm saying this
       | with sadness, as someone who fell in love with Go back in 2012
       | and still writes it at least weekly.
       | 
       | Is it a better bet to move on and go full Rust, rather than
       | bother with wherever the goggle golang train is headed?
       | 
       | p.s. Even though code generation is [also] annoying and perhaps
       | not ideal, I've rarely needed to use it and kind of liked that it
       | was inconvenient - forcing me to think about problems
       | differently. Certainly some problems will benefit from the
       | addition of generics, but is it really enough to justify the
       | added complexity? I wonder if this is a case of tragedy due to
       | vocal minority.
       | 
       | p.p.s. Generics in other languages like Java or Scala seem fine,
       | as they are "kitchen sink"-style "all things to all people"
       | languages. Such behemoths are nearly always clunkier and less
       | easy to read than pre-generics Golang.
        
         | rackjack wrote:
         | Every language feature gets misused in some way, but if it is
         | overwhelmingly used to clarify and reduce code, I think it is a
         | win. I believe generics will overwhelmingly be used to do this,
         | so I think they are a win.
         | 
         | I doubt more complex features than this will be added,
         | considering how long it took to get generics.
         | 
         | Rust is a very different language from Go, though it can do
         | similar things. If you have people willing to learn it, you can
         | certainly try, though you might find the ecosystem lacking.
        
         | amelius wrote:
         | > Is it a better bet to move on and go full Rust, rather than
         | bother with wherever the goggle golang train is headed?
         | 
         | If you want to unnecessarily encumber your mind with trivial
         | but tedious memory management puzzles, then choose Rust.
        
         | cloudfifty wrote:
         | I'm not so sure it will be an overall win.
         | 
         | Will it be nice with generics for carefully crafted and cherry-
         | picked use-cases? Absolutely.
         | 
         | Will it make the average large codebase less readable after a
         | dozen coders have been doing their own cleverness with generics
         | 3-5 years down the line? In my experience, most definitely.
         | 
         | Of those two, I'm much more afraid of working with the latter
         | than missing out on the former.
         | 
         | It sometimes feel like we as devs have a habit of optimizing
         | for the individual dev's convenience (not to mention what's
         | fun) rather than for the collective effort's best interest -
         | like the long-term maintainability/coherency of the code base.
         | To some extent I assume that's just being human, but in other
         | professions I think it would be seen as a bit lazy and thus
         | more stigmatized.
        
         | fiedzia wrote:
         | > Is it a better bet to move on and go full Rust, rather than
         | bother with wherever the goggle golang train is headed?
         | 
         | Ecosystem aside, with Rust you'll get far better language
         | design (generics fully integrated with everything (stdlib,
         | consts, all libraries), sane error handling, sane dependency
         | management, no "any" type, editions, and more. More complexity
         | too though.
         | 
         | > Certainly some problems will benefit from the addition of
         | generics, but is it really enough to justify the added
         | complexity?
         | 
         | Coming from languages that have them, it's just hard to take
         | Golang seriously, where every library either ditches type
         | safety (more runtime errors I wouldn't have with other
         | language), or forces you to copy-paste code just because you
         | need support for some new type (more boilerplate to maintain ==
         | more errors). Or reinvents generics with code generation and
         | aboriginal characters.
         | 
         | Once you start using generics, they really aren't complex.
        
           | hpen wrote:
           | Is Rust really a suitable replacement for Go? I mean I know
           | they are both system languages but I feel they have different
           | use cases completely.
        
             | pizza234 wrote:
             | I'm a Rust "fanboy" (if one wants to say so), and I still
             | think that the use cases for Rust are just a minority in
             | the landscape of modern languages (that is, where there is
             | a choice).
             | 
             | Rust has a mind-boggling overhead, for many reasons (and
             | I'm not talking about the borrow checker, which I think one
             | gets used to after some time), even if the language itself
             | is consistent and ergonomic (within the intended
             | constraints).
             | 
             | To me, they have very different use cases - one will
             | definitely know when Rust is required or it's an
             | appropriate pick. For the rest, Go is fine. I think that
             | those who put them on the same basket, haven't really used
             | one of them.
             | 
             | Regarding systems programming, my opinion is that they
             | require the lack of a runtime (not just because of the
             | performance, but also, for the framework(s) written with
             | low-level primitives in mind), but this is arguable (in
             | particular, there's no clearcut definition of what systems
             | programming is).
        
               | hpen wrote:
               | I have only touched Rust & Go but I would only consider
               | Rust where I would previously have used C or C++. The
               | stuff that needs to be fast, low memory, and what not. I
               | see Go as more of a Java. Good for backend systems. Also
               | CLIs.
        
             | fiedzia wrote:
             | > they are both system languages
             | 
             | Due to ability to work without stdlib, Rust is system
             | language in a sense Go never will be, to the point Go
             | authors withdrawn this definition.
             | 
             | > Is Rust really a suitable replacement for Go?
             | 
             | It depends on your requirements for the ecosystem. If you
             | need compatibility with Go or Go libraries, than it's not a
             | replacement.
             | 
             | Libraries and support aside, any program written in Go can
             | be written in Rust (and going back to nostdlib, many
             | programs written in Rust cannot be written in Go). If you
             | have required libraries, I'd say it can be written
             | comparably quickly and easy. For example you can have web
             | service returning hello world in 10 lines of code or so in
             | either.
             | 
             | They are popular in different circles, but that is mostly
             | not related to technical abilities. For 99% of of
             | applications, you could pick either one.
        
             | [deleted]
        
           | saghm wrote:
           | Slight nit: Rust does have an `Any` type[0] (and has since at
           | least 1.0). Unlike Go's `interface{}`/`Any` type though, it's
           | actually type-safe; the only way to get a value from it is to
           | try to downcast into a concrete type, which returns an Option
           | and will always be `None` if it doesn't match the type.
           | 
           | [0]: https://doc.rust-lang.org/std/any/trait.Any.html
        
           | LanceH wrote:
           | > Coming from languages that have them, it's just hard to
           | take Golang seriously
           | 
           | Some people judge the language on their ability to get work
           | done with it.
           | 
           | I get generics, but they really don't come up in daily use
           | with the tasks where I use Go. Yes, it would be nice for
           | writing some libraries but you're going through a laundry
           | list of Rust features which don't hamper my ability to get
           | work done at all.
           | 
           | I even like Rust, but if I'm going to write a worker that
           | will read from a queue, do a transformation and write to a
           | few more queues/services upon completion, Go just works and
           | the turn around time is far better than Rust. It's like was
           | Perl was for Unix, but for the cloud instead.
        
             | pjmlp wrote:
             | That comparison is a disowner for Perl, given its language
             | capabilities.
        
               | mseepgood wrote:
               | It's a disowner for Go given that Perl's philosophy is
               | "more is more" and Go's philosophy is the Wirthian "less
               | is more".
        
             | fiedzia wrote:
             | > I get generics, but they really don't come up in daily
             | use with the tasks where I use Go.
             | 
             | I sort of understand this argument, but I can't really
             | imagine defining queue as something else then <T>
             | wait_for_item() -> T. I've been writing Python for to long
             | to know that wait_for_item() -> any will backfire in
             | production eventually and I don't want that. At some scale
             | (both in code size and amount and scope of dependencies)
             | those problems just become too serious and too common to
             | not have language that deals with that. And Go is way too
             | popular for people to limit its use only for the cases
             | where it currently works.
        
               | LanceH wrote:
               | Define queue using generics, sure. It will be huge for
               | people waiting packages.
               | 
               | A specific queue is typically well defined and has a
               | struct in/out.
               | 
               | There are times when I've wanted arbitrarily nested JSON
               | that doesn't map into structs very well, but it is
               | uncommon enough.
        
             | choeger wrote:
             | > Some people judge the language on their ability to get
             | work done with it.
             | 
             | Really? Safety and correctness aren't relevant for you?
             | Then why even bother with go instead of Python or a Lisp?
             | 
             | For me it's crucial that a programming language contains
             | tools that allow me to definitely rule out as many errors
             | as possible. A powerful (and sound) typesystem does just
             | that.
        
               | fnord123 wrote:
               | Maybe they don't want a target directory using 3gb from a
               | clean build.
        
               | cloudfifty wrote:
               | It's already self-evident that Go manages that just fine.
               | That's just weird dogma.
        
               | ori_b wrote:
               | How are you finding Idris? or are you more in the Agda
               | camp?
               | 
               | If you want to definitely rule out as many errors as
               | possible, dependently typed languages are the state of
               | the art, allowing you to write a sort function that will
               | fail to compile if it returns a list that isn't sorted
               | (eg,https://dafoster.net/articles/2015/02/27/proof-terms-
               | in-idri..., or https://www.twanvl.nl/blog/agda/sorting).
               | 
               | After all, if you can't even prove basic properties about
               | your code from your language, like array accesses being
               | within bounds, are you really using all possible tools to
               | rule out errors at your disposal?
        
               | choeger wrote:
               | To be fair, I never had a chance to use Idris nor Agda. I
               | don't know how capable I would be to encode the proofs in
               | libraries nor client code. If it's usable, I am all for
               | it.
               | 
               | Otoh, I do know that languages like OCaml, Haskell, or
               | Rust take the burden of trivial errors from my shoulders
               | for neglible cost.
        
               | grey-area wrote:
               | Does Rust also have a feature that instills a burning
               | desire to proselytise?
        
               | choeger wrote:
               | I like Rust mostly for its user-friendly tools. I dislike
               | the compilation model. The type system I already liked
               | even before Rust existed. So, not every String opinion on
               | PL is down to Rust.
        
               | AnimalMuppet wrote:
               | > > Some people judge the language on their ability to
               | get work done with it.
               | 
               | > Really? Safety and correctness aren't relevant for you?
               | Then why even bother with go instead of Python or a Lisp?
               | 
               | A charitable reading of the GP would be that "safety and
               | correctness" would be included in "getting work done", in
               | amounts that are appropriate to the work in question.
               | Your interpretation is... less than charitable.
        
               | LanceH wrote:
               | Exactly. Go is safe enough. Correctness for most programs
               | is more about making sure it solves the problem
               | correctly, not merely that it guarantees no errors if it
               | runs. That feels like a modern version of "It compiles,
               | I'm done."
        
             | eweise wrote:
             | I use Go every day and yeah you can your work done with it
             | but not quickly due to typing all the boilerplate.
        
             | cube2222 wrote:
             | Agreed.
             | 
             | I wrote a bunch of Rust, Scala, Haskell, but I still
             | greatly prefer Go, even without generics.
             | 
             | I am very happy with the generic container libraries I'll
             | get with generics, but I hope people won't try to be too
             | clever (as they usually do). So far, Go is a language that
             | just rules out a lot of bikeshedding, which I very much
             | appreciate. We'll see how that evolves.
             | 
             | I do think premature or wrong abstractions are a much
             | bigger and widespread problem than a lack of abstraction.
             | 
             | Also, I really like Go's error handling, it results in
             | error messages in Go projects usually being top-notch
             | (because of explicit handling and wrapping which includes
             | relevant context and human-readable messages).
        
               | garethrowlands wrote:
               | Premature or wrong anything is clearly bad. But is
               | parameterisation a premature or wrong abstraction? I'd
               | say that parameterisation - even in the type language -
               | is the original proven abstraction.
        
               | cube2222 wrote:
               | Yes, in my opinion oftentimes it is.
               | 
               | There is a reason why even in mathematics people like to
               | operate on concrete examples to get an intuition. For
               | many, concrete is much easier to understand than
               | abstract.
               | 
               | That's the less important point. The more important point
               | is that making your code generic often involves more
               | trickery which makes the code more complex, even if you
               | only use the code once or twice - so that's just effort
               | wasted.
               | 
               | The fact that parameterization is a proven abstraction
               | doesn't mean it's good everywhere. Same as I don't agree
               | with the "Clean Code" way of creating a myriad of 4 line
               | functions.
               | 
               | Yes, good programmers won't make these mistakes, you can
               | totally handle them. But when arriving at legacy code or
               | open-source projects I greatly prefer to find under-
               | abstraction rather than over-abstraction.
               | 
               | To be clear, I'm not against generics, I just agree with
               | the parent of my original message. I'm worried people
               | will overuse them and I don't want a whole laundry list
               | of Rust features in Go. I'm very happy about libraries
               | with type-safe generic B-Trees.
        
               | Jtsummers wrote:
               | I think this is why I always have trouble understanding
               | arguments against generics (in the general case at
               | least). Parameters are added to functions/methods in
               | order to make them more generic/flexible, as a rule. To
               | move something that may have been hardcoded into
               | something that can now be configured:
               | get_data() { filename=default ... }       =becomes=>
               | get_data(filename=default) { ... }
               | 
               | When the type either does not matter, but the concrete
               | instance records it, or the type makes sense to be
               | configurable, you want generics. As a silly example (but
               | short enough to fit into a comment block):
               | fn nth(seq: [int], n: int) -> int
               | 
               | Now you have to make a new _nth_ for every single
               | sequence type, even though it has no bearings on the
               | actual operation. Or you make it generic:
               | fn nth<T>(seq: [T], n: int) -> T
               | 
               | That's a trivia case, yes. But if anyone has ever worked
               | on a complex code base there are plenty of situations
               | like this that turn up, at least in my experience. Sure,
               | I almost always start off with concrete instances with a
               | fixed type, but as soon as it becomes apparent that the
               | type itself is irrelevant and I have a couple use-cases
               | with different types, why _not_ make it generic and be
               | done with it? Like, would you _really_ have more than one
               | version of that _get_data_ function running around, one
               | for every conceivable filename? That would be obscene.
               | Why would you do the same with types?
        
               | krylon wrote:
               | I'm with you. Go has its problems, and I am aware of
               | them, but it is just _so_ compatible with the way my
               | brain works, it is amazing.
               | 
               | I remember listening to a podcast about C++, and the
               | guest explained how after working with C++ for about five
               | years, they still encountered aspects of the language
               | that surprised them on a regular basis (to be fair,
               | though, that was before C++11). To me, Go just clicks in
               | way few languages did.
        
           | kubb wrote:
           | There is a market for a language like Rust but with garbage
           | collection and reflection. There is OCaml, but it's not for
           | the modern developer. Go with generics is the closest thing
           | to that which is getting some use.
        
             | jpgvm wrote:
             | I think so too but I think the languages that fit the bill
             | are Kotlin and Swift. Both modern syntax, great generics
             | w/GC and ARC respectively.
             | 
             | Go w/generics falls very short IMO, expressibility, type
             | safety and poor null handling all rule it out as a
             | reasonable stand-in for Rust.
        
             | wbl wrote:
             | Why not Ocaml?
        
             | cb321 wrote:
             | This more|less also describes Nim. The recent automatic
             | memory management ARC/ORC alternative is not really even
             | what most people think of as "garbage collection". Its
             | macros give you full AST accept & re-emit powers and it's
             | had generics since before Go existed. I realize it probably
             | does not score highly on "gets used", but it deserves more
             | attention.
        
             | echelon wrote:
             | Swift is pretty much that language. It doesn't have the
             | imitable crate ecosystem or tooling, though.
        
             | ReleaseCandidat wrote:
             | > There is a market for a language like Rust but with
             | garbage collection and reflection.
             | 
             | That's why languages like JS/TS, Haskell, Elixir, OCaml
             | (which is way more modern than Go), ... exist and are used.
        
         | cogman10 wrote:
         | > Do you think Generics will be an overall win for the Go
         | language, or will they be overused / end up making code harder
         | to read / harder reason about?
         | 
         | Here's my $0.02 from a java background. There will be cases
         | where someone overuses generics. That happen pretty much every
         | time a new language feature lands in any language.
         | 
         | However, my expectation is that like java, you will see Go
         | generics in general practice only come up when dealing with
         | things like collections. Once the community settles and stops
         | trying to use generics as a meta-programming language, they
         | will become pretty boring (which is what you want).
         | 
         | From a readability standpoint, IMO, generics in Java don't
         | really have a negative impact on readability. Sure, you'll get
         | the random `Map<Map<String, Object>, Object>`... but most
         | people see that as the anti-pattern it is.
         | 
         | In short, I'm guessing they'll be a win.
        
         | fizx wrote:
         | I use Go because it compiles quickly, the GC is reasonable, the
         | ecosystem is good enough, and it's not rocket science
         | (Scala/Rust/etc).
         | 
         | While generics moves Go in the direction of rocket science, it
         | feels like this is solving a problem I always have.
        
         | crehn wrote:
         | I'm concerned about two things (that I hope I'm wrong about):
         | (1) developers will overuse generics and use poor types or
         | `any` where not necessary, and (2) this marks the beginning of
         | Go's convergence to yet another language with a million choices
         | for abstractions and a million ways to misuse its features.
        
           | grey-area wrote:
           | I think they did this really quite elegantly by extending the
           | interfaces abstraction.
           | 
           | Personally I would discourage overuse of generics in an
           | application codebase as I'd discourage overuse of interfaces,
           | concurrency or channels - they have their place in certain
           | areas (for generics e.g. collections, orms - mostly in
           | library code) but most of the time simply aren't required.
        
         | ur-whale wrote:
         | > What previously was elegant and easy on the eyes is now
         | annoying and muddled by the additional layer of abstraction
         | 
         | You're just getting old is all.
         | 
         | What was once familiar now isn't ... how annoying.
         | 
         | If that worries you, don't: we're all walking down that path.
         | 
         | Give it a couple of decades and everything in your life will
         | feel like that.
        
         | mseepgood wrote:
         | > Is it a better bet to move on and go full Rust
         | 
         | If you don't like generics you shouldn't use Rust. You can't
         | escape them in Rust. The designers repeated the mistake of C++
         | and made it a language feature kitchen sink. It's an unholy
         | mess. You'll find yourself constantly fighting the borrow
         | checker. Type signatures are littered with lifetime
         | annotations. The type system is Turing complete because they
         | didn't analyze it before implementing it. Go's generics were
         | formally validated [1]. Rust's compile time is slow, and the
         | 'async' story is sad. Async functions are colored and infect
         | everything.
         | 
         | [1] https://arxiv.org/pdf/2005.11710.pdf
        
           | [deleted]
        
           | opnitro wrote:
           | A type system being turing complete really isn't a problem.
           | You bound the recursion depth in practice, and the chance of
           | a real world programming hitting that limit is minuscule.
           | Lot's of other languages have turing complete type systems,
           | subtyping and typeclasses lead towards it.
        
             | mseepgood wrote:
             | Sure, if you regularly want to increase your
             | #![recursion_limit] or #![type_length_limit] for the next
             | generation of type bloat.
        
             | socialdemocrat wrote:
             | Hmmm I guess it is all in the eye of the beholder. If you
             | are the kind of person who thinks C++ went wrong with its
             | template system, then you might find issue with any
             | language emulating C++ failures.
             | 
             | If you think C++ is a beautiful well deigned language, then
             | I am sure you will not have issues with Rust either.
        
               | opnitro wrote:
               | Java & Haskell both have turing complete type systems as
               | well. I'm not a particular fan of C++'s type system,
               | doesn't mean have metaprogramming features is bad.
        
           | dralley wrote:
           | >You'll find yourself constantly fighting the borrow checker.
           | 
           | In the beginning, yes, this is true. But most people learn
           | within a month or two which design patterns lead to problems
           | with the borrow checker and which work smoothly, and often
           | this knowledge translates to good design in languages like C
           | and C++ as well.
           | 
           | If you're fighting the borrow checker in Rust, you'd probably
           | have been fighting segfaults and use-after-free in C / C++.
           | I'd rather spend 30 minutes fighting the borrow checker than
           | spend 4 hours digging around in Valgrind.
           | 
           | > Type signatures are littered with lifetime annotations.
           | 
           | You cannot avoid the concept of lifetimes, without a garbage
           | collector. If you don't want garbage collection, you have to
           | deal with them.
           | 
           | Having explicit lifetime annotations in the code is _vastly_
           | better than trying to track the lifetimes in your head from
           | scratch every time.
        
             | lawl wrote:
             | > If you're fighting the borrow checker in Rust, you'd
             | probably have been fighting segfaults and use-after-free in
             | C / C++.
             | 
             | That is in my ( admittedly limited) experience just not
             | true. There's plenty of things that are perfectly safe that
             | the borrow checker just doesn't understand.
             | 
             | The borrow checker can prove that a subset of things is
             | safe. But the borrow checker being unable to prove
             | something doesn't mean it's not safe.
        
               | giovannibajo1 wrote:
               | This, one thousands times.
               | 
               | The borrow checker forces you to write in the very narrow
               | subset of code paradigms it can understand. When it fails
               | to compile, it doesn't mean it's wrong: it means that it
               | can't prove that it's correct, which is a completely
               | different statement.
        
           | socialdemocrat wrote:
           | Ah yeah, I am not sure everybody know me what "colored" means
           | but I remember when comparing a C# solution using async with
           | a Go solution using channels and Go routines I finally
           | understood why people keep raving about concurrency in Go. It
           | composed very nicely while any language following the popular
           | async/await approach turns into a total mess. I guess
           | async/await looked good years ago because we compared it with
           | managing POSIX threads manually. That sucked.
        
             | curun1r wrote:
             | It's worth noting that Rust's Async functionality starts
             | with very different priorities from Go's goroutines. Rust,
             | as a systems language, made lack of overhead (allocations,
             | etc) the highest priority. It's part of Rust's overall
             | zero-cost abstractions ethos. Goroutines are just never
             | going to be zero cost. Go chose to prioritize the interface
             | to the programmer, which is much more a part of Go's ethos
             | around being simple.
             | 
             | There's nothing wrong with either approach, they just have
             | different trade-offs because their goals are different.
             | Rust's approach will sometimes push complexity onto the
             | programmer to handle. But it can be made to perform better
             | and more predictably than the Go equivalent. This might not
             | matter if you're not pushing the performance envelope, but
             | if you are, Rust makes that possible in a way that Go
             | simply doesn't. You'd never want to write code using
             | goroutines for an embedded device with limited CPU/memory,
             | but Rust's async is already proving useful for these sorts
             | of projects.
             | 
             | However if you can tolerate the performance overhead that
             | Go imposes, giving the programmer a simpler mental model
             | can easily be worthwhile. Technology is all about trade-
             | offs and you have to choose the right tool for the job.
        
             | djur wrote:
             | Async/await was intentionally chosen by a lot of languages
             | well after Go had become popular. Rust once had Go-style
             | concurrency and abandoned it in favor of its current model.
        
           | gpderetta wrote:
           | Paraphrasing Stroustrup, there are only two types of
           | languages: those (that end up) with a Turing complete type
           | system and those that nobody use.
        
         | ppeetteerr wrote:
         | Not a Go programmer but I can say that Generics were important
         | for me to consider adoption of Go. Now that they are present,
         | it's a legitimate language. Whether they make code messy really
         | depends on how they are being used.
        
           | choeger wrote:
           | > Now that they are present, it's a legitimate language.
           | 
           | I second that sentiment, but I would have to look into the
           | specifics. Generics ala Java aren't really that attractive
           | when Rust mainstreams ML-style polymorphism with Haskell-
           | style overloading.
        
           | spion wrote:
           | What about `if err return err` everywhere?
        
         | nynx wrote:
         | I'm certainly not a fan of Go, but I suspect generics will
         | result in the language and ecosystem getting better. I'm not
         | personally a fan of the go generics syntax because I find
         | braces and parentheses to be visually similar, but I'm sure
         | that would go away if I used it more.
         | 
         | I'd go for Rust tbh. I think it's a much more coherent
         | language.
        
           | spinny wrote:
           | Wrote Go code daily for quite some time, also tried Rust.
           | 
           | I like Go because of the tooling and simplicity of the
           | language, it's easy to learn and explain.
           | 
           | Rust has the borrow checker has a corner stone. The concept
           | mutability and references is easier to understand if you are
           | coming from the c/c++ side of things
        
         | marcosdumay wrote:
         | Hum, I've never seen generics making code harder to reason
         | about in any language, except, of course for C++, where they
         | are hacked over text.
         | 
         | If they will make code harder to read, that's up to syntax. I
         | don't know how all that will look up on the end, but it should
         | be reasonably easy to just write an example.
        
           | spinny wrote:
           | > Hum, I've never seen generics making code harder to reason
           | about in any language, except, of course for C++, where they
           | are hacked over text.
           | 
           | do you mean templates?
           | 
           | i was under the impression that c++ generics == templates,
           | but after a google search found out that c++ has both (at
           | least according to microsoft), not surprised
           | 
           | https://docs.microsoft.com/en-us/cpp/extensions/generics-
           | and...
        
             | marcosdumay wrote:
             | Yes, generics in C++ are created with templates.
        
             | tsimionescu wrote:
             | C++/CLI is C++ compiled to NET CLR IL, so it has all the
             | features of the regular C++ compiler (templates) AND all
             | the features of the CLR (generics).
             | 
             | It is an extremely niche language, extremely rarely used
             | even in the .NET ecosystem, except sometimes as glue code.
             | 
             | Normal C++, including MSVC C++, has only templates.
        
               | pjmlp wrote:
               | It is definitely nicer than trying to correctly get
               | P/Invoke declarations or debug COM marshaling issues.
               | 
               | This is the kind of tooling that makes me still reach out
               | for C++ when going outside managed languages.
        
               | tsimionescu wrote:
               | My experience was that P/Invoke is much easier, but of
               | course YMMV. COM I never played around with.
               | 
               | I also found a pretty ugly bug in the C++/CLR compiler -
               | if you used in-place initialization for an array
               | (something like auto arr = Object[]{obj1}), it would
               | allocate an array of length 0xC0FFEE and set the elements
               | you specified. They acknowledged the bug but said they
               | will only fix it in a future version of the language.
               | 
               | This told me all I needed to know about how popular it
               | actually was.
        
         | johnmaguire wrote:
         | As someone who's been writing Go full-time for only about 8
         | months now, I've repeatedly been frustrated with the lack of
         | generics while building web APIs. For example, the Go GraphQL
         | ecosystem is a bit of a disaster full of type unsafe code and
         | use of reflection or code generation to support simple things
         | like "a resolver that returns FooResult" vs. "a resolver that
         | returns BarResult."
         | 
         | Here's a fun one I stumbled on: How do you implement a PUT
         | endpoint where a missing JSON value is treated different than a
         | null JSON value? This ends up being _very_ difficult and
         | requires a boilerplate wrapper type for every single type you
         | might accept. It 's even worse when you start accepting slices
         | or maps, or slices of maps...
         | 
         | These are areas where generics will help me a lot.
        
           | masklinn wrote:
           | > How do you implement a PUT endpoint where a missing JSON
           | value is treated different than a null JSON value?
           | 
           | Tbf that's a pain in the ass everywhere unless you're
           | reifying it as a map (so manipulating a json dom).
           | 
           | Iirc in rust the "complete" way to do this for a struct (as
           | opposed to a map) with serde require two options and a
           | bespoke deserializer.
        
             | johnmaguire wrote:
             | It's much easier to do in dynamically typed languages or by
             | using maps - agreed. Unfortunately we have other design
             | decisions that force us into using structs for
             | deserialization on this endpoint (part of our validation
             | strategy.)
             | 
             | The Go answer is a struct that contains an IsDefined
             | boolean (i.e. your first option), and a pointer-to-value
             | (i.e. your second option.)
             | 
             | This is fine if you need it, but having to write this same
             | logic over and over again for every type gets old...
             | especially if your validators are tied to your types (i.e.
             | a type per field.)
        
         | zemo wrote:
         | having played with generics over the past few weeks: my guess
         | is that there will be a period of widespread misuse, the first
         | six months or so after 1.18 is released. So... between February
         | and August of next year I'm expecting a lot of the Go discourse
         | to be characterized by a very poor signal to noise ratio. I
         | think there's virtually no chance that Go 1.18 will come out
         | and people will use generics well; people will use generics
         | poorly before they use them well.
         | 
         | A bunch of people will write libraries that utilize generics in
         | some way that's not very orthogonal to the rest of the Go
         | ecosystem. They'll put these libraries out as quickly as
         | possible, because they want a first-mover advantage in picking
         | up adoption. A handful of people will take their time and learn
         | how to utilize generics in a way that is native to Go.
         | Eventually those people come out of the woodwork, and it turns
         | out that utilizing generics in Go looks different than it
         | looked in some other language, so a lot of the early
         | assumptions about how to use them were wrong. A bunch of those
         | early libraries turned out to be badly designed once actually
         | deployed into the real world, so they fade out of use as their
         | problem domains get written by newer libraries that utilize
         | generics in a manner more orthogonal to the rest of the Go
         | ecosystem. A few of those libraries picked up significant
         | market share, and maybe a startup has shipped stuff that
         | generates revenue with those libraries, so they fund those
         | projects, which continue to exist as a result of pure inertia.
         | So now you have some big libraries written in like ... March of
         | 2022, which are just bad, but people keep promoting them
         | because they have a vested interest in doing so, but the
         | ecosystem at large moves on, and by late 2022, generics will
         | fit in very nicely with Go and not complicate things in an
         | unnatural way. I'm wary of what's coming in the short term, but
         | optimistic of what's coming in the long term as a result of
         | this change.
        
         | [deleted]
        
         | horsemans wrote:
         | I have never needed generics in Go, and I've probably been
         | using it since 2017. I've never even once had to resort to any
         | interface{} trickery to express what I want, and I've written
         | Go programs for Fortune 50 companies, as well as complex
         | personal projects such as AST parsers/code generators.
         | 
         | I'm pretty disappointed to see generics introduced into the
         | language and every example I've seen feels completely
         | unreadable to me compared to pre-generics implementations.
         | 
         | To be clear, it has never been the case that the Golang authors
         | were 100% against generics. It has always been their position
         | that the implementation needed to be good enough to make the
         | trade-offs worthwhile. I just don't think they chose the right
         | trade-offs.
        
           | qaq wrote:
           | never needed min/max ?
        
           | kodablah wrote:
           | > I've never even once had to resort to any interface{}
           | trickery to express what I want, and I've written Go programs
           | for Fortune 50 companies, as well as complex personal
           | projects such as AST parsers/code generators.
           | 
           | That's pretty surprising to me. Have you never had to
           | implement marshalers for unknown types and such? I have had
           | to implement things like json.Marshal and json.Unmarshal for
           | different encodings dozens of times in my Go tenure. I have
           | had to use reflection a lot. I have had to deserialize into
           | map[string]interface{} to handle ambiguous situations at
           | runtime a lot. Have you never even had to wrap or build your
           | own Printf equivalents that accept interface{}? No loggers?
           | No custom containers? None of that which operates on unknown
           | types?
           | 
           | I see use of interface{} all over the vast majority of Go
           | projects. I think your experience may be atypical.
        
         | cube2222 wrote:
         | I share your worries, but I think it will be just fine. There
         | are two reasons I have for that:
         | 
         | First, the Go community mainly comprises people who love
         | simplicity and got accustomed to it. I imagine most people who
         | want to go overboard with generics will stay with languages
         | that let them go way more overboard.
         | 
         | Second, and more importantly, there's no method
         | parameterization, which saves us from monadland.
        
         | jjice wrote:
         | I hope that this quote from the article is true:
         | 
         | > I'm not sure that most Go developers will be using generics
         | daily, but it's nice to know that they exist if we need them.
         | 
         | Most people won't need generics in Go, and I hope people don't
         | force them into their code where an interface would do just
         | fine. I'm a big fan of good type systems like Rust, but Go
         | doesn't need all that power all over the place. I think
         | generics are a good feature for Go, but I really hope they
         | don't get overused in places that would currently use an
         | interface.
        
         | 13415 wrote:
         | In my opinion, there are plenty of good alternatives to Go such
         | as Nim, or Python if performance allows, and even languages
         | like Zig, V, CommonLisp, and D depending on the use case. I
         | don't get why people keep mentioning Rust in threads about Go.
         | It's perhaps a replacement for C, C++ and Ada - though for the
         | latter only if you're okay with switching from self-documenting
         | code to unreadable gibberish. Rust's philosophy is pretty much
         | the opposite of that of Go, and it is neither designed nor
         | suitable as a high productivity, easy to use language.
         | 
         | IMHO Go generics are simple and useful, particularly for
         | container libraries. They are fairly readable, unlike template
         | programming and macros in other languages. Together with the
         | _any_ type alias for _interface{}_ they will make code more
         | readable.
         | 
         | I do hope that Go stays at version 1, though, or that it at
         | least takes a long time to add new substantial features and get
         | version 2. Slow change is one of the many advantages of Go and
         | I'd rather see them improve the compiler in hidden ways.
        
         | spinny wrote:
         | While generics are definitely useful to implement container
         | types, it seems that the Go design seems to prevent that. It
         | seems to me that generics get overused when the language allows
         | you operator overloading for example. Go is a "one way to do
         | thing X" language, it doesn't give much room to write
         | "creative" code
        
       | FpUser wrote:
       | >"In case you've been living under a rock ..."
       | 
       | Not really but getting to know Go is not on the list of my
       | priorities.
       | 
       | Looked at examples. Many languages use angle brackets for
       | generics and templates but in case of Go they had to do it their
       | own way and use square brackets that most programmers would
       | perceive as an array. Funny.
        
       | bullcitydev wrote:
       | Author here. I just removed the previous section I had around
       | using build tags because I realized I was using `// +build 1.18`
       | instead of the correct `// +build go1.18`. Oops.
        
         | grey-area wrote:
         | Shame build tags aren't part of the language with a proper
         | syntax check instead of magic comments.
        
           | giovannibajo1 wrote:
           | Can you show me an example of a language that does syntax
           | checking of build-system related directives at compile time?
        
         | travisd wrote:
         | FYI: Looks like code blocks are unreadable on mobile (probably
         | a overflow: hidden CSS rule somewhere that truncates lines and
         | doesn't let you scroll).
        
           | bullcitydev wrote:
           | Just fixed it. Thanks again!
        
           | bullcitydev wrote:
           | thanks! I'll check it out!
        
       | geoka9 wrote:
       | It could be my personal negative experience with maintaining code
       | that overuses generics in other languages, but I have
       | reservations about this feature. I almost never need them, but on
       | the other hand I don't feel too good about having to repeat
       | myself when writing library packages.
       | 
       | I almost feel I would be happy with generics in Go if Go made
       | them illegal in anything but libraries (not allowed in package
       | main, maybe? Or not allowed in a package unless it gets imported
       | by another package?).
        
         | FpUser wrote:
         | Yes generics / templates are mostly useful for general
         | libraries. But if you afraid of programmers doing stupid things
         | just for the fuck of it it is better not to hire such
         | programmers, warn them if they're juniors or just hit them with
         | the bat on code review.
        
           | geoka9 wrote:
           | That could be said about any language though? Yet here we
           | are, arguing whether generics are good for Go, instead of
           | just using Java.
        
       | random314 wrote:
       | This is a phenomenal achievement, that I didn't expect to see in
       | my lifetime!
       | 
       | Gives me hope that P vs NP will be resolved in my lifetime too!!
        
       | hmmdar wrote:
       | Another way to do `Option` without pointers could be similar to
       | the following with a struct with two members.
       | type Option[T any] struct {           v T           isSet bool
       | }              func NewOption[T any](v T) Option[T] {
       | return Option[T]{               v: v,               isSet: true,
       | }       }              func (o Option[T]) Get() (v T) {
       | if !o.isSet {               return v           }           return
       | o.v       }              func (o Option[T]) IsSet() bool { return
       | o.isSet }
       | 
       | With this pattern you're able to use `Option` as a value without
       | pointers.                 var o Option[int32]              o =
       | NewOption(int32(1))              fmt.Println("value:", o.Get())
       | fmt.Println("is set:", o.IsSet())
       | 
       | Alternative separate `Get` and `IsSet` methods, is to combine
       | them into one, similar to map look up pattern.
       | func (o Option[T]) Get() (v T, isSet bool) {           if
       | !o.isSet {               return v, false           }
       | return o.v, true       }              var o Options[int32]
       | v, ok := o.Get() // zero, false              o =
       | NewOption(int32(1))       v, ok = o.Get() // 1, true
        
         | 1_player wrote:
         | I don't understand your example, `isSet` is always true and can
         | never be false. Missed something?
        
           | hmmdar wrote:
           | The only time `IsSet` would be false is when `NewOption` was
           | not used to initialize the value.
           | 
           | e.g.                 var o Option[int32]
           | 
           | or could have `None` helper                 func None[T
           | any]() Option[T] { return Option[T]{} }            o :=
           | None[int32]()
        
         | iambvk wrote:
         | I agree with `Get` returning `(T, bool)` I don't see why one
         | would want to return an `error`.
        
       | dsnr wrote:
       | That's a welcome feature even though I don't like the syntax. But
       | Go could become the perfect language if they just fixed error
       | handling and a couple small annoying quirks.
        
         | Jemaclus wrote:
         | Can you elaborate on "fix[ing] error handling" and what some of
         | those small annoying quirks might be? I've got my own
         | annoyances, but am always interested in what other people
         | think.
        
         | fourseventy wrote:
         | I like the go error handling
        
         | dewey wrote:
         | I've never seen a person who writes Go for more than a few
         | weeks complain about the error handling. I certainly don't mind
         | it myself. Is it really a problem people have or just somewhat
         | of a meme at this point?
        
           | stouset wrote:
           | Hi, I'm one of these people.
           | 
           | I used Go for about six months and eventually abandoned it to
           | pursue Rust, a decision I've been extremely satisfied with.
           | The longer I used Go, the more I grew to hate it and error
           | handling was one component of that.
           | 
           | Well over half of Go source code in practice is dealing with
           | errors, and somehow the Go ecosystem has convinced themselves
           | that "verbose" is the same as "explicit" when it doesn't need
           | to be. The worst problem isn't that it's just a lot of excess
           | code, it's that it makes all sorts of very simple and common
           | programming tasks ridiculously unwieldy. The most obvious
           | example is calling a fallible method, doing something to the
           | result, and returning it (or the error). This is _one single
           | character_ in Rust but a minimum of four lines--with
           | branching--of copy-pasted boilerplate in Go. Which isn 't a
           | lot in the abstract, but then you multiply that by hundreds
           | of times and now I have read, lex, parse, and mentally
           | discard the majority of pages of source code that's doing
           | something that could be done in ten lines _with a massive
           | incerase of clarity_ in a more reasonable language.
           | 
           | You've probably "never seen" us because we felt very let down
           | by the overpromise and underdelivery of go and _we left_.
        
             | mseepgood wrote:
             | > This is one single character
             | 
             | So you're bubbling up the error without annotating it...
             | great
        
               | stouset wrote:
               | There's so much wrong in just this once sentence it's
               | going to take a surprising amount of text to cover it
               | all.
               | 
               | First, if you want to add extra annotations or scope to
               | the error, you can actually do so--and trivially--while
               | still using that single `?`. Widely-used error crates
               | like `thiserror` allow you to specify that (for example)
               | an I/O error will be automatically wrapped with `?` by
               | some custom error type specific to your crate that
               | conveys more information about what went wrong. This is
               | phenomenal for errors that need to be bubbled up to end-
               | users.
               | 
               | Second, for the majority of errors that are normal,
               | expected, and recoverable, annotating them is just
               | pointless busywork since they'll never be visible from
               | outside of your program. For example, errors that
               | eventually bubble up to an `.ok_or(...)` receive zero
               | benefit from being annotated.
               | 
               | Third, is your preferred alternative the Go approach
               | where you function as a less-capable human exception
               | handler? Having to hunt through the source to identify
               | what actually happened through some contortionist `error:
               | thing went wrong: subsystem died: api client failed:
               | gcloud client: cache error: filesystem error: file not
               | found: tmp.VRVcBX1j` with no line numbers or function
               | names, and various random components of the error string
               | coming from either third-party libraries or the golang
               | standard library? This is just so comically terrible to
               | anyone who's spent time in languages with decent error
               | handling it's genuinely hard to believe that people
               | regularly come to its defense.
               | 
               | But of course I'm being generous here when we both know
               | the actual status quo in the overwhelming majority of
               | production Go projects is to simply bubble up the error
               | with `return nil, err` with no context whatsoever, so you
               | just get `error: file not found: tmp.VRVcBX1j` with
               | absolutely no idea of where it came from. Those are
               | always my favorite.
               | 
               | So, to recap: with Rust's `?` operator you actually _can_
               | have your cake and eat it too. You can add library-
               | specific context to your errors while actually wrapping
               | the underlying error and not merely mashing strings
               | together. You can opt into stack traces for your own code
               | if you want to. And you can skip the annotations for code
               | where you handle errors and don 't bubble them up. The
               | only apparent downside is that it's not overly verbose
               | enough for Go adherents.
        
               | LandR wrote:
               | Go developers aren't happy unless they are taking 10
               | lines of code and turning it into 150.
        
           | cytzol wrote:
           | I like Go. It's useful for the things I need it for since it
           | compiles fast into a single binary and has networking
           | utilities in its standard library. I was used to Rust's error
           | handling when I started, but I liked how simple Go's design
           | was in comparison, so I stuck with it to get a proper feel
           | for the language.
           | 
           | After a while, I tried using the Goland IDE, and its static
           | analysis tool found a dozen places where I wasn't handling
           | errors correctly: I was calling functions that return errors
           | (such as `io.ReadCloser.Close` or
           | `http.ResponseWriter.Write`) without assigning their results
           | to variables, so any errors produced by them would simply be
           | ignored. My code was compiler-error-free, go-vet warning
           | free, and _still_ , I was shipping buggy code.
           | 
           | A few months later, I try using the golangci-lint suite of
           | linters, and _again_ , it found _even more_ places where I
           | wasn 't handling errors correctly: I was assigning to `err`
           | and then, later, re-assigning to `err` without checking if
           | there was an error in between. My code was still compiler-
           | error-free, go-vet warning free, and now IDE-warning free --
           | and I was still shipping buggy code.
           | 
           | I don't see how anyone can see this as anything other than a
           | big ugly wart on the face of the language. It's not because
           | it's repetitive, it's because it's fragile. Even with code I
           | was looking at and editing regularly, it was far too easy to
           | get wrong. I'm going to continue using Go because it still
           | fits my purposes well, but I'm only running it on _my_
           | servers, so any mistakes I make are on _my_ head, rather than
           | on anybody else 's.
           | 
           | I also don't think Go's design is really amenable to things
           | like the Option and Result types people are writing -- yes, I
           | would never have had these problems in Rust, but code written
           | using them in Go is clunky and looks out-of-place and doesn't
           | _feel_ like it 's the right thing to write. I wouldn't ever
           | use the `Optional` type in the article. But it's definitely
           | not a solution in search of a problem. There's a huge
           | problem.
        
             | xxpor wrote:
             | So wait, go has handle errors by returning them, but it
             | also doesn't force you to actually handle all return
             | values? I thought that was the entire point of implementing
             | error handling like that.
             | 
             | How are we still repeating the same mistakes C made 50
             | years ago?
        
             | geoka9 wrote:
             | > I don't see how anyone can see this as anything other
             | than a big ugly wart on the face of the language.
             | 
             | Would you be satisfied if the compiler forced you to check
             | error returns?
        
           | ghayes wrote:
           | It might also be self-selection that people that truly
           | dislike the error handling simply avoid golang. I'd really be
           | interested to see how well go generics handle the Result
           | type.
        
           | jatone wrote:
           | meme. its like the least annoying thing I deal with on a
           | daily bases when programming. oh no... I have to handle an
           | error....
        
           | eweise wrote:
           | They probably stop complaining after a few weeks because
           | there's no use. It is what it is.
        
         | topicseed wrote:
         | What would you like for error handling?
        
           | spion wrote:
           | See Swift for a much more reasonable way to do error handling
           | https://docs.swift.org/swift-
           | book/LanguageGuide/ErrorHandlin...
        
           | pkaye wrote:
           | Personally I think the documentation should enumerate all the
           | error types returned by functions.
        
       | bruce343434 wrote:
       | How does Go handle the ambiguity between [] meaning generics and
       | [] also meaning array?
        
         | pphysch wrote:
         | You can use optional(?) parenthesis to make it extra clear.
         | 
         | []MyContainer[T] // slice of generic struct or interface
         | 
         | can/must be written as
         | 
         | [](MyContainer[T])
         | 
         | but ([]MyContainer)[T] isn't a valid use of generics anyways.
        
         | uluyol wrote:
         | In most cases there is no parsing ambiguity. In the cases where
         | there are, you need to use parenthesis to clarify.
        
       | unix1 wrote:
       | I too was playing around with Go generics. I wrote some naive
       | concurrent filter and fold (reduce) functions for slices and maps
       | here https://github.com/unix1/gostdx if anyone is curious how
       | those would feel.
        
       | Laremere wrote:
       | My opinion with 9+ years since first learning Go, multiple of
       | those using it for a full time job:
       | 
       | Putting the end first, my rule of thumb for using generics in Go
       | is: Don't go down the OOP road of over planning and programming
       | with fancy type work. 99% of the time, the common Go programmer
       | won't need to write any generics. Instead, just focus on actually
       | solving the problem and manipulating the data like you would
       | normally. If you encounter a place where code is repeated and
       | complicated enough to be worth a new function, move it to one. If
       | you find yourself repeating multiple functions but with different
       | data types, turn that into one generic function.
       | 
       | Generics are an incredibly useful addition to the language that
       | I'll almost never use. Really to be more precise, Go has had some
       | generics this whole time: Maps, slices, arrays, and channels all
       | have type parameters, and have covered the vast majority of my
       | needs. There are a few times where I've wanted more general
       | generics, though:
       | 
       | - The sort and heap packages are rough to use. You need to
       | specify a bunch of nearly identical functions just to get them to
       | work on any custom type. The generic versions (not coming in
       | 1.8's standard library, iirc) will be much easier to use.
       | 
       | - Was writing an Entity-Component-System game for fun, and needed
       | a weird custom container. Turned to code generation, and really
       | that turned out to be necessary anyways because it did more than
       | any (non-metaprogramming) generics could do.
       | 
       | - We had one very complicated multiple Go routine concurrent data
       | structure that needed to be used for exactly 2 different types.
       | Others were writing the code, and very afraid of using
       | interface{}. This is despite there only being a handful of casts.
       | In reality if they caused a bug, it would be found immediately.
       | There's a strong hesitation around type safety dogma that isn't
       | risky in practice. Still, generics would've been the preference
       | here.
       | 
       | - I was parsing WASM files, and there's a common pattern for
       | arrays where it encodes the length of the array, then that many
       | objects in a row. It led to a lot of minor code repetition.
       | Replacing that with a generic function that took a function to
       | parse a single object, and returned the array of those objects
       | was a nice, but relatively minor win.
       | 
       | On the other hand:
       | 
       | I've never really been bothered by having to do sets like
       | map[int]struct{}. There was one case where I saw someone put set
       | operations out into a different library. I eventually found to my
       | dismay that the combination of how the set library was used, and
       | how it was implemented caused a performance critical part of the
       | code to be several orders of magnitude slower than it needed to
       | be. Had this code been more idiomatically inlined, this flaw
       | would have been more immediately obvious.
       | 
       | I really don't like seeing map/reduce/filter type functional
       | programming coming into Go usage. This type of code tends to need
       | more dramatic changes due to minor conceptual changes, more than
       | direct procedural code does. Also like the set example, how you
       | iterate and manipulate objects can have large performance
       | implications that using such functions hides away.
        
       | jamespwilliams wrote:
       | One annoying bit about Go's generics is that you can use type
       | parameters in functions, but not in methods.
       | 
       | So for example, maybe you'd want to write a Map function for the
       | Optional type in this article, which returns None if the option
       | is None, or calls a given function with the value of the Optional
       | otherwise.
       | 
       | You'd probably write it like this:                   func (o
       | Option[T]) Map[U any](f func(a T) U) Option[U] { ... }
       | 
       | But that doesn't work: "option/option.go:73:25: methods cannot
       | have type parameters"
       | 
       | The type inference is also a bit limited, e.g: let's say you have
       | a None method:                   func None[T any]() Option[T] {
       | ... }
       | 
       | And you call it somewhere like:                   func
       | someFunction() option.Option[int] {             if (!xyz) {
       | return option.None()             }             // ...         }
       | 
       | it isn't able to infer the type, so you have to instead (in this
       | case) write option.None[int]().
       | 
       | Generics is a super cool addition anyway though.
       | 
       | Edit: I just found
       | https://go.googlesource.com/proposal/+/refs/heads/master/des...
       | which has some details on why method type parameters aren't
       | possible.
        
         | kubb wrote:
         | There is another way, you can declare option as
         | type Option[T any] *T             nil is None             opt
         | == nil instead of IsNone()             func Some[T any](t T)
         | Option[T] { return &t }             *opt instead of opt.Get()
         | option.Map(opt, func(x int) double { return double(x) }) for
         | the monadic behavior
         | 
         | I wish there was type inference for function arguments, so that
         | you could write func(x) { return double(x) }. Maybe in a couple
         | of years the Go team could be convinced.
        
         | tubby12345 wrote:
         | >One annoying bit about Go's generics is that you can't use
         | type parameters in methods.
         | 
         | i haven't written go in a long time (generics would/could get
         | me to go back to it) but are you saying that functions can't be
         | generic? or is members here vernacular for class (struct?)
         | associated functions? i thought those were called "receivers",
         | which you mention further down. so it looks to me like you're
         | saying that functions can't be generic. to which i ask: wtf is
         | the point of generics when functions can't be generic...?
        
           | jamespwilliams wrote:
           | You can use type parameters in functions, but not methods.
           | Methods are functions which have a receiver, so:
           | // This is a function, you can use type parameters here:
           | func Foo[T any](g T) { ... }                  type bar struct
           | {}              // This is a method, you can't use type
           | parameters here:         func (b bar) Foo[T any](g T) { ... }
           | 
           | In the second case, "Foo" is a method which has a "bar"
           | instance as a receiver.
           | 
           | I've edited my original post to make it a bit clearer.
        
             | tubby12345 wrote:
             | so does this mean there are no generic structs in generic
             | go?
        
               | uluyol wrote:
               | You can do                   type X[T any] struct{}
               | func (x *X[T]) Method() {}
               | 
               | just fine. What you can't do is                   func (x
               | *X[T]) Method[T2 any]() {}
        
               | loopz wrote:
               | Not saying mixing OO and generics could never have any
               | merit, but.. Isn't a method just a function having an
               | object as first parameter. Does Go change this beyond
               | "syntactic sugar" somehow? Been a while from coding Go,
               | so interested to hear.
               | 
               | The rationale seems to me that generics be functions
               | first (ok, procedural), and not complecting it with
               | objects and OO too much, whatever that mix could mean..
        
               | klodolph wrote:
               | > Isn't a method just a function having an object as
               | first parameter.
               | 
               | Differences:
               | 
               | - Methods must be defined in the same package as the
               | receiver.
               | 
               | - Methods can be used to implement interfaces.
               | 
               | - Methods can be discovered dynamically by inspecting the
               | type of the receiver (either through reflection or with a
               | dynamic cast).
        
               | egeozcan wrote:
               | In other words, methods cannot _introduce_ generic types.
        
       ___________________________________________________________________
       (page generated 2021-12-16 23:00 UTC)