> No support covariance or contravariance. Maybe I am on shaky ground in terms of my understanding but doesn't this mean, for instance, that if I have two interfaces, Foo and Bar, and a third composite interface, FooBar, which consists of Foo and Bar, that a function with a generic parameter T constrained by Foo would not accept a type that implements FooBar? If i am incorrect, where does this come into play?
I've actually be doing some reading on this lately! I'd love a chance to try and explain it to someone. So covariance / contravariance has to do with subtyping and parameterized types. If a type T' is a subtype of T that means that T' fulfills the responsibilities of T and can be used anywhere T is used. Subtyping for parameterized types gets more tricky. For example []int is not a subtype of []interface{} (even though int is a subtype of interface{}), because you cannot use a []int anywhere you use a []interface{}. The important case being: you cannot add an interface{} to a []int, but you can add an interface{} to a []interface{}. The only subtype of []interface{} is []interface{}. So covariance is where a parameter to a parameterized type *can* accept subtypes. For example an immutable list would be covariant. ImmutableList(int) fulfills the responsibilities ImmutableList(interface{}). Contravariance is where a parameter to a parameterized type can only accept *super*types. For example functions are contravariant with respect to their input parameters. A Function(i interface{}) fulfills the responsibilities of Function(i int) Invariance is where a parameter to a parameterized type only accepts the specific type specified. As stated above slices are invariant. So my understanding is that in the current design doc all generic structs would be treated as invariant wrt their parameters (like slices) even if they could technically be treated as covariant or contravariant wrt their parameters without causing errors. I hope that helps! --Beka On Monday, August 17, 2020 at 10:13:45 AM UTC-7 jlge...@gmail.com wrote: > As someone who has spent a LOT of time in Rust, I really miss generics in > Go (Conversely, i miss the simplicity of Go. My personal favorite, > imaginary language would probably be Go + Generics + Sum Types and > destructuring) and so I am really excited to see this taking shape. > > That being said, here are some things that I personally think are less > than ideal (first world problems eh?): > > 1) Of the enumerated omissions, the ones that I think are really > unfortunate are, in order of importance, from my perspective: > > - No operator methods & no adapters - Doesn't this make generic types > sort of second class?. I think these features would be an elegant addition > to the language but I assume that there is a reason for their omission. > - No support covariance or contravariance. Maybe I am on shaky ground > in terms of my understanding but doesn't this mean, for instance, that if > I > have two interfaces, Foo and Bar, and a third composite interface, FooBar, > which consists of Foo and Bar, that a function with a generic parameter T > constrained by Foo would not accept a type that implements FooBar? If i am > incorrect, where does this come into play? > - No support for variadic type parameters. Rust gets around this with > hygienic macros and meta-programming. I am not a big fan of the level of > complexity/quirkiness involved with working around the lack of variadics > in > Rust. I hope to see them in Generics in Go one day. Otherwise, you will > probably end up api bloat full of functions differing only in the number > of > parameters supported. > > 2) I don't see syntax for directly applying multiple constraints to a > generic type. Is this achievable only via interface composition? > 3) And something I glossed over during the first reading, but is a bit sad > - Methods may not take additional type arguments. > > Also, in the area of ergonomics, here are some thoughts: > 1) Allow for separating out generic type declarations from constraints. > Rust allows you to split type parameter declaration from type constraints > via an optional `where` keyword which comes right before the body of the > entity. This is very helpful for readability, especially given complex > constraints. > 2) I personally don't think allowing multiple types to share a constraint > is worth not allowing unbounded types without the bulky "interface{}" type. > Is there some other simpler syntax that could be considered? Would a simple > {} be a parsing nightmare? What about '_' ? Something like `func Something > (type T _, U SuperUseful ) (a T, b U){...}` ? > On Monday, August 10, 2020 at 9:46:44 AM UTC-7 3cl...@gmail.com wrote: > >> I am trying to add my 2 cents here. >> >> >> I am sorry if my opinions have been mentioned. >> >> I personally prefer Round Brackets (parentheses). It is not about >> readability on symbols, but the way how I understand the logic of Type >> Parameters. >> >> >> >> I see Type Parameters as a way to describe how to "instantiated" a >> Declaration (Func/Struct) for being used. >> >> Considering the case of https://go2goplay.golang.org/p/JjA67w8ZvFu , the >> func `min` is asking for a `type` argument to be specified so it can work >> properly. Which means it is valid to code line L19 `m := min(int)` to >> initialize the func `min` with type `int`. >> >> If we try to read a Type Parameterized func declared in this way, it >> means the func `min` will first take a `type` argument to initialize it. >> then the second Round Brackets `(...)` put the arguments to call the func. >> >> However with Square Bracket, L19 of the case will not work, cause `m := >> min[int]` would mean taking an element from `min` on index `int`. (sure, >> min here is a Type Parameterized Func, not a slice) >> >> >> >> On the other hand, we can take an analogy of how Functional Programming >> (FP) works with funcs with multi parameters. (correct me if I am wrong). >> >> In FP, when a function take two arguments, say `f(a int, b string)`, it's >> actually interpreted as "A function called `f`, it will first take an >> argument `a` with type `int`, and return a function f2 which keep a copy of >> `a` and takes an argument `b` with type `string`". >> >> An example in Go is following: >> >> ```go >> func concat(a int, b string) string {} >> ``` >> >> is equal to >> >> ```go >> func concat(a int) (func( b string) string){ >> return func(b string) { >> a := a >> // DO THE ACTUAL WORK >> return >> } >> } >> ```` >> and when calling `concat()` with `concat(1, "2")`, is actually >> `concat(1)(2)` or `tmp := concat(1); result := tmp(2)` >> >> >> Taking this analogy back to the original Type Parameters proposal. We can >> think of a Type Parameterized func has to be called with a `type` being >> specified. The Type Parameterized func will return a typed version of it. >> Then we call it with the actual argument(s). >> >> With Square Brackets, it cannot be interpreted in this way IMO as the >> syntax is inconsistence. It only make it easier to read for declaring a >> Type Parameterized func, but not easier to make an instance of the func >> with type. >> >> >> On Saturday, August 8, 2020 at 12:02:51 PM UTC+2 Denis Cheremisov wrote: >> >>> > Have the authors considered the implications of requiring the `type` >>> keyword to use a generic type, not just at declaration time? Would this >>> open up more syntax possibilities, such as `var x T<type int>`? This might >>> be easier to read at the expense of five more characters of typing. It also >>> could unify declaration and usage syntax even more than the proposal. >>> >>> > This might be easier to read >>> >>> Square brackets are easier to read. They are larger and catchier to eyes >>> than lesser and greater signs used as brackets. And type-less syntax with >>> mandatory constraint is even easier and feels like a great match with the >>> rest of the language. >>> >>> >>> четверг, 6 августа 2020 г. в 22:25:19 UTC+3, Red Daly: >>> >>>> Have the authors considered the implications of requiring the `type` >>>> keyword to use a generic type, not just at declaration time? Would this >>>> open up more syntax possibilities, such as `var x T<type int>`? This might >>>> be easier to read at the expense of five more characters of typing. It >>>> also >>>> could unify declaration and usage syntax even more than the proposal. >>>> >>>> (Personally, I will accept any syntax. It's not realistic to expect >>>> this for go2, but I would prefer if go3 ditched the C-style syntax >>>> altogether in favor of a simpler, lisp-style syntax. Such a syntax would >>>> make it easier to introduce language features like this one. Macros and >>>> metaprogramming would also be much more straightforward for users to add >>>> useful abstractions to the language.) >>>> On Thursday, August 6, 2020 at 7:15:08 AM UTC-7 Mike Schinkel wrote: >>>> >>>>> Hi Russ, >>>>> >>>>> In general, I think the proposal is a really good one. I like that >>>>> you abandoned contracts as interfaces were just too similar, and >>>>> personally >>>>> I like the choice of square brackets. >>>>> >>>>> There are a few aspects I do not like — 1.) no zero value and 2.) lack >>>>> of covariance and contravariance — but perhaps those can be addressed in >>>>> the future? >>>>> >>>>> All in all, I think the team has come up with a really good approach >>>>> to generics, much better than the prior proposals. >>>>> >>>>> -Mike >>>>> >>>>> P.S. If there is one thing that piqued my interest about this thread >>>>> it was Geoff Speicher's suggestion of a "generic" keyword, assuming type >>>>> inference could be addressed. That approach would be even easier to >>>>> reason >>>>> about than the current proposal, I think. That said, the current >>>>> proposal >>>>> is very good if type inference can not be addressed in Geoff Speicher's >>>>> suggestion. >>>>> >>>>> On Wednesday, July 22, 2020 at 8:02:55 PM UTC-4 Russ Cox wrote: >>>>> >>>>>> So it sounds like everyone is in favor of the entire generics >>>>>> proposal and all the semantics, and all we have left to hammer out is >>>>>> the >>>>>> bracket characters? Do I have that right? >>>>>> >>>>>> Best, >>>>>> Russ >>>>>> >>>>>> >>>>>> >>>>>> -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/135aefda-322d-424f-9a53-756676271a91n%40googlegroups.com.