Can Generics match implementers of an interface?

341 views
Skip to first unread message

Mike Schinkel

unread,
Oct 21, 2023, 6:58:00 PM10/21/23
to golang-nuts
Recently I was trying to write a func using generics where I wanted to use a slice of an interface that would contain implementers of that interface and then pass those types to a generic function, but I ran into this error:

type MyStruct of MySlice{} does not match inferred type MyInterface for T

My code is complex so I wrote the simplest example for this email and here is part of that code:

type Suiter interface {
Suit()
}
func Append[T any](s []T, i T) []T {
return append(s, i)
}
func main() {
var s []Suiter

//CAN GENERICS SUPPORT THIS?
//s = Append(s, Clubs{})
//s = Append(s, Hearts{})
//s = Append(s, Diamonds{})
//s = Append(s, Spades{})

//VERSUS HAVING TO DO THIS?
s = Append(s, Suiter(Clubs{}))
s = Append(s, Suiter(Hearts{}))
s = Append(s, Suiter(Diamonds{}))
s = Append(s, Suiter(Spades{}))

for _, suit := range s {
fmt.Printf("Suit: %s\n", suitName(suit))
}
}
The full code is here in a playground.

Note: My example func Append() makes no sense in real use, I only use it as it should be an easily understood example to show the syntax I am trying to illustrate.

Question: Is there a way to write
Append() such that I can call Append(s, Clubs{}) instead of having to write Append(s, Suiter(Clubs{}))?

And if no, is there a chance that in the future Go generics will be able to support that level of type inference?

Dan Kortschak

unread,
Oct 21, 2023, 7:15:03 PM10/21/23
to golan...@googlegroups.com
The pre-generics language handles this case:
https://go.dev/play/p/jaJF7LTSVYe

Is there something about your real case that makes this not acceptable?

Mike Schinkel

unread,
Oct 21, 2023, 7:44:44 PM10/21/23
to golang-nuts
No, that pre-generics case is not sufficient for my use-case.  

For my use-case I need to be able to use other types besides []Suiter such as []int, e.g.:

var n []int
n = Append(n, 1)
n = Append(n, 2)
n = Append(n, 3)
n = Append(n, 4)
for _, i := range n {
fmt.Printf("Int: %d\n", i)
}

See full code in playground.

Axel Wagner

unread,
Oct 21, 2023, 8:01:05 PM10/21/23
to Mike Schinkel, golang-nuts
This is purely a type-inference problem. If you explicitly instantiate `Append`, it works: https://goplay.tools/snippet/15RFAPFPl3y
Type inference is still relatively limited. It might become possible to at some point omit the instantiation. I think this might be "Inferring based on interfaces" in https://github.com/golang/go/issues/58650
Until then, it's expected that there will be some cases where you need to specify the types.

--
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...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/805dbd4a-e2a0-426e-b61f-45b9333803f5n%40googlegroups.com.

Mike Schinkel

unread,
Oct 21, 2023, 8:09:51 PM10/21/23
to golang-nuts
@Axel Wagner —

Thank you for adding clarity to this.

Yes, it would be nice if we could get this to be handled with better type inference. 

But unless and until then, we have our workarounds.

tapi...@gmail.com

unread,
Oct 22, 2023, 3:57:52 AM10/22/23
to golang-nuts
On Sunday, October 22, 2023 at 4:09:51 AM UTC+8 Mike Schinkel wrote:
@Axel Wagner —

Thank you for adding clarity to this.

Yes, it would be nice if we could get this to be handled with better type inference. 

It is hard to call such type inference better. That is too aggressive.

Mike Schinkel

unread,
Oct 22, 2023, 8:40:55 AM10/22/23
to golang-nuts
How so? 

Can you give an example scenario where it could cause unintended consequences?  Or some other negative?

-Mike

tapi...@gmail.com

unread,
Oct 23, 2023, 2:38:59 AM10/23/23
to golang-nuts
Sorry, I didn't look your full code.
I think the full code should work with Go toolchain 1.21.n.

tapi...@gmail.com

unread,
Oct 23, 2023, 3:01:47 AM10/23/23
to golang-nuts
On Monday, October 23, 2023 at 10:38:59 AM UTC+8 tapi...@gmail.com wrote:
Sorry, I didn't look your full code.
I think the full code should work with Go toolchain 1.21.n.

Aha, it actually doesn't. I'm surprised.

Victor Giordano

unread,
Oct 23, 2023, 6:20:28 PM10/23/23
to golang-nuts
Very interesting case.

As Alex says, if you "help" the compiler writing  the actual type parameter like `Append[Suiter](slice, suiter)` it works. I have seen this before in Java when generics comes into town... I guess with time golang team with time will improve the type inference engine... this also happens with typescript... perhaps is a common trait in evolution of language compilers.

Now if you allow me, I do appreciate that not using generics and using interfaces in your Append method things will work... I mean this... 
I know... probably it won't fit to your coding issues... but what I feel sometimes is that generics aren't necessary and we tend to make use. I don't know.. forgive me if I'm wrong... just an opinion.

Mike Schinkel

unread,
Oct 23, 2023, 7:53:14 PM10/23/23
to golang-nuts
Yes, I was surprised too.  It actually took me the better part of a day trying to get this to work before finally posting to the list.

It turns out that this limit was actually documented by Ian Lance Taylor back in February 2023:

https://github.com/golang/go/issues/58650

Look for the section entitled "Inferring based on interfaces."

Again, it sure would be nice it this were possible, if for no other reason than to keep others being as time-inefficient as I was while trying to figure it out. 

