3 ms·
Good introduction. I have to agree with other commenters that the syntax leaves something to be desired. A lot of parentheses competing for attention. Perhaps
by atombender 6y ago
Good introduction.
I have to agree with other commenters that the syntax leaves something to be desired. A lot of parentheses competing for attention.
Perhaps we could take a leaf from the Modula-3 book — Go was influenced by Modula-2, which didn't have generics — and be more explicit in declarations. I feel this would be more in the tradition of Go.
For example, instead of
func Max(type T Comparable)(a, b T) T {
if a > b {
return a
}
return b
}
This could instead be enveloped by a "generic" declaration like so:
generic T Comparable
func Max(a, b T) T {
if a > b {
return a
}
return b
}
- loopz 6y agoWhile skimming, I find the article-examples largely unreadable compared to idiomatic Go. You'd almost require generic-aware syntax highlighting in order to grok complex syntax, which breaks normal readability. Experimenting with wrapping as you suggest, seems a good way to see if that separates concerns in syntax enough to make generics "fun again". Programmed for long time in C++ w/templates . Any and everything that avoids the hells of those syntax and compiler error/messages, could even be called innovative if hitting the right spots. I see generics as convenience, but only if the costs doesn't accumulate over time * complexity. Generics need to be something natural, not bolted onto a language, or sneaked in. Unlike precompiler defines, and templates to some degree. To that end, maybe it deserves its own nomenclature, form and space, to properly distinguish those special cases from more concrete cases of syntax. Just like we distinguish looping with "for".
- atombender 6y agoAgreed. To keep Go simple and keep it from descending into the kind of extreme generics that Rust practices (nothing wrong with it, but it seems antithetical to Go's simplicity), the idea behind my syntax suggestion is to think about monomorphization as an explicit concept. You're basically telling the compiler to generate new versions of the same function, or struct, or whatever. The mental challenge with just adding type parameters is that you're thinking of the type as generic, which creates "what colour is my code" distinctions; either types are generic or they're not. I had another syntax in mind that would reuse the "for" keyword: for type T: func Max(a, b T) T { ... } Both syntaxes work fine for other declarations; structs and methods, for example: for type T: type Atomic struct { v T } for type T: func (a *Atomic) Get() T { ... } Of course, you still need some syntax to specify types in expressions, but that's also solvable.
- loopz 6y agoParametric polymorphism should probably be very syntactically distinguishable from imperatively looping with "for", though you'd need constraints and multiple types for sure. The problem from the start with such kind of programming, is that once you start meta-programming, there's always a bunch of stuff you could be missing or adding to the implementation. Just right up to the point where you could be implementing or self-referencing the language in the meta-program itself, or vica versa. But doing this without adding too much complexity for normal everyday use, would either be genius or a failed attempt at keeping things easy. So I'm sure many are investigating all the use cases what the target should be. Though the end result should still be easy, readable and otherwise clearly distinguishable from other idioms of the programming language.
- irq-1 6y agoWith a 'generic' interface declaration we could remove the (type T) annotations. The compiler would still know what type parameters are needed (because they are used in the function prototype.) // generic works like an interface type T generic { comparable // generic allows additional constraints } // we know the type parameters by the use of T // (because T is generic type) func Same(a, b T) T { ... } // calls may still need to include the type parameters, // but type inference will generally make them unnecessary s := Same(type string)("hi","howdy") s := Same("hi","howdy")
- mseepgood 6y ago> This could instead be enveloped by a "generic" declaration like so What would instantiation of the function look like? With the current design it is maxInt := Max(int) which has a positional symmetry to the declaration.
- tandr 6y agoI will raise you with (type $T Comparable) func Max(a,b $T) $T { if a > b { return a } return b }
- tandr 6y agoInvocation maxInt := Max(1,2) maxUnk := (SomeType).Max(k,z) or maxUnk2 := Max@SomeType(k,z) or just maxUnk3 := Max(SomeType(k), SomeType(z))
- atombender 6y agoI like the idea of using special syntax to denote the type — $T signals that it is a higher-order placeholder. It means there's no ambiguity to the reader or the compiler. It also means that for a function that requires no type constraints, nothing more is needed: func WorksWithAllTypes(val $T) { ... } I don't like the type constraint syntax, though. I think it could be done like this: func Max(a, b $T Comparable) $T { ... } The idea here is that we only need to annotate the first instance of $T; all others will implicitly share the same type constraint.
- tandr 6y agoI posted semi-coherent thoughts on golang-nuts [1], but the message got completely ignored as for constrains, say if we use decorator, then since T has to adhere to one interface only, func Max from your example could become func Max(a, b $Comparable) $Comparable { // ... } [1] https://groups.google.com/forum/#!topic/golang-nuts/Rp3yUUy2nS8 https://groups.google.com/forum/#!topic/golang-nuts/Rp3yUUy2...