6 ms·
Generic Methods in Go 1.27
- tancop 2mo ago> Go’s interface system works at runtime. The specific type of a value passed into an interface parameter is resolved while the program runs. This dynamic dispatch clashes with generics being resolved at compile time. What if the compiler generated both vtable and monomorphized variants for each method? Most calls would use the static version but places that need it like interface generics call the virtual method.
- saturn_vk 2mo agovtables still need types, and a generic method that is not yet instantiated will not have them
- masklinn 2mo agoThe problem is that your vtable would have to have a monomorphised copy of the generic method for each possible instance, this requires whole program analysis just to generate the interface — and even then I would not be surprised if you could generate calls which the compiler was not able to relate to the interface — and then you get to the potential size explosion of your vtable as it has to hold an unbounded number of methods. Note that despite having much stronger static semantics and much weaker reflection than Go Rust has the exact same limitation: a trait method with a non-lifetime generic parameter is not dyn-compatible. C++ is the same, a template member function (generic method) can’t be virtual (dynamically dispatched).
- EdSchouten 2mo agoGo is often thought of as a successor of C. C doesn't have methods, only global functions. From my perspective, Go added methods primarily so that you can use them in combination with interfaces. Given that interfaces don't support generic methods, I'm personally not convinced that this feature was worth adding.
- munificent 2mo ago> From my perspective, Go added methods primarily so that you can use them in combination with interfaces. They also give you a limited form of overloading. Without methods or overloading, you end up in the situation that C and Scheme are in where every operation on a data structure has to redundantly have the data structure in its name like: list_clear(my_list); queue_clear(my_queue); map_clear(my_map);
- kune 2mo agoIn Go you would methods for that: my_list.Clear(), my_queue.Clear() and my_map.Clear(). Now you can define a Clearer interface, which has only the Clear method. That allows you to write a function clearAndLog(item Clearer) and it will work with the list, queue and map.
- munificent 1mo agoYes, that's my point. Go doesn't have overloading by parameter list signature. But you can have methods with the same name defined on different types, so there is a sort of overloading or namespacing based on the receiver type. Methods give you that.
- wasmperson 2mo ago> Without methods or overloading, you end up in the situation that C and Scheme are in Well in C at least we now have this: #define clear(s) _Generic((s) \ ,struct list: list_clear \ ,struct queue: queue_clear \ ,struct map: map_clear \ )(s) clear(my_map); clear(my_list); clear(my_queue); ...although it turns out the other nice thing about methods is automatic namespacing.
- deleted 2mo ago[deleted]
- so-cal-schemer 2mo agoI just want to leave this here: SICP: 2.5 Systems with Generic Operations https://sarabander.github.io/sicp/html/2_002e5.xhtml https://sarabander.github.io/sicp/html/2_002e5.xhtml
- throwaw12 2mo agopeople working actively in "modern" Go codebases with generics, is it becoming like a Java/Spring kind of codebase? I understand why you might need generics, but I hate how Java ecosystem exploits it so much that, reading code becomes so difficult, because it was inherited from 10 levels of parent classes and in some cases Java Beans get created based on generic types and their parent classes are abstract classes.
- riobard 2mo ago> inherited from 10 levels of parent classes This is not (yet) a thing in Go. Go does not have classes and inheritance. Interface is more like duck-typing.
- Zanfa 2mo agoBut you can do equally horrible inheritance-y things with embedded structs.
- metadat 2mo agoYes, though it's non-idiomatic and in my experience, rare to encounter in the wild for anything you'd actually want to use.
- saturn_vk 2mo agoThat’s composition, and it’s not really the same as inheritance
- EspressoGPT 2mo agoThat's right, embedded structs in Go are far less common than inheritance in Java though.
- throw-the-towel 2mo agoI remember my coworkers having managed to write Java in pre-generics Go. The code had functions wrapped in functions wrapped in yet more functions, and interfaces only ever implemented by one type to replace the generics abuse. Life finds a way.
- DrCiphers 2mo agoSo Go is becoming Java?
- bmurphy1976 2mo agoMaybe. It's been what I wished Java was since the beginning, personally.
- saturn_vk 2mo agoAbsolutely. If you’ve never used Java or Go
- deleted 2mo ago[deleted]
- dekdrop 2mo agoTIL > However, Go’s interface system works at runtime. The specific type of a value passed into an interface parameter is resolved while the program runs.
- mknyszek 2mo agoThere's a little more nuance to this. The compiler knows the static type of any value placed into an interface value, and emits code to place a concrete type pointer (or itab pointer) into the interface value. You can see this in the disassembly. Later when you pass this value around and assign it to places, sure, there may be a different type depending on where the interface value came from. But the construction of these values is very much static. In this sense I wouldn't really call this "resolv[ing] while the program runs" unless you take a very broad sense of "resolution."
- masklinn 2mo agoThe construction of interface values is a very shallow mean and essentially irrelevant to the need for interfaces. Whereas the runtime resolution of operations performed through an interface (dynamic dispatch) is the primary purpose of and use care for interfaces, with the dynamic resolution of wrapped types (type erasure / downcasts / type switches) is the secondary one.