[generics] how to constraint a type must be a map or a slice?

725 views
Skip to first unread message

T L

unread,
Jun 20, 2020, 9:16:39 AM6/20/20
to golang-nuts
.
Message has been deleted

T L

unread,
Jun 20, 2020, 10:13:55 AM6/20/20
to golang-nuts
I mean I don't care about the element and key types of the parameter type.

For a simple example, I want to define a generic function which prints the length of a container (do do some other things):

func Print(type T Container) (v T) {
   // ... do some things

   fmt.Println(len(v))

   // ... do some things
}

On Saturday, June 20, 2020 at 9:16:39 AM UTC-4, T L wrote:
.

Axel Wagner

unread,
Jun 20, 2020, 10:21:56 AM6/20/20
to T L, golang-nuts
I would assume it's

type MapConstraint(type K comparable, V interface{}) interface {
    type map[K]V
}

func F(type M MapConstraint(K, V), K comparable, V interface{}) (m M) {
}

Note that you are under no obligation to make use of a type-parameter if you don't need it.

--
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/4f42e5e9-f991-4ee7-a043-5350a62f787fo%40googlegroups.com.

T L

unread,
Jun 20, 2020, 11:03:03 AM6/20/20
to golang-nuts


On Saturday, June 20, 2020 at 10:21:56 AM UTC-4, Axel Wagner wrote:
I would assume it's

type MapConstraint(type K comparable, V interface{}) interface {
    type map[K]V
}

func F(type M MapConstraint(K, V), K comparable, V interface{}) (m M) {
}

Note that you are under no obligation to make use of a type-parameter if you don't need it.

I don't very understand this. Can a slice value be used as the argument of the F function?
 

On Sat, Jun 20, 2020 at 4:14 PM T L <tapi...@gmail.com> wrote:
I mean I don't care about the element and key types of the parameter type.

For a simple example, I want to define a generic function which prints the length of a container (do do some other things):

func Print(type T Container) (v T) {
   // ... do some things

   fmt.Println(len(v))

   // ... do some things
}

On Saturday, June 20, 2020 at 9:16:39 AM UTC-4, T L wrote:
.

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

David Finkel

unread,
Jun 20, 2020, 3:08:42 PM6/20/20
to T L, golang-nuts
On Sat, Jun 20, 2020 at 11:03 AM T L <tapi...@gmail.com> wrote:


On Saturday, June 20, 2020 at 10:21:56 AM UTC-4, Axel Wagner wrote:
I would assume it's

type MapConstraint(type K comparable, V interface{}) interface {
    type map[K]V
}

func F(type M MapConstraint(K, V), K comparable, V interface{}) (m M) {
}

Note that you are under no obligation to make use of a type-parameter if you don't need it.

I don't very understand this. Can a slice value be used as the argument of the F function?
For that, I think you'd need the interface to be:
type MapSliceConstraint(type K comparable, V interface{}) interface {
        type map[K]V, []V
}

I'm not quite sure how to eliminate the useless K type-param for slices, though.


Here's an almost working example:

It looks like there's a bug in the type-parameter constraint checking because in the above example code, I get:
type checking failed for main 
prog.go2:11:39: K does not satisfy comparable 

This, despite the type parameter definition literally requiring that K be comparable:
func genLen(type T MapSliceConstraint(K, V), K comparable, V interface{})(collection T) int {
        return len(collection)
}

