Skip to content
Go

The Arrival of Generic Methods on Types in Go 1.27

Published: Duration: 5:49
0:00 0:00

Transcript

Guest: Thanks so much for having me, Alex. It’s a great day to be a Gopher! I’ve been refreshing the release notes basically every hour for this one. Host: [Laughs] I bet! So, Leo, let’s start at the high level. We’ve had generics since 1.18. Why is this specific update in 1.27—generic methods—such a big deal? Why wasn't it there from the start? Guest: That is the million-dollar question. So, in 1.18, we got generic functions and generic types. You could make a `List`, right? But the problem was that the *methods* on that list couldn't have their own *new* type parameters. If you wanted a method that transformed your `List` into a `List`, you couldn't actually define that `U` on the method itself. You had to use a standalone function. It felt... incomplete. The Go team really wanted to get the implementation right without destroying compiler performance, and it took until 1.27 to really nail that "orthogonality," where methods can be just as flexible as functions. Host: Right, it felt a bit like a "workaround" culture started forming. I remember seeing people embedding structs or doing these wild type assertions just to get something that *looked* like a generic method. What was the "ugliest" workaround you had to use before this? Guest: Oh man, definitely the "Interface and Assert" dance. You’d pass in an `interface{}`, or `any` now, and then inside the method, you’d have this massive switch statement or reflection block to figure out what the caller actually gave you. It pushed all the errors to runtime. You’d ship the code, and then *boom*, a production panic because someone passed a string instead of an int. It felt very "un-Go-like" because we value that compile-time safety so much. Host: Exactly! So, let’s talk syntax. How does this actually look in Go 1.27? If I’m looking at my editor, what am I typing now that I couldn't type before? Guest: It’s actually pretty elegant. Imagine you have a receiver, like a struct called `Box`. Previously, your methods could only use `T`. Now, after the method name, you can add new brackets. So it looks like: `func (b Box) Process(input P)`. That `` is the new part. It’s a type parameter specifically for that method, totally independent of the `T` on the Box. Host: Oh! So the method gets its own "scope" for types. That is interesting! Does that mean the compiler has a harder time figuring out what `P` is? Do I have to explicitly tell it every time I call the method? Guest: That’s the "aha moment" for me—the type inference is actually incredibly smart. Most of the time, the compiler looks at the argument you’re passing into the method and just... figures it out. You don’t have to write `myBox.Process("hello")`. You just write `myBox.Process("hello")`. It keeps the call-site really clean. It’s that balance of "powerful but readable" that Go usually hits. Host: I love that. Actually, I was looking at an example earlier about a `Vector` type. Before 1.27, if I wanted to "Map" a vector of integers to strings, I had to call a standalone function like `Map(myVector, myFunc)`. But now? Guest: Now you can finally do `myVector.Map(myFunc)`. It sounds like a small cosmetic change, but for anyone who likes fluent APIs or object-oriented patterns, it’s huge. It makes the code discoverable. When you hit "dot" in your IDE, the `Map` method shows up right there. You don’t have to go hunting for a utility package. It makes the `Vector` feel like a first-class citizen. Host: That’s a great point. It’s about the developer experience. But let’s talk about the constraints. You mentioned `` earlier. Do we still have to use those interface constraints for these methods? Guest: Absolutely. All the rules for generics still apply. If your generic method needs to compare two things, you need the `comparable` constraint. If it needs to do math, you might need a custom interface. It’s still very strict, which is good. It prevents the "wild west" of generic programming where anything goes. Host: So, thinking about real-world struggles... library authors must be throwing a party right now. If I’m building a database driver or an event dispatcher, how does this change my life? Guest: Oh, it’s a game-changer for middleware and event systems. Imagine an event dispatcher where you have a `Publish` method. Before, you’d have to write a separate method for every event type, or use `any`. Now, you can have one method: `func (d *Dispatcher) Publish(event E)`. It’s type-safe, it’s one method to maintain, and it handles everything. It’s going to slash the lines of code in some of these big frameworks by 20 or 30 percent, easily. Host: Wow, 30 percent? That’s a lot of boilerplate going into the trash. Guest: Honestly, maybe more in some cases. When you look at how much code is just "boilerplate for type safety," it’s shocking. Host: You know, I can hear some of the "minimalist" Gophers in the back of my head saying, "Is this making Go too complex?" Does this move Go too close to something like C++ or Java? Guest: [Laughs] There’s always that concern, right? But I think the Go team has been very careful. They didn't just add this to be "fancy." They added it because the community showed them thousands of use cases where the lack of generic methods was causing real pain and bugs. It’s still Go—it’s just Go with fewer "hacks" required to do modern systems programming. Host: That’s a fair take. It’s about solving the problem, not just adding features for the sake of it. Now, for someone listening who wants to start using this today—or as soon as they upgrade to 1.27—what’s the one thing they should be careful about? Any "gotchas"? Guest: I’d say, don't over-genericize. Just because you *can* make every method generic now, doesn't mean you *should*. If a simple interface or a standard function works, stick with it. The "gotcha" usually comes in when you have deeply nested generic types and methods—it can get hard for a human to read, even if the compiler is fine with it. Keep it simple. Use it where it removes clear duplication. Host: "Just because you can, doesn't mean you should." That’s basically the Golden Rule of programming, isn't it? [Laughs] Guest: Exactly. Host: Well, Leo, this has been such an eye-opener. I’m actually really excited to go refactor some of my old collection utilities now. Guest: Do it! It’s surprisingly satisfying to delete those old standalone utility functions. Guest: My pleasure, Alex. Happy coding! Host: And thanks to all of you for tuning into Allur. If you enjoyed this episode, subscribe on Spotify or Apple Podcasts, and leave us a review. It really helps the show. I’m Alex Chan, and we’ll catch you in the next one!

Tags

Go Golang software engineering backend generics type inference compiler