67 comments

[ 4.5 ms ] story [ 534 ms ] thread
I can not wait to never have to type interface{} again.
Sad thing is that there is always a bunch of whining in any thread about 1.18 with people complaining about how much generics are going to ruin the language. I cannot wait for this release either, getting a proper set of data structures and concurrency libraries will be worth their weight in gold.
Some things are just really painful to do in Go: merging maps, drilling into a JSON structure, checking if an element exist in a slice.

Hopefully generics alleviates some of this boilerplate.

I haven't used Go in a while, but those don't sound particularly hard. Isn't searching for an element just a for loop?
Rereading the same loop more than once is not a good use of time. A generic function can be named and reused forever.
When I was writing Go I used to write little helper functions named "findThingy" that just wrapped a single for loop. A typical module might have a few of them. It wasn't hard to read and it wasn't that big a deal. I think the boilerplate from error handling hurts readability more.

It will be nice not to have to do that, though, if I get back to Go again.

I'm particularly excited to have all the patterns from the slice tricks wiki page[0] shipped as a standalone package. (I'm not sure why the slices package doesn't include any of the good stuff...) Understanding those patterns requires internalizing the relationship between slices and arrays, which is important but too high of a bar for a simple, safe in-place filter.

[0]: https://github.com/golang/go/wiki/SliceTricks#additional-tri...

