Live data from Hacker News

How generics are implemented in Go 1.18

github.com

71–80 of 228 posts

Re: How generics are implemented in Go 1.18

#71

Earlier quoted context omitted.

The compile time issues for C++ are entirely because of the creaky header mechanism that doesn't permit efficient parsing. Generics have worked fine in Ada since its inception. Any modern language can adopt the same process of tracking a formal abstract interface that is parsed once and expanded into concrete code as necessary.

That's not true, Rust doesn't have those headers and has the same compile time issues as C++.

Rust has macros and an expensive type system though, and compilation is getting faster.

Re: How generics are implemented in Go 1.18

#72
post #28

Does Go support separate compilation? The approach sounds like a change in the implementation of a generic function (changing the gcshapes) could cause client code to break unless it is recompiled as well. What am I missing?

This is also true in C++ templates, and C macros for that matter.

Re: How generics are implemented in Go 1.18

#73
post #30
post #11

Earlier quoted context omitted.

The process of expanding genetic code into concrete code based on the types (monomorphizing) can also be an expensive process. At least, people in the rust world point to it a lot as a reason why some crates compile slowly. Monomorphizing multiplicatively increase how much code LLVM needs to process (and optimize). Mind you, C/C++’s ridiculous header system is probably still a much bigger issue. Especially because C+…

Increases compared to what? If you don't use generics and write the code for each type manually, you'll end up with exactly the same thing.

I often wonder about that - if I was going to write by hand I might end up extracting a simple interface, do some type coercion/promotion or some other trick to reduce the number of functions I need to write.

I read about how .Net does Generics at the VM level and was very impressed, a good compromise between C++ "macro expansion" and Java "type erasure", both of which seem extreme.

At the end of the day, though, when generics are present I stop worrying and just use List, List, List, etc. without a second thought. The compiler, VM or runtime can deal with it although I might get punished in some way.

Re: How generics are implemented in Go 1.18

#74
post #22

Something I haven't been able to pull up yet: what does the addition of generics do the `reflect` package? I assume it needs to be extended to deal with reflection through generics?

All types are concrete at run time, so, no it doesn't end up needing changes: https://go.googlesource.com/proposal/+/refs/heads/master/des... "We do not propose to change the reflect package in any way. When a type or function is instantiated, all of the type parameters will become ordinary non-generic types. The String method of a reflect.Type value of an instantiated type will return the name with the type argument…

Note that with this change, only "gcshapes" are static at runtime. Any other information reflection needs would have to come from the dictionary. That would bloat the dictionaries.

Re: How generics are implemented in Go 1.18

#75
post #62

By the way, are there any projects underway to produce a library of the most common basic template functions? I'm very much looking forward to unifying some of my most copy-pasted functions when 1.18 is out, but I would like to unify on a central library right away.

It's partially being done in the x/exp module to prototype it thoroughly before including it into the stdlib. See: * https://pkg.go.dev/golang.org/x/exp/constraints * https://pkg.go.dev/golang.org/x/exp/maps * https://pkg.go.dev/golang.org/x/exp/slices

Cool. I'd love to see this become part of the stdlib rather than competing external packages.

Re: How generics are implemented in Go 1.18

#76
post #46

Earlier quoted context omitted.

From the article you linked, those subdictionaries seem to support calling a function g[T1] inside a function f[T1, T2]. There’s a concept called polymorphic recursion, supported by languages like Haskell, which goes beyond that and allows using arbitrary derived types in a function, in particular, in recursive calks. My interpretation of the section in “non-monomorphisable functions” in the original article is that…

These "GC shapes" a lot like GHC's "runtime reps": https://hackage.haskell.org/package/base-4.16.0.0/docs/GHC-E... GHC allows recursion that is "polymorphic in the types" but "monomorphic in the runtime reps". There is no reason why Go shouldn't allow polymorphic recursion that is "monomorphic in the gc shapes" either, though they might not have bothered to allow it yet.

I think they do; the problem is that Go puts way less things behind a pointer than Haskell does. Every struct is its own runtime representation. If you change the example in https://github.com/golang/go/issues/48018 to use a pointer indirection, I think it should work.

Re: How generics are implemented in Go 1.18

#77
post #51

Earlier quoted context omitted.

It does have subtyping relationships via interface. It absolutely has subtypes in the co/contravariance. In theory, a slice of structs that implement an interface should be able to be used as a slice of that interface. But due to the implementation, that requires a full copy.

It’s not just a random implementation artifact. Since all slices in Go are mutable, it logically wouldn’t make sense to upcast them while keeping the reference. That would mean the ability to put other objects in the slice. Same for pointers. That’s a basic fact of type safety that people often get wrong. For example, the JVM famously allows upcasting arrays, with very surprising results.

Ah yes that's true it is mutable

But even an immutable list cannot be made covariant. Or, say, funcs.

Re: How generics are implemented in Go 1.18

#78
post #53

Earlier quoted context omitted.

It does have subtyping relationships via interface. It absolutely has subtypes in the co/contravariance. In theory, a slice of structs that implement an interface should be able to be used as a slice of that interface. But due to the implementation, that requires a full copy.

No it's not due to the implementation, it's due to the language specification: there is no general subtyping. You can see it this way: there is implicit syntactic sugar that creates an interface value (pointer + type info) when you assign a value of type T to a variable of type interface I where T implements I. This happens on variable assignment, function parameter bindings and return value bindings. A slice of Is i…

[deleted]

Re: How generics are implemented in Go 1.18

#79
post #50
post #47

Programming languages are lacking because they are too stuck in the "implementation plane" while trying to deal with lots of "system design" problems. Generics, traits, interfaces, union types and others are fundamentally targeted at giving developers more expressive power to describe the systems we are designing. We know there are many parts we could swap around, using different implementations, connecting some piec…

Right. Basically Go team is lacking big picture thinkers like this[1] 1. https://dilbert.com/strip/1994-12-17

Golang is my favorite language, and I really like the approach that the team takes. A few days ago I shared here some interesting comments from Griesemer on Golang enums.

But sure, let's not give any ideas or question anything ever again, someone might get offended.

Re: How generics are implemented in Go 1.18

#80

Earlier quoted context omitted.

I only occasional do language design / compiler writing projects, or work with compiler internals. Most people are really bad at estimating the implementation complexity and tradeoffs inherent in various language features. I'd say that C++ serves as a warning to others... think before you add features to your language, or you'll end up a total mess, like C++. Java and C# gave us some interesting and subtle lessons ab…

C++ still has the dubious honor of being the only language where I encountered code that I could not compile because my machine lacked enough memory. I'm sure that's possible in other languages, but the program I was trying to compile wasn't that complicated... It had just been written by someone who believed every concrete class needed an abstract interface it was implementing.

I see you haven't worked with the joy of gradle & modern Java development. By the time you stack up gradle, javac itself, proguard or for Android R8 which are basically required to fix the terrible bytecode javac produces, some annotation processors because WHY NOT, custom build plugins, etc... it gets big
Post reply on HN