Generics Error - How to fix?

255 views
Skip to first unread message

da...@suarezhouse.net

unread,
Jan 1, 2021, 10:06:15 AM1/1/21
to golang-nuts
I thought I read the generics doc well but.. :-)  Help is appreciated:

I instantiate a generic table example here in line 41: https://go2goplay.golang.org/p/SadxA0khqx7 

Then I use it in lines 42 and 43.

The errors I get are below:
prog.go2:67:10: cannot use generic type Table[colA, colB, colC fmt.Stringer] without instantiation 
prog.go2:72:10: cannot use generic type Table[colA, colB, colC fmt.Stringer] without instantiation  

I am using the same table.  The method belongs to the struct so I would think should be considered instantiated and that I wouldn't have to repeat in lines 42 and 43 the types.

Is this a bug and it should infer since created in line 41 or what did I misunderstand in the doc?

Thanks in advance for the help!
David

da...@suarezhouse.net

unread,
Jan 1, 2021, 11:07:17 AM1/1/21
to golang-nuts
Thought if I went to the next step it would solve the first but didn't work.  This version is still cleaner than above once I can get some help on what I am doing wrong on the method call.  Updated version:  https://go2goplay.golang.org/p/b7ZrYd2zI17 

Side note: the methods are not using constraints as of now, just basic interface so more confusing on why it would expect those methods to require instantiation. 

Thanks!
David

roger peppe

unread,
Jan 1, 2021, 11:50:57 AM1/1/21
to da...@suarezhouse.net, golang-nuts
You need to declare the type parameters in the method definitions too.
Something like this works OK:

  cheers,
    rog.

--
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/9c999eee-3887-4d64-a41d-9402a1103a47n%40googlegroups.com.

da...@suarezhouse.net

unread,
Jan 1, 2021, 12:48:59 PM1/1/21
to golang-nuts
First of all --  awesome, thanks!!!  

Question 1:  the need for the additional typeOf function you added at the end, would that be needed in a future implementation or would that be deduced in the existing reflect.TypeOf in the future?

Question 2:  this experience has shown me a bit better that anything is possible but will take some getting used to.  Do you think having an "import generics" similar to unsafe as a separate in the actual "library" part of the code would resolve the concerns on user cleanliness?  This example I think shows me that if the library writer is careful the end user of the library would have a very minimal impact.  As a side note, I started playing with this to understand the other generics long thread going on :-)

Thanks again for solving this so quickly!!!
David 

Brian Candler

unread,
Jan 1, 2021, 12:50:15 PM1/1/21
to golang-nuts
If by "generics doc" you mean this one, then note:

"Generic types can have methods. The receiver type of a method must declare the same number of type parameters as are declared in the receiver type's definition. They are declared without any constraint."

That is, you can't define a method on plain Table, but you can define a method on Table[T1, T2, T3]

Without actually looking further into what your code is doing, that implies the following change:

func (t *Table[T1, T2, T3]) Add (a, b, c interface{}){
row := Row {colA: a, colB: b, colC: c}
append(t.rows, row) 
}

However that's also not right, because you're ignoring the return value from append (for more info read the blog posting on slices).  So:

func (t *Table[T1, T2, T3]) Add (a, b, c interface{}){
row := Row {colA: a, colB: b, colC: c}
t.rows := append(t.rows, row) 
}

The next problem is here:

func (t *Table[T1, T2, T3]) Print (){
fmt.Println("table format is: %v, %v, %v", reflect.TypeOf(t.colATemplate), reflect.TypeOf(t.colBTemplate), reflect.TypeOf(t.colCTemplate))
for row := range t.rows {
fmt.Println("%v, %v, %v", row.colA, row.colB, row.colC)
}
}

prog.go2:72:33: row.colA undefined (type int has no field or method colA)
prog.go2:72:43: row.colB undefined (type int has no field or method colB)
prog.go2:72:53: row.colC undefined (type int has no field or method colC)

Iterating over a slice with just one receiver variable gives you only the index.  This needs to be:

func (t *Table[T1, T2, T3]) Print (){
fmt.Println("table format is: %v, %v, %v", reflect.TypeOf(t.colATemplate), reflect.TypeOf(t.colBTemplate), reflect.TypeOf(t.colCTemplate))
for _, row := range t.rows {
fmt.Println("%v, %v, %v", row.colA, row.colB, row.colC)
}
}

This then breaks because t.rows is a slice of interface{}, not a slice of Row.  So I changed it to []Row.  Then fixing your Println's to Printf's, this gives https://go2goplay.golang.org/p/dAnPU_r0DpM and now it runs.

However, I think this still needs work. There should be no need for interface{} in Row; you should use generics for this too, and then your Table just needs to be a slice of Row[T1, T2, T3]

da...@suarezhouse.net

unread,
Jan 1, 2021, 2:56:24 PM1/1/21
to golang-nuts
I am wondering if this is also something easy for the more experienced folks here.

I took the example from Rog: https://go2goplay.golang.org/p/ZUAVncRrmZW

and tried to further "hide" the generics implementation on the library side by shifting the type instantiation into a function.  Only line 45 is the change here (previous line commented right above it for ref + in the library side the additional New function): 
New link with the changes here:  https://go2goplay.golang.org/p/mnc8yjaREwo

It feels functionally equivalent but I am getting an error in line 57 which has a generic attempt of the previous user side instantiation.  Is this possible in a slightly different way?

Thanks again!
David

robert engels

unread,
Jan 1, 2021, 3:21:15 PM1/1/21
to da...@suarezhouse.net, golang-nuts
I think the first version is far more understandable. You are declaring the Table and the types for each column - passing the type rather than instances of the type.

