Live data from Hacker News

Go 1.27 Interactive Tour

victoriametrics.com

151–160 of 219 posts

Re: Go 1.27 Interactive Tour

#151

"The best way to teach something new is to compare it to something the audience already understands." Could someone take the example, reduce it to a non-generic version for two types I DO understand, then show that with the new feature I can collapse them into the Box/Map example in the doc? I have 10+ years of Go experience and I can't make heads or tails of "(b Box[T]) Map[U any](f func(T) U) Box[U]"

    type IntBox struct { v int }
    type StrBox struct { v string }

    func (b IntBox) MapToStr(f func(int) string) StrBox {
        return StrBox{v: f(b.v)}
    }
(Please forgive any typos I made on mobile.)

It wasn't a great example because "Box" isn't really a useful type. But the point is that you no longer need to define a separate "MapToXXX" method for every type you might want to map to; now you can have just one type-generic "Map" method.

Re: Go 1.27 Interactive Tour

#152

One thing I think generics in Go is missing is the concept in Java. If you're taking a List[T] and all you want to do is to call list.size() then you don't care what type of list it is. In Java you can write a function which takes a List but in Go you have to write List[T] so then the question becomes what is T? You have to make the function (or type you're a method on) generic. If you make the type generic then ever…

You need this in Java because interfaces are explicitly implemented. You don't need this in Go because interfaces are structurally implemented. The way you spell "anything that has a method named Size which returns int" is interface{Size() int}.

Re: Go 1.27 Interactive Tour

#153

"The best way to teach something new is to compare it to something the audience already understands." Could someone take the example, reduce it to a non-generic version for two types I DO understand, then show that with the new feature I can collapse them into the Box/Map example in the doc? I have 10+ years of Go experience and I can't make heads or tails of "(b Box[T]) Map[U any](f func(T) U) Box[U]"

It's not a great example.

I think it's trying to show a mapping operation for a generic container where the container values are of one type and the mapping function is allowed to return a container with values of a different type.

Without generics, something along the lines of the following (with runnable example at https://go.dev/play/p/KHBI1uAhbO0):

  type MySlice []int

  // Map maps from a slice of ints to a slice of float64s.
  func (s MySlice) Map(f func(int) float64) []float64 {
     var out []float64
     for i := range s {
         out = append(out, f(s[i]))
     }
     return out
  }
From a quick search, this seems to be better explanation of this new 1.27 feature:

https://www.gopherguides.com/articles/golang-generic-methods

(That uses an example that seems similar in spirit to the Interactive Tour's example, but with a more useful type of a Stack[T] and corresponding explanation seem clearer.)

Re: Go 1.27 Interactive Tour

#154
post #115

Earlier quoted context omitted.

ML's parametric polymorphism

Go lets you constrain type parameters with interfaces. To do anything analagous in SML you have to use functors, which is substantially less convenient. I think people who refer to ML's parametric polymorphism in this context must really be thinking of parametric polymorphism in OCaml or Haskell.

You just do dictionary passing.

Re: Go 1.27 Interactive Tour

#155
post #115

Earlier quoted context omitted.

Go lets you constrain type parameters with interfaces. To do anything analagous in SML you have to use functors, which is substantially less convenient. I think people who refer to ML's parametric polymorphism in this context must really be thinking of parametric polymorphism in OCaml or Haskell.

You just do dictionary passing.

Like this, you mean? https://haskellforall.com/2012/05/scrap-your-type-classes

Fine in principle, but AFAIK it never really caught on because the ergonomics suck. Interfaces/traits/type classes do seem to be a popular feature across languages, for what it's worth.

Re: Go 1.27 Interactive Tour

#156

Earlier quoted context omitted.

No. This cognitive load is conceptual. You can't avoid it by using slightly different syntax.

I think the problem is that the Box / Map / any stuff and all the explicit declarations that Go requires makes it harder. In Haskell as well, you can let the compiler infer a lot of things but that doesn’t appear to be the case with this example. I’d want the compiler to infer things, but that - I think - is at odds with Go desiring a fast compiler, which I also understand.

I was about to mention Haskell as well, I feel like it also avoids this sort of cognitive load. Maybe it's something to do with the languages being designed as functional languages instead of languages with functional components.

Re: Go 1.27 Interactive Tour

#157
post #118

This: "(b Box[T]) Map[U any](f func(T) U) Box[U]" is the type of cognitive weight I was happy that Go avoided.

We often forget that our profession (computer programming) belongs to STEM. Some (like Go 1.0 :)) wish to think it is Arts & Humanities. The sooner we realize that yes, it is OK and actually expected to bear a cognitive weight of "(b Box[T]) Map[U any](f func(T) U) Box[U]" the sooner we get back to reality... :)

In terms of tooling, Go is one of the few languages which remembers that we are in STEM.

Re: Go 1.27 Interactive Tour

#158

This: "(b Box[T]) Map[U any](f func(T) U) Box[U]" is the type of cognitive weight I was happy that Go avoided.

It's not good Go code anyway. In Go you would use a for loop. Just because Go has generics nowadays doesn't mean you should abandon good taste and write ML/Haskell/Rust/C# in it.

Sure it's a bad example. But you can't simplify something like this without losing type safety:

    SortBy[T, K comparable](slice: []T, key: func (T) K)

Re: Go 1.27 Interactive Tour

#159

This: "(b Box[T]) Map[U any](f func(T) U) Box[U]" is the type of cognitive weight I was happy that Go avoided.

> (b Box[T]) Map[U any](f func(T) U) Box[U] Map method of b (of type Box[T]) that takes f (of type function that takes value of type T and returns value of type U (which could be any type)) and returns value of type Box[U] is defined as follows return Box[U]{v: f(b.v)} func[U any] b:Box[T].Map(f:func(T)->U)->Box[U]: return {v: f(b.v)} func[U any] Box[T].Map(f:func(T)->U)->Box[U]: return {v: f(this.v)} // maybe all of…

Map/Filter/Reduce is a bad example for an imperative language. But look at slices and maps packages, or the new proposal for container types. There are many good examples how generics are like salt to food. Another example is errors.AsType.
Post reply on HN