-
Notifications
You must be signed in to change notification settings - Fork 17.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
proposal: math: Reflect, Least, Greatest #60274
Comments
Why would this one be less heavyweight? What would it do differently? |
Unlike switch T.(type) {
case ~uint8:
return uint8Type Even if it needs to resort to skullduggery and reach-into-the-runtime or teach-the-compiler-a-trick magic to work around the current inability to write that in Go itself, I'd imagine that it would still retain the essence of being a simple lookup. |
At this point, math contains almost all float64 stuff. I think if there's a package with generic math stuff, it should go in a new package, and the old math package can be considered implicitly "math/float64s". Maybe math/numeric.Types/Reflect()/Min()/Max(). |
If it needs a new package, that's fine by me. math does already have untyped constants for all the Min/Max values, though. |
I created https://github.com/zephyrtronium/number as a demonstration of the proposed |
First, super cool! Second, I do think even if the abi remains stable I'd feel uneasy relying on a third party dep making those kind of assumptions and playing those kinds of shenanigans. Third, I think regardless of implementation having it part of the stdlib is worthwhile to have it in a centralized place, especially one that can be updated in lockstep if something like, for example 128 bit ints get added to the language. |
Here's a small example of use. It provides a fully correct generic variadic min. It works correctly even if func Min[T notComplex](vs ...T) T {
min := math.Greatest[T]()
if math.Reflect[T]().Float() {
// T = ~float32 | ~float64
// so these are always lossless conversions
min := float64(min)
for _, v := range vs {
min = math.Min(min, float64(v))
}
return T(min)
}
for _, v := range vs {
if v < min {
min = v
}
}
return min
} |
You can't switch on a generic type like that. If you're proposing a language change ("With language support ...") you should say so. |
@fzipp I was saying that IF there were such a language change the code would, then, in that hypothetical scenario, just be a big ole switch. |
@zephyrtronium a more concrete argument against relying on the internals is that alternate Go implementations may not use the same representation internally but if it's in std each such implementation can wire it in appropriately. |
If it does get its own package, it could hold the various number-y constraints, too. Something like: package number
type Signed ~int | int8 | ⋯
type Unsigned ~uint | uint8 | ⋯
type Integer Signed | Unsigned
type Float ~float32 | ~float64
type Ordered Integer | Float
type Complex ~complex64 | ~complex128
type Type Ordered | Complex
type Kind uint
// A bunch of methods on Kind
func Reflect[T Type]() Kind
func Least[T Ordered]() T
func Greatest[T Ordered]() T That gives you a lot of what you need to write generic numeric algorithms in one place without filling math up with a bunch of definitions. |
A nice to have would be (using the definition of Type in the previous post, not the one in the first post) func Convert[S, T Type](T) (v S, lossless bool)
func CanConvert[S, T Type](T) (lossless bool) that returns true if converting back to |
@jimmyfrasche I feel like the actual proposal here is drifting substantially, so I can't tell whether I'm +1. It might be to everyone's benefit to update the title and first post with exactly the API you're suggesting. |
Sorry. Reflect/Least/Greatest are the main thing. I'm fine for those going in math. If they go in their own package then that package could be a good place to put the numeric constraints as well. The Convert/CanConvert functions are semi-related functionality that seem like a good fit with Reflect/Least/Greatest, wherever those end up. I'll think about how best to clear that all up. |
Can you clarify, for a float, is Least math.Inf(-1) or minus math.MaxFloat32/64? I don't think it matters too much which, just think it should be documented. |
|
updated the proposal |
Related |
Overlap with #50019 that proposes just Greatest/Least (under different names) and contains some useful and relevant discussion |
Reflect returns a Kind bitset that provides information about the properties of a numeric type. The bool returning methods correspond with the constraints and Size returns 8, 16, etc. Since this is about the properties of the type not its identity
Reflect[int]() == Reflect[int64]()
on platforms where int is 64 bits.Least (Greatest) return the element that is
<=
(>=
) every element in T. For example,Greatest[float64]()
ismath.Inf(0)
,Least[uint]()
is 0, andGreatest[int16]
ismath.MaxInt16
.Convert performs the conversion between numeric types S and T and the boolean reports whether the conversion was lossless, returning false if there was any truncation or wrapping.
Future versions of the language may allow
Reflect
to be written using type switches but this would still provide a more convenient interface.For convenience, I've assumed #52427 is accepted and that
Unsigned
,Signed
,Integer
,Float
, andComplex
have been moved into package math.I have also assumed that these additional constraints are defined:
The
Ordered
constraint is similar to that in packagecmp
except that it does not include~string
. The package qualification should be sufficient to disambiguate.If this api is too much or too different for math, it, and all the constraints, could go into a new package,
math/number
or the like.The text was updated successfully, but these errors were encountered: