1. 20

  2. 11

    So, for example, if you want to write a function that modifies a slice, you might instinctively write

    func modify[T any](in []T) []T

    This will take in any slice, but if you define a type like type MySlice []int when you call modify with a MySlice, you will get back a plain []int. The answer is to instead write

    func modify[S constraints.Slice[T], T any](in S) S

    This is significantly more of a pain in the ass to write, so I think a lot of code that doesn’t need to work with named types will end up using the simpler []T syntax instead.

    1. 5

      Agreed! However, there’s an open proposal under consideration that makes this a lot nicer, so hopefully it gets accepted. It will let you write constraints.Slice[T] as just ~[]T inline, so will look like this for your second version:

      func modify[S ~[]T, T any](in S) S
      1. 3

        I read the earlier version of that proposal and was very skeptical of it, but this version looks good. The point about interface{X} being equivalent to interface{interface{X}} is convincing that it’s a good idea.

        1. 2

          Interesting, thanks for the link!

          To clarify a bit for people (like me) who are roughly aware of the coming generics proposal in Go, but not deep in the trenches of all the discussions, syntax, and recent changes — IIUC:

          • func modify[S constraints.Slice[T], T any](in S) S — under other currently accepted (?) proposals is a “more ergonomic wrapper” (?) for arguably more verbose (yet IIUC syntactically correct as well?) syntax as below:
          • func modify[S interface{~[]T}, T any](in S) S; whereas:
          • func modify[S ~[]T, T any](in S) S — is the currently proposed shorter syntax for the above “expanded/verbose” syntax (in accordance with the current title of the proposal being: “allow eliding interface{ } in constraint literals”).

          Notably, the new proposal, after a tweak making it what it I describe above (vs. an earlier version), quickly got active interest from the Core Team, with a CL by them being promised, which I see as a good (though not 100%) prognostic for a solid chance of it being accepted, in this way or another (in particular, possibly leading to some other, surprising yet quite cool, improvement).

      2. 3

        One of the nicer things about Go is the excellent built in Go AST libraries, which allow you to write correct codemods quite easily. If this missing ~T constraint is an issue in dependencies I foresee a codemod tool to vendor and transform dependencies showing up quite quickly.

        1. 3

          Some of the mistakes of leaving out the ‘~’ will be found early, and I think adding it wouldn’t create API problems for existing users, so this may not be a big issue in practice. But I wish that the defaults were the other way around, so that you had to go out of your way to restrict generics to specifically those types with no derived types allowed.

          This is also the way it currently works for regular function parameters; using myFun(MyString("hello")) – where MyString is type MyString string and myFun accepts a string – is an error. The type constraints are essentially the same concept, but with extra steps, and it make sense to keep it consistent.

          Supporting func f(s ~string) and case ~string in type switches might be a good future enhancement. The latter one is mentioned in the type parameter proposal/spec.