(example without a main() to reduce clutter: https://go2goplay.golang.org/p/1gqiYuDELuI)
 

On Sat, Jun 20, 2020 at 4:14 PM T L <tapi...@gmail.com> wrote:
I mean I don't care about the element and key types of the parameter type.

For a simple example, I want to define a generic function which prints the length of a container (do do some other things):

func Print(type T Container) (v T) {
   // ... do some things

   fmt.Println(len(v))

   // ... do some things
}

On Saturday, June 20, 2020 at 9:16:39 AM UTC-4, T L wrote:
.

--
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 golan...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/4f42e5e9-f991-4ee7-a043-5350a62f787fo%40googlegroups.com.

--
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/f841c497-8c29-4f16-a027-2c446f1a94b6o%40googlegroups.com.

Axel Wagner

unread,
Jun 20, 2020, 3:50:43 PM6/20/20
to David Finkel, T L, golang-nuts
Maps and Slices don't have a lot of operations in common. In general, the only ones I can think of are
- `make(T, someInt)`, though it means *very* different things for both, so a generic function doing this is likely not super sensible
- `for _, v := range x`, though even this differs, as the order is not guaranteed to be deterministic for maps, but it is for slices
- `x == nil`, `len(x) == 0`

If you'd restrict the key-type of the map to be of integer type, there's one (?) more
- `x[i]` for the key-type. But only on the RHS, as it's not addressable for maps.

I might overlook something, but in any case, the set of operations a generic function could do with an argument constrained like this is extremely limited. I guess the most useful way to express the constraint would be

type SliceOrMap(type K constraints.Integer, V interface{}) interface {
    type map[K]V, []V
}

But really, given that this is such a useless constraint, I feel it's fine that it's hard to express nicely.

Ian Lance Taylor

unread,
Jun 20, 2020, 4:53:41 PM6/20/20
to David Finkel, T L, golang-nuts
On Sat, Jun 20, 2020 at 12:08 PM David Finkel <david....@gmail.com> wrote:
>
> Here's an almost working example:
> https://go2goplay.golang.org/p/qcdfl0tuHlb
>
> It looks like there's a bug in the type-parameter constraint checking because in the above example code, I get:
>
> type checking failed for main
>
> prog.go2:11:39: K does not satisfy comparable
>
> This, despite the type parameter definition literally requiring that K be comparable:
> func genLen(type T MapSliceConstraint(K, V), K comparable, V interface{})(collection T) int {
> return len(collection)
> }
> (example without a main() to reduce clutter: https://go2goplay.golang.org/p/1gqiYuDELuI)

Yes, that looks like a bug. Would you mind filing it in the issue
tracker? Thanks.

Ian

T L

unread,
Jun 20, 2020, 11:07:57 PM6/20/20
to golang-nuts


On Saturday, June 20, 2020 at 3:08:42 PM UTC-4, David Finkel wrote:


On Sat, Jun 20, 2020 at 11:03 AM T L <tapi...@gmail.com> wrote:


On Saturday, June 20, 2020 at 10:21:56 AM UTC-4, Axel Wagner wrote:
I would assume it's

type MapConstraint(type K comparable, V interface{}) interface {
    type map[K]V
}

func F(type M MapConstraint(K, V), K comparable, V interface{}) (m M) {
}

Note that you are under no obligation to make use of a type-parameter if you don't need it.

I don't very understand this. Can a slice value be used as the argument of the F function?
For that, I think you'd need the interface to be:
type MapSliceConstraint(type K comparable, V interface{}) interface {
        type map[K]V, []V
}

I'm not quite sure how to eliminate the useless K type-param for slices, though.


Here's an almost working example:

It looks like there's a bug in the type-parameter constraint checking because in the above example code, I get:
type checking failed for main 
prog.go2:11:39: K does not satisfy comparable 

This, despite the type parameter definition literally requiring that K be comparable:
func genLen(type T MapSliceConstraint(K, V), K comparable, V interface{})(collection T) int {
        return len(collection)
}

(example without a main() to reduce clutter: https://go2goplay.golang.org/p/1gqiYuDELuI)


Thanks for making this example.

However, it almost reach my upper limit understanding ability to get the implementation.
I looks some bad practices in using C++ template.

Is it good to add a Kind list constraint? For example,

type MapOrSlice interface {
   kind map, []
}
 
 

On Sat, Jun 20, 2020 at 4:14 PM T L <tapi...@gmail.com> wrote:
I mean I don't care about the element and key types of the parameter type.

For a simple example, I want to define a generic function which prints the length of a container (do do some other things):

func Print(type T Container) (v T) {
   // ... do some things

   fmt.Println(len(v))

   // ... do some things
}

On Saturday, June 20, 2020 at 9:16:39 AM UTC-4, T L wrote:
.

--
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 golan...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/4f42e5e9-f991-4ee7-a043-5350a62f787fo%40googlegroups.com.

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

David Finkel

unread,
Jun 20, 2020, 11:28:23 PM6/20/20
to Ian Lance Taylor, T L, golang-nuts

Ian Lance Taylor

unread,
Jun 21, 2020, 11:24:37 PM6/21/20
to T L, golang-nuts
We've already decided in this design draft that we are not going to
permit all possible constraints. Therefore, this is the kind of
question that needs to be answered based on experience using real
code. Do people want or need to write real code that permits
declaring that some type parameter is a map or a slice, without
knowing anything else about the type? I don't see how such
information would be useful at all. Without knowing anything about
the key or element types of the map/slice, it would be very difficult
to use such a type parameter in any useful way. And quite apart from
that, when is it useful for people to write a function that takes
either a map or a slice, but nothing else? We need real examples of
real code that people want to write, not theoretical ideas for code
that people might in theory want to write. Thanks.

Ian

T L

unread,
Jun 22, 2020, 11:49:00 AM6/22/20
to golang-nuts
One example is the above Print function example.
Another example I current get is to iterate and print
all the key and values of a container in a current format.
There should be more examples with this need I think.

Ian Lance Taylor

unread,
Jun 22, 2020, 1:25:33 PM6/22/20
to T L, golang-nuts
On Mon, Jun 22, 2020 at 8:49 AM T L <tapi...@gmail.com> wrote:
>
> One example is the above Print function example.
> Another example I current get is to iterate and print
> all the key and values of a container in a current format.
> There should be more examples with this need I think.

I want to stress that we want real examples of real code that people
want to write, not theoretical ideas for code that people might in
theory want to write.

Do you have a real program that uses both slices and maps where you
would want to have a generic function that prints the keys and values
of either a slice or map? When does that come up? When I ask that,
I'm looking for a real program, not the idea that somebody somewhere
might want to do that. I agree that somebody somewhere might want to
do that. But is it an important enough use case that we must handle
it in the first attempt at adding generics to the language? When
thinking about that, consider that one goal of generics is to permit
people to write their own container types, which will by definition
not be maps or slices. Should we be looking for some mechanism that
can print the keys and values of any container type? Why is it
important to handle the cases of slices or maps but not the case of
other container types?

Ian

T L

unread,
Jun 23, 2020, 11:33:53 AM6/23/20
to golang-nuts
I think this is a problem whether or not long tail matters for the generic design.
It might affect user happiness, I think, but it is hard to predict.

Ian Lance Taylor

unread,
Jun 23, 2020, 1:07:24 PM6/23/20
to T L, golang-nuts
It seems to me that we do not have to handle the entire long tail in
the first version of generics. Perhaps I am wrong about that.

Ian
Reply all
Reply to author
Forward
0 new messages