Dnia 2020-12-31, o godz. 13:15:00
"K. Alex Mills" <
k.alex...@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!