What's quite sucky is that they will remain as standalone functions and not member functions, so you can't chain them (e.g. slice.Sort(...).Filter(...).Reduce(...))`. Not sure why golang is resistant to adding member functions to types.
Why not just get a “pipe” operator added to the language instead? Many functional programming languages already have one.

https://docs.microsoft.com/en-us/dotnet/fsharp/language-refe...

No need to alter the type system of the language, while it’s clearly a syntactical improvement you’re looking for.

I (sadly) can't imagine that getting through the language modification process, somehow, though it certainly would solve this particular problem! If we're looking for things that Go could usefully take from functional languages I'd personally start with the much lower-hanging fruit of some guarantees about mutability of structures, though.

(ps: Hi, Ed!)

My guess is that compilation time could be increased, which would let Go in the same boat as Rust or C++. I suspect every nice or must-have feature you add to a language, you must take the choice between deal with it in runtime or compilation time. Not adding features, no choice to take.
It shouldn't affect compile times though. golang compile times arealready in a similar ballpark to Java (if not slower) for large codebases.
To be fair, I am really excited for generics. However I do think the lack of the is the major reason go is such a readable language. Not being able to hide complexity behind types of types of types really ends up making code easier to follow.

I'm excited and anxious about generics in go.

Isn't interface{} similar to void * - the king of hiding types?
Yes, but it's a bit like Rust's `unsafe` in that reaching for it first is not a great practice. There's usually a better way.

Using interface{} where you truly don't know and can't predict the data being sent to you is mostly something that libraries (like encoding/json) have already handled, so I don't have to interact with it much directly.

I think generics are going to have the biggest impact in adding effortless type safety to all kinds of libraries, though.

I really don't come across this in most projects I read and learn from.
Not sure golang is readable compared to other more expressive statically typed languages like Java and C#.
Definitely is for me and I used to only use Java for years.

You can potentially test this for yourself by opening two large open source projects in each language and trying to figure out an issue from their issue tracker.

> Sad thing is that there is always a bunch of whining in any thread about 1.18 with people complaining about how much generics are going to ruin the language.

FWIW I think their complain even if not totally objective still have more weight as compared to non-users who say "I will use Go only when it has real generics/error handling/sum types/21st century features blah..blah.."

That depends on what the goal of Golang is. If they are happy with their current level of success, then sure.

If not, there are a lot more non Golang programmers out there than there are current Golang programmers.

Sometimes there are tools that we have to use if we want to stay at current job, so it is nice when they actually update themselves into modern times, switching job everytime there is something we dislike isn't a viable long term career path.
(comment deleted)
The resistance to adding generics to Go is a strong signal that the Go community has a serious problem.
He's talking about how Go 1.18 comes with a new "any" keyword, which is an alias to interface{}. Obviously there will still be uses for interface{}/any in your code, you just won't have to type interface{} anymore as you will be able to type any instead. This has nothing to do with generics.
Now you can focus on if err return err instead.

I wanted to like go for its crossplatformness, compile speed and relatively small memory usage while still being more practical than C++.

But not having generics and having to constantly check for errors was the two big things that made me bail.

Just to clarify, I don't want exceptions, I just want some language mechanism that changes err, value to be errOr<value>, which if passed to any function while an error will just propagage that to the return value of the function.

Maybe for extra sugar something like errOr<value> | valueToUseIfError. This makes the code nice and thight, mean that I don't have to declare variables to give them one value to pass into the arguments of the next function and still perserve all the nice properties of Go.

Also a nice cross gui library would be nice, but that is a lot harder. Still 20 years on the best cross gui library that compiles once and runs anywhere is Java...

> Now you can focus on if err return err instead.

Yes that is indeed the next most-frustrating thing about Go! In the last Go language survey (https://go.dev/blog/survey2020-results), about 90% of people wanted generics and 60% of people want better error handling. So, one down, one to go.

Modern languages like Zig and Rust show how you can do "errors as values" way better. Zig has error returns and stack traces built in, there's no reason Go has to be so impoverished here.

Is the RC any better than the beta when it comes to having `~/sdk` hardcoded as the location for Go's files?
I'm pretty sure ~/sdk is only used if you install Go versions using `go install golang.org/dl/<version>`
Is there a ternary operator yet?
No and there likely never will be:

https://go.dev/doc/faq#Does_Go_have_a_ternary_form

That's what they said about generics, and yet here we are.

edit: Wrong, see below

That's not true at all. Go core team always thought of adding generics in Go but Go core team couldn't reach a consensus on any proposed implementation and design for generics into Go, until this design.

https://go.dev/blog/why-generics

(comment deleted)
It's unfortunately misguided in my opinion. With a ternary operator you can initialize in one line, e.g.

    x := val ? foo() : bar()
Versus

    var x Type // now this is default initialized, which may or may not be a valid state for your program
    if val {
        x = foo()
    } else {
        x = bar()
    }
Honestly, I'd be fine with it being for initialization only (like the walrus operator)
How about f(a ? b : c, d, e)?

The go alternatives are too horrible to even contemplate, but here goes:

  if a {
     f(b, d, e)
  } else {
     f(c, d, e)
  }
or

  var tmp WhatFuckingTypeIsThisAgain
  if a {
     tmp = b
  } else {
     tmp = c
  }
  f(tmp, d, e)
It's hard to say which one is worse, but there is no doubt that the C version is "unquestionably easier to read."
my gut reaction was "no, that's exactly why they don't want these sorts of constructs" but the alternative (only allowing it in init statements) is worse I think. Only allowing in init statements is how you end up with the c++ initialization mess.

Re; your example, what about

    tmp := a ? b : c
    f(tmp, d, e)
Even in C++ that's likely how I'd write it.
Or make if… an expression instead of a statement.

Go core are very smart people so I’m sure they have their reasons, but my Lisp-addled brain can’t understand why you’d ever want statements instead of expressions with potentially discarded values.

Works great in Rust, but almost everything is an expression there.

I sadly don’t see it getting added to Go.

I agree with this. The limited location I find that I really miss ternary operations is initialization.

  v := if foo() {
    7
  } else {
    11
  }
But this means {} blocks now have values, which is weird in a C derivative. Of course, one could do

  v := func() int {
    if foo() {
      return 7
    } else {
      return 11
    }
  }()
but... that's kind of awful.
As best I can tell from the history books, the creator of Go, Ken Thompson, was responsible for inventing the ?: syntax (although the ternary concept is older). As such, there is probably nobody more familiar with what you propose than the Go team, so there may be some wisdom in the choice to actively not include it in Go.

   x = bar()
   if val {
       x = foo()
   }

Is both shorter and functionally more equivalent with the ternary example.
I did think of this, but left it out of the original post to keep it shorter. It is functionally better, but in terms of reading code, I find it easier to keep initialization blocks together and linearly scoped; the optional branch means I have to actually figure out which branch is being taken. That's definitely in the personal preference area though

I'd still rather a ternary over any of the above options though!

But you execute bar() when you don't need it. At best it's wasteful, at worst bar() actually is sendNuke().
Nope, that's incorrect. When val is true both functions are called.
I like to do it this way

  x := func() Type {
      if val {
          return foo()
      }
      return bar()
  }()
I've used that one in C++ quite a lot for const initializing variables that have awkward initialization steps, and it's probably my favourite of the options, but it's still nasty; having to declare the return type of the function removes one of my favourite things about golang!
This is supposed to be ... easier to read than `x := val ? foo() : bar()`? Really?
(comment deleted)
I don't write Go code but I admire them for sticking to their guns to not include it. Having had to decipher nested ternaries in the past, it's not something I want to have to think about again.

Python has some interesting shortcuts too, like being able to do `if 1 <= number <= 10:` to do chained comparisons but I much prefer the longer hand syntax. I have a solid amount of Python experience but no formal math background beyond HS Algebra. I often don't see this shorthand method to compare a range but when I do I always have to stop and decipher it.

I know this thread isn't about Python but I think it falls in line with this conversation. A language that sticks to slightly more verbose syntax for the sake of crystal clear clarity is very appealing.

just because someone can abuse a language feature doesn't mean you should bar every responsible programmer from using it.
Yeah, but there are other languages that support the idea of there being many different ways to do something and also give you a lot of rope to either hang yourself or create "clever" solutions (this isn't a bad thing btw, besides Python I also really like Ruby too).

I think we should respect language creators to keep a clear vision on their language, this way the audience who uses it can either strongly love it or hate it. If you try to do everything and cater to everyone then you'll end up with a worse result IMO.

It's the same way with music. You wouldn't expect a deathcore band to release a country album because a small portion of folks were interested in that, it would alienate their true fans and would likely leave the band internally not liking that decision. If you want to listen to a different style of music then you can pick a different band or genre.

>The new compiler -asan option supports the new go command -asan option.

How is ASAN used in a memory-safe language like Go? Is it useful only if I do uintptr shenanigans?

So far in the betas the generics support has been really great, some issues with inferring the types of functions but otherwise going to be a welcome addition to the language.
Looking forward to a STL library of Go after generics is official.
Are the famous and acclaimed generics included in this new version?
One step closer to CLU, finally.