-Mike

Mike Schinkel

unread,
Oct 23, 2023, 7:58:57 PM10/23/23
to golang-nuts
Absolutely, some times generics are not needed. 

I actually don't find a need to use them that often which is probably why when I came across a use-case that really needed them I was so stumped as to how make it work.  Kudos again to Axel for helping me recognize my blindspot.

-Mike
P.S. BTW, regarding your "I mean this..." link, I already addressed why that was not sufficient for the use-case earlier in the thread. #justfyi

Victor Giordano

unread,
Oct 23, 2023, 9:21:49 PM10/23/23
to Mike Schinkel, golang-nuts
Yes Ineed Mike! Generics can be good and can be bad... perhaps just as the OOP inheritance.

And thanks Alex indeed! His answer was enlightening!

TD;DR; 
Just another personal feeling.

Prior to generics: with interfaces I live a happy life, I got all the generosity I shall need... if I wanna work with slices of interfaces I learn that I have to use the for range loop for converting each element of the interface's slice into the concrete type. I learned it from this article (Look for "Values of []T can't be directly converted to []I, even if type T implements interface type I").



--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/eD7207kM8zA/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/c62243c1-d6af-41c1-b64d-be7d59063576n%40googlegroups.com.


--
V
Message has been deleted

Victor Giordano

unread,
Oct 23, 2023, 11:38:59 PM10/23/23
to Mike Schinkel, golang-nuts
TD;DR;
Erratas: I mean, I got all the genericity (not "generosity") I need (without "I shall")

I'm sorry and please accept the amendment.
--
V

tapi...@gmail.com

unread,
Oct 24, 2023, 2:04:33 PM10/24/23
to golang-nuts
In the "Special situations" section of this article https://go.dev/blog/type-inference,
it is mentioned a bit on this.
My understanding of that chapter is, when choosing the inferred type argument,
the current priority is: name types > directional channel types > other unnamed types.

In the case of the current thread, there are two type argument candidates, both of
them are named types, so the type interference fails.

Maybe the priority should be: interface types > named types > directional channel types > other unnamed types.

tapi...@gmail.com

unread,
Oct 24, 2023, 3:01:19 PM10/24/23
to golang-nuts
My another surprise is that the below partial instantiation doesn't work.

s = slices.Insert[[]Suiter](s, len(s), Clubs{}) // not work
s = slices.Insert[[]Suiter, Suiter](s, len(s), Clubs{}) // works

Axel Wagner

unread,
Oct 24, 2023, 3:49:40 PM10/24/23
to golang-nuts
I think addressing this would sensibly include a rule to allow unifying two types, if one is assignable to the other (which, AIUI, we already do for directional channels).

It's possible that this can be confusing in some circumstances including composite types e.g. something like

func Append[T any](s []T, v ...T)
func main() {
    var (
        s []any
        v []io.Reader
    )
    s = Append(s, v...) // would infer Append[any] and then fail to compile because []io.Reader is not assignable to []any
}

But I can't really come up with an example where this is worse than the status quo. Or even where something that *could* compile with fully specified instantiation then doesn't compile with inferred arguments.

The situation also becomes significantly more complex if we take assignment context into account for inference. AIUI we currently don't and it is something I want.

I wouldn't want to confidently state that this is something we should or should not do.

--
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...@googlegroups.com.

Victor Giordano

unread,
Oct 24, 2023, 4:15:02 PM10/24/23
to Axel Wagner, golang-nuts
TD;DR: The above is just a stream of consciousness that I release in this place that I find appropriate for this purpose. Forgive me in advance.

This is the thing about generics... make the world a very complex place.. and I do wonder... ¿ What kind of problems can be solved by generics that can not be solved by interfaces? 
If the idea is to be minimalism... ¿why do you surrender to the temptation of generics?... ¿Does a language need generics to become better or is human temptation in its unfilled need to write less and less that invent generics...? ¿I'm the lazy one that rants for having to learn new types theory?

and After a few drinks: First Object class.... now interface{} struct... you both have everything... generics... keep it simple please... don't become Scala...

You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/eD7207kM8zA/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAEkBMfEWgAvSqqL5mSr-Nf%2B5P%2BNkOA%2BCSbt8fi%3DRuJYKiZfYVA%40mail.gmail.com.


--
V

Axel Wagner

unread,
Oct 24, 2023, 5:52:16 PM10/24/23
to Victor Giordano, golang-nuts
On Tue, Oct 24, 2023 at 6:14 PM Victor Giordano <vituc...@gmail.com> wrote:
TD;DR: The above is just a stream of consciousness that I release in this place that I find appropriate for this purpose. Forgive me in advance.

I find it inappropriate, pardon my bluntness. The use cases for generics are well documented. We have them in Go, since three versions. Please move on. If you want to improve the language, accept where we are right now and how we can best continue from here. Instead of pretending it is still 2+ years ago and we would still discuss whether to add them.

This thread in particular is not even a significant complication of them. It's about a comparatively mild, potential improvement on type inference. It's not about improving their expressive power in any way.

Victor Giordano

unread,
Oct 24, 2023, 6:11:04 PM10/24/23
to Axel Wagner, golang-nuts
Alex those were my opinion and my thoughts, as long as they don't harm anyone they can coexist in peace... in any case, your bluntness is pardoned and thanks for reading me. As I said before this is a feeling and it makes me feel good to release it, so allowing me to write this, is, at the bottom, allowing me to express freely and I'm thankful for that. 
--
V
Reply all
Reply to author
Forward
0 new messages