Dnia 2020-12-31, o godz. 13:15:00
"K. Alex Mills" <k.alex.mi...@gmail.com> napisaƂ(a):

> At a glance, this feels to me like it is more complicated than the current
> generics proposal. That said, it also seems very original so I have to give
> credit there.

It is just the other kind, as I see it. You know, it was born just yesterday :)
I forbade matching on the result parameter type, but I think it might
be part to match, too. See example at the end.
 
> This proposal seems to put the responsibility for monomorphizing generic
> code onto the programmer. I'm not sure why it would be simpler than
> monomorphizing generic functions directly, which we can do today.

It is the author of the generic function that bears the burden - yes. 
But thousands others using her older code need not even know that some day
it went generic and "legacy" signature went to the one of cases. Ie. I as an 
author
may start with plain Go function, then make it generic just when I need same
functionality for other but similar set of parameter types. See Min(x, y) 
example in
the playground document.

> I guess under this proposal all the monomorphized versions would be able to
> share similar function signatures and we can't do that today.

All call sites to the identifier share the signature shape, ie number of 
parameters, yes.

> I do worry that in case you have two generic parameters, this proposal
> would seem to require NxM cases to be explicitly written out.

No. Not that much explicitly. See lines 23..32 in the playground document.

Eg. the "underlying" type syntax lets us write cases that encompass way many of 
NxM
combinations in a few branches of the Signature switch, while analysis (read 
time)
stays linear: find declaration, find case that matches your parameters, read.
Also, if given set of parameter types matches a case signature, compiler will
instantiate (or even reuse in the far future) respective case's code. Otherwise
compile error will tell us that our current types here are not served (yet).
Or that we eg. need to give a type to the untyped constant we used.

Below float to int conversion example deals with any call site that call us 
with any int type
that happens to be based on int32, int64 as "int" and float32, float64 "float". 
Func ToInt
returns result of the x parameter type and an ok flag set to true if conversion 
went ok 
If there was an overflow, func ToInt returns respective MaxInt and false.

Note that (for now) there is no match on the result parameter type, so the 
ToInt got
a parameter that might not be needed were result parameters matched too.
Such version is below, too.

// https://play.golang.org/p/T97kLYaHS9e
// negative numbers branch left out for brevity
func ToInt (x +T, y +U) (r +T, ok bool) {
                switch func.(type) {
                case func(x (int32), y (float64)) (r T, ok bool): fallthrough
                case func(x (int32), y (float32)) (r T, ok bool): // (type) 
underlying type of
                  lim := float64(math.Nextafter32(float32(math.MaxInt32+1), 0))
                        if float64(y) > lim { // Mmm, Is it ok? I should study 
IEEE754 more
                                return T(math.MaxInt32), false
                        }
                        return T(int32(y)), true

                case func(x (int64), y (float32)) (r T, ok bool): fallthrough
                case func(x (int64), y (float64)) (r T, ok bool):
                  lim := math.Nextafter(float64(math.MaxInt64+1), 0)
                        if float64(y) > lim {
                                return T(math.MaxInt64), false
                        }
                        return T(int64(y)), true
                }
                return // not reached
}

// if result parameters can be matched
func ToInt (f +F) (r +T, ok bool) {
                switch func.(type) {
                case func(f (float64)) (r (int32), ok bool): fallthrough
                case func(f (float32)) (r (int32), ok bool):
                  lim := float64(math.Nextafter32(float32(math.MaxInt32+1), 0))
                        if float64(f) > lim {
                                return T(math.MaxInt32), false
                        }
                        return T(int32(f)), true

                case func(f (float64)) (r (int64), ok bool): fallthrough
                case func(f (float32)) (r (int64), ok bool):
                  lim := float64(math.Nextafter(float64(math.MaxInt64+1), 0))
                        if float64(f) > lim { // Mmm, Is it ok? I should study 
IEEE754 more
                                return T(math.MaxInt64), false
                        }
                        return T(int64(f)), true
                }
                return // not reached
}


> That feels like a lot of work as compared to the current proposal, in which 
> the
> compiler can inspect the callsites and automatically generate only the
> binary code needed to satisfy the types in use.

This is true also for the Signature switch - it is compiler that picks pieces 
of code
according to the rules (case signatures) set by the programmer. It certainly
might be more work for the author of the generic code but for the readers
the Go's clarity is preserved, IMO. 

Not to mention that more work means also less abuse ;).

Nonetheless, it is just an ad-hoc idea stem from the partisan fights I read 
past year.
One to be looked at in leisure time and exercise on the paper, if at all :)

Happy New Year!

-- 
Wojciech S. Czarnecki
 << ^oo^ >> OHIR-RIPE

-- 
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/20210101062911.39633675%40xmint.

Reply via email to