Live data from Hacker News

Go(lang): Robust generic functions on slices

go.dev

31–40 of 85 posts

Re: Go(lang): Robust generic functions on slices

#31
post #11

Earlier quoted context omitted.

If immutable and mutable slices are differently typed [2], it is natural to define two functions (say, `slices.Compact` vs. `slices.Compacted`) to handle each type, like Python `list.sort` vs. `sorted`. It should be natural to expect `slices.Compacted` to never alter its input, and any attempt to use a mutable version will be very explicit except for slicing [1]. [1] Especially given that the capacity is preserved by…

This sounds awful in practice having to memorize different functions for the same thing based on mutability of the thing.

Programming is hard and one can not destroy complexity, only move it; other news at 12.

Re: Go(lang): Robust generic functions on slices

#32

> func Index[S ~[]E, E comparable](s S, v E) int { After seeing this signature, I think that Go is giving up on it's simpleness principle.

what does the ~ do here anyway?

type Something []string

ensure that the underlying type is a slice

Re: Go(lang): Robust generic functions on slices

#34

> func Index[S ~[]E, E comparable](s S, v E) int { After seeing this signature, I think that Go is giving up on it's simpleness principle.

I was quite upset that they introduced generics. It is slow marching into C++ like look and feel and all the eyesore that it entails.

In C# I feel you needed generics because there was no resizable array without casting from object (the Pareto 80-20 use case) and later async and Task but I don’t think these problems apply to Go so it could have done without it (maybe!). Non userspace generics may be where it is at to ease suffering in places.

As a language design though Elm remains remarkably simple with parametric polymorphism (aka Generics) but it needs other design choices to do so. Elm is the Go of Haskell :-)

Re: Go(lang): Robust generic functions on slices

#35

Earlier quoted context omitted.

what does the ~ do here anyway?

type Something []string ensure that the underlying type is a slice

Why do you need a tilda for `S ~[]E`, but not for `E comparable`?

Both are type-constraining annotations, so why two syntaxes?

Re: Go(lang): Robust generic functions on slices

#36
I feel like I’m taking crazy pills. How are these APIs even remotely defensible?

    slices.Sort(s)          // fine
    slices.Compact(s)       // broken
    s  = slices.Compact(s)  // fine
    s := slices.Compact(s)  // broken (!!!)
    slices.Delete(s, …)     // broken
    s = slices.Delete(s, …) // fine
How is one intended to remember which functions require overwriting (due to invalidating) their input and which don’t? Why does the language make it so easy to render function parameters unusable upon return but impossible to enforce that they aren’t used afterward?

How on earth did it take twelve years for this “simple” language to make a function to delete elements from an array, with `s = append(s[:start], s[end:]...)` having to suffice until then? How on earth does the “better” API twelve years later have such a gaping footgun? This is a core type that quite literally every program uses. How have things gone so far off the rails that “setting the obsolete pointers to nil” is such an intractable problem for end users they had to add a new keyword to the language?

For other languages I see posts where weird language corner cases bring up challenging issues that really reinforce the idea that language design is hard. Rust—for example—has unsoundness issues in corner cases of the type system. But for go, it feels like there’s a constant stream of own goals on core areas of the language where the design should have knocked it out of the park. “Simple manipulation of arrays” just should not have this many footguns.

Re: Go(lang): Robust generic functions on slices

#37
post #35

Earlier quoted context omitted.

type Something []string ensure that the underlying type is a slice

Why do you need a tilda for `S ~[]E`, but not for `E comparable`? Both are type-constraining annotations, so why two syntaxes?

Guessing that E is the element, so is not a slice (or more accurately we don’t care if it is a slice or not!)

Re: Go(lang): Robust generic functions on slices

#38
post #35

Earlier quoted context omitted.

type Something []string ensure that the underlying type is a slice

Why do you need a tilda for `S ~[]E`, but not for `E comparable`? Both are type-constraining annotations, so why two syntaxes?

It is like S: where S = []E where E: comperable.

I like the way Rust has it a lot more but it is still imperfect and feels arbitrary in ways.

I find myself unsure where to put the templatization parameters and it doesn't feel perfectly symmetrical.

Unsure if impl MyType where T: X

is comperable to impl MyType Sometimes it needs impl MyType where T: X

Re: Go(lang): Robust generic functions on slices

#39
post #36

I feel like I’m taking crazy pills. How are these APIs even remotely defensible? slices.Sort(s) // fine slices.Compact(s) // broken s = slices.Compact(s) // fine s := slices.Compact(s) // broken (!!!) slices.Delete(s, …) // broken s = slices.Delete(s, …) // fine How is one intended to remember which functions require overwriting (due to invalidating) their input and which don’t? Why does the language make it so easy…

Without defending this API, the easiest way to go about avoiding bugs when working with slice mutating functions is to consider all those "fine" scenarios as not fine.

Always assume that only the return value of slice mutating functions are the valid reference and the old one always invalid. This is not always completely accurate, but it is very useful in that, it is also never "wrong".

Post reply on HN