HNNewShowAskJobs
Built with Tanstack Start
Generic Interfaces(go.dev)
10 points by Merovius 2 days ago | 5 comments
  • tapirla day ago

    > This idea proves to be surprisingly powerful when it comes to expressing constraints on generic functions and types.

    Disagree. IMHO, this idea is the root cause of why Go generics is so complicate but also restrictive at the same time. And it introduces significant challenges in implementation and design: https://go101.org/generics/888-the-status-quo-of-go-custom-g...

  • dlock1717 hours ago

    I didn't realize how important order was to type inference.

    Are there any real packages out there using these techniques?

    • Merovius16 hours ago |parent

      > I didn't realize how important order was to type inference.

      I was unclear, I'm afraid. You can reorder the type parameters, it just changes which of them you need to specify: https://go.dev/play/p/oDIFl3fZiPl

      The point is that you can only leave off elements from the end of the list, to have them automatically inferred.

      > Are there any real packages out there using these techniques?

      I think so far, the usage of generics for containers in Go is still relatively sparse, in public code. I think in part that is because the documentation of how to do that is relatively sparse. That is part of the motivation for the post, to have a bit of somewhat official documentation for these things, so they become more widely known.

      The standard library is just starting to add generic containers: https://github.com/golang/go/issues/69559 And part of that is discussing how we want to do things like this: https://github.com/golang/go/issues/70471

      That being said, I have used the pointer receiver thing in my dayjob. One example is protobuf. We have a generic helper to set a protobuf enum from the environment. Because of how the API was designed, that required a pointer receiver constraint.

      • dlock1712 hours ago |parent

        The automatic part was what I was referring to, yes. I didn't realize you wrote the article, thanks!

        The article mentions using the function version to implement all others, but also that the method version would be optimized better.

        Would the compiler be able to inline MethodTree's compare even though it's passed in as a function variable to node.insert?

        • Merovius5 hours ago |parent

          In practice, currently, that depends on inlining decisions. If the function taking the function (say `node.insert`) is inlined, then yes. There are also other optimizations, like escape analysis, that matter here: the compiler can prove that the arguments to `node.insert` only escape into the `cmp` passed in. That decision is kept as metadata on `node.insert` even if it is not inlined. So if you pass a method expression to it, it can actually look at that and decide that the arguments don't escape from it either and hence that they don't escape overall. Whereas if you pass a `func` field, it can make no assumptions.

          My larger point though, is that with the `func` field the compiler can't optimize things even in principle. A user could always reassign this field (if nothing else using `*t = *new(FuncTree)`). So the compiler has to treat it as a dynamic call categorically. If the `func` is passed as a function, then at least in principle, it can prove that this function can't get modified during the call so can make optimization decisions based on what is being passed to it. For example, even without inlining, a future compiler might decide to compile two versions of `node.insert`, one with general dynamic calls and one specific one for a specific static function.

          My philosophy when it comes to API decisions that impact performance is, not to make them too dependent on what the compiler is doing today, but just to take care there is enough information there, that the compiler can do an optimization in principle - which means it either will do it today, or we can make it smarter in the future, if it becomes a problem.