But here is the corrected code https://go2goplay.golang.org/p/VMFOcI91i4X

--
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.

da...@suarezhouse.net

unread,
Jan 1, 2021, 3:51:19 PM1/1/21
to golang-nuts
Wow, you are awesome!  I think this shows that generics "can be" fully hidden from view of typical users if desired.  In other words, the typical user wouldn't need to know they exist whereas more advanced users can leverage to minimize code duplication.  My question is:  should that be a goal or is it a non-goal? 

I see what you are saying in terms of might be less readable but if I put myself in the shoes of someone that has never seen anything about generics and this example works (which it does), potentially stating it as a goal would alleviate concerns on losing simplicity?  e.g. the library writer can always make the effort to hide the usage of generics if the intended audience is the general public vs. internal code while the internal code would still have the same compile time checks, reduction of duplication, etc.

Thoughts?

Thanks again!
David

robert engels

unread,
Jan 1, 2021, 4:49:48 PM1/1/21
to da...@suarezhouse.net, golang-nuts
But this/your code is not really using generics - it is using interfaces. The only type check is that the instances implement fmt.Stringer - this is very different than the previous version.

robert engels

unread,
Jan 1, 2021, 4:57:00 PM1/1/21
to da...@suarezhouse.net, golang-nuts
Sorry, the code works as expected - as I thinking of something else.

Ian Lance Taylor

unread,
Jan 1, 2021, 6:08:32 PM1/1/21
to da...@suarezhouse.net, golang-nuts
On Fri, Jan 1, 2021 at 12:52 PM da...@suarezhouse.net
<da...@suarezhouse.net> wrote:
>
> Wow, you are awesome! I think this shows that generics "can be" fully hidden from view of typical users if desired. In other words, the typical user wouldn't need to know they exist whereas more advanced users can leverage to minimize code duplication. My question is: should that be a goal or is it a non-goal?
>
> I see what you are saying in terms of might be less readable but if I put myself in the shoes of someone that has never seen anything about generics and this example works (which it does), potentially stating it as a goal would alleviate concerns on losing simplicity? e.g. the library writer can always make the effort to hide the usage of generics if the intended audience is the general public vs. internal code while the internal code would still have the same compile time checks, reduction of duplication, etc.
>
> Thoughts?

It is an explicit goal that it be possible for the user of a package
to not have to fully understand generics even if the package itself
uses generics. It's not entirely clear how well the design draft
succeeds at that, but I think it does reasonably well. There is some
brief discussion at
https://go.googlesource.com/proposal/+/refs/heads/master/design/go2draft-type-parameters.md#complexity
.

Ian

roger peppe

unread,
Jan 1, 2021, 6:39:12 PM1/1/21
to da...@suarezhouse.net, golang-nuts


On Fri, 1 Jan 2021, 17:49 da...@suarezhouse.net, <da...@suarezhouse.net> wrote:
First of all --  awesome, thanks!!!  

Question 1:  the need for the additional typeOf function you added at the end, would that be needed in a future implementation or would that be deduced in the existing reflect.TypeOf in the future?

It's not needed even now - I just included it because I think it's neat, and works correctly even when the type parameters are interface types.

Question 2:  this experience has shown me a bit better that anything is possible but will take some getting used to.  Do you think having an "import generics" similar to unsafe as a separate in the actual "library" part of the code would resolve the concerns on user cleanliness?  This example I think shows me that if the library writer is careful the end user of the library would have a very minimal impact.  As a side note, I started playing with this to understand the other generics long thread going on :-)

Personally, my main concerns about cleanliness are not about when packages are trying to minimise the generic API, but that people with experience in other languages bring a lot of the patterns they've previously used until Go.

Pervasive use of iterators is one such - I can easily see a future where people are criticising the Go compiler because it can't optimise some iterator-based solution enough.

Another concern is that people will use type parameters instead of interfaces for their efficiency properties rather than for correctness (for example by using a type parameter as an argument to a constructor rather than using an interface value, making the type harder to use because of the need to reference the type parameter every time the generic type is used). Many people seem to be aiming that the Go compiler will monomorphise all generic instances. I'm not sure that that's a good idea because it is likely to increase the pressure to use generic types even when there are sufficient usability disadvantages.

Instead, I am hoping that the cost of invoking a method on a generic value will be roughly comparable with that of invoking a method on an interface value, thus hopefully making it easier for people to choose to use the simpler non-generic solution without incurring too much relative performance overhead.

da...@suarezhouse.net

unread,
Jan 2, 2021, 6:05:44 AM1/2/21
to roger peppe, golang-nuts
Thank you!  My personal opinion from this small journey into this topic is what you all built here is very flexible and robust.  Are you all at the point of "perfect is the enemy of the good"?  What is the criteria that will define when this releases?

As I see it, if you use something like impact to...:
*  newcomers - Can be zero if no core library changes in the first release
*  existing users - same as above but does enable existing users to start leveraging where appropriate so may be a value add here
*  future maintenance -  ? not qualified to guess :-)  but if this is all that is really outstanding at some point it can just be improved in place I would assume and hence the Voltaire question

Look forward to seeing this in a release soon and thanks again for all of the insight!

David
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/D2RYwYj9KVM/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/CAJhgachPJ0Xt6E%2B54iatZaGVg2FWWk0i4E1%3DfomK%2B%2BaDCLitqw%40mail.gmail.com.

Sincerely,

David Suarez

Gallup Strengths Finder:  Achiever * Strategic * Relator * Ideation * Learner

https://www.linkedin.com/in/davidjsuarez/ 

Reply all
Reply to author
Forward
0 new messages