Proposal: Blank types instead of Generics for Go 2

271 views
Skip to first unread message

meta keule

unread,
Jul 23, 2017, 4:17:04 AM7/23/17
to golang-nuts

Hi,

here is a proposal for an alternative to Generics for Go2:

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

Please discuss!


mhh...@gmail.com

unread,
Jul 23, 2017, 6:05:42 AM7/23/17
to golang-nuts
if we could have a list of use case,
written in g1, with an explanation about why it can t be generalized,
we could check any proposal that at first it answers them,
then enter into more detailed study and proposals ?

I m reluctant to provide examples about concurrency,
i have some ideas of what functions i need,
i m not hot to write them...

At least here is some func i wish was generalized
- concurrentSync(sync func(...)..., concurrency int) (wrappedSync func(...)...., cancel chan struct{})

- concurrentAsync(async func(..., jobDoneSignal chan struct{})..., concurrency int) (wrappedSync func(..., jobDoneSignal chan struct{})..., cancel chan struct{})
(this sig is soooo long...)

- throttle (call a func at most once every D time.Duration)
     throttle(f func(...)..., d time.Duration, head bool) (throttledFunc func(...)..., cancel chan struct{})
- mustNorErr ?

then stuff like map.Each, slice.Each etc.

That being said, in
    func Add1(key $A, val $B, m map[$A]$B) {
        m[$A] = $B
        return
    }

It will trigger a runtime error if $A is of type []byte (met that error yesterday with an interface{} type).

Sooooo, as the bloat already exists with interface{}, is it something to keep or to remove ?
More generally at which extent runtime 42 errors are acceptable,
or should be used to compromise a prefect/ideal model in order to simplify/fix <something in the model> ?

Jesper Louis Andersen

unread,
Jul 23, 2017, 9:00:27 AM7/23/17
to meta keule, golang-nuts
On Sun, Jul 23, 2017 at 10:17 AM 'meta keule' via golang-nuts <golan...@googlegroups.com> wrote:

Hi,

here is a proposal for an alternative to Generics for Go2:


From a quick skim:

It looks like you are trying to discuss a combination of three things:

* universals
* type inference
* type variables

For each, it looks like you are placing some rather arbitrary constraints on these in order to make the system sound w.r.t. other Go features. I think much can be gained by splitting up the discussion into the handling of type variables and universal functions, if you want to go down this path.

Universals are a generalization which is possible whenever a function doens't depend on a particular type. For instance, in the function

func len(arr []int) int {
count := 0
for _ = range(arr) {
count++
}
return count
}

There is no dependence on the fact that the array is an 'int' so we could as well write 'func len(arr []$A) int' in your notation. Languages with (full) type inference can figure this out by making *all* types into metavariables and then look at what types variables must be, based on type constraints. In the above, the metavar generated for '$A' will have no constraints which is why it can be generalized into an universal.

Type variables already exist in Go, but they are limited to built in structures of slice and map types. When we write []int, we really instantiate a type []$A into []int. Likewise for a map. If I construct my own type, for a RB-tree say, then I can't get at this generalization but must use interface{}. For each use I would have to build my own wrapper API in order to make the usage of my RB tree type safe.

Any generic proposal must address the two above problems at the least. I must also address how to mix those into the existing interface concept, which will give rise to how generics will work in Go if added.

Another viable path is to stratify generic instantiations to be at the package level. That is, you can declare a

package foo<T>

for some abstract type T. Use of the package by import will expand T into a concrete type. A more ambitious solution would generalize this by noting that each package has a *signature* which is the set of exported types and functions. We'd like to then say

functor foo<P : Sig>

to say that foo is a module level function (a functor) which takes a package P as a plug-in with signature Sig. Generic programming is then handled by plugging in concrete implementations at the package level rather than at the module level. For a concrete type 't' you can simply refer to P.t in the foo package/functor.

All of these ideas already exist and have working precedents in Standard ML or OCaml.

My hunch is that most constrained attempts at generics are likely to fall short in usage examples. That is, there is no easy way out: you have to address the problems up front. In Go, you'd have to handle the interface concept and generics. But my intuition is that this is possible because interfaces look a lot like existential types which have good support in the litterature together with the abstractions mentioned above.

Egon

unread,
Jul 23, 2017, 9:40:11 AM7/23/17
to golang-nuts
2. You didn't mention all the cons your proposed methods has
3. You didn't mention prior art of golang proposals, i.e. how it fixes the problems in them.
4. You are missing demonstrations of what problems exactly you are targeting with this proposal.

+ Egon

meta keule

unread,
Jul 24, 2017, 3:51:55 AM7/24/17
to golang-nuts
I've updated the proposal to include ideas of how feature parity with generics could be reached.
Reply all
Reply to author
Forward
0 new messages