-
-
Notifications
You must be signed in to change notification settings - Fork 1.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
typetraits: add rangeof(T), a shortcut for low(T)..high(T) #15232
Conversation
This func returns a slice with the full range of type `T`, basically a shortcut for `low(T)..high(T)`. This is useful for verifying whether a value of one type can be converted to an another. The main use case for this would be as a sugar for the initial conversion between an ordinal and a `range` type, though it's flexible enough that it can be used for many other situations, like conversions between int/uint of different sizes.
@@ -183,3 +183,32 @@ since (1, 1): | |||
|
|||
type T2 = T | |||
genericParamsImpl(T2) | |||
|
|||
func rangeof*(T: typedesc): Slice[T] {.inline, since: (1, 3, 5).} = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be named sliceof
and then it's ready to go as far as I'm concerned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sliceof
sounds weird IMO. Example:
assert 42 in sliceof(Positive):
It's hard to understand that statement without knowing what slices are in Nim, and even then you'd need to whip out the docs just to know what sliceof()
does.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well it returns a Slice[T]
so I have to know Nim's slice type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but arguably, comparing between these:
assert 42 in rangeof(Positive)
assert 42 in sliceof(Positive)
The former does a better job at saying "I want to make sure that 42 is within the range of type Positive
".
You can know Slice[T]
and still have to stop to look at the docs because sliceof(type)
just sound alien.
I think it is not suitable to add it to the standard library because it is difficult to name and has fewer use cases. |
Can you elaborate? |
As highlighted by a comment in https://forum.nim-lang.org/t/8188, enum:s are also a kind constrained integer that would need a similar facility - they're not representable as a range though since they might have holes. |
just a matter of changing signature to func rangeof*(T: typedesc): Slice[T]
=>
func rangeof*(T: typedesc[Ordinal]): Slice[T] = |
```nim | ||
import typetraits, strutils | ||
|
||
type | ||
AllowedPort = range[1024..65535] | ||
|
||
proc setupServer(port: AllowedPort) = | ||
# Setup a webserver... | ||
discard | ||
|
||
stdout.write("Please enter a port [1024-65535]: ") | ||
stdout.flushFile() | ||
let port = stdin.readLine().parseInt() | ||
|
||
if port in rangeof(AllowedPort): | ||
setupServer(AllowedPort(port)) | ||
else: | ||
stderr.write("Invalid port number") | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since when do examples go into the changelog?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a trend started by Nim 1.2 where we put examples of new syntactic sugar to the change log.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
example belongs where the API is defined, not in the changelog (DRY, plus follows current convention, plus changelog is too big already for adding such examples)
## setupServer(AllowedPort(port)) | ||
## else: | ||
## stderr.write("Invalid port number") | ||
low(T)..high(T) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I honestly think this is too short to justify it's own stdlib function, people can just write that themselves.
that doesn't help solving this issue for |
ordinal enums are ordinal |
that is a point that's true, yes... but not all enums are ordinal. |
|
no, it wouldn't - that was the essence of my initial comment: there's opportunity to create an API with broader support to cover safe conversion of more nim types that could be evaluated. |
#15212 covers this |
i don't understand the essence of your comment then, what would your API be for holey enums. With #18044, that API even becomes O(1) (even for holey enums). And by simply exposing a private-for-now symbol, int => Enum (even with holes) that doesn't raise can be done in O(1) as well after that PR, which solves the problem raised in https://forum.nim-lang.org/t/8188, without raising, and in O(1) instead of O(n) |
## # Setup a webserver... | ||
## discard | ||
## | ||
## stdout.write("Please enter a port [1024-65535]: ") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
example is way too complex especially for this simple API; good examples should illustrate semantics and edge case, that's it
docs say:
but this fails, see 3 cases below: import std/typetraits
for a in low(int8)..high(int8): discard # ok
for a in rangeOf(int8): discard # ok
type A1 = low(int8)..high(int8) # ok
type A2 = Slice[int8.low..int8.high]
# type A3 = rangeOf(int8) # Error: expected type, but got: rangeof(int8)
# type A4 = range[rangeOf(int8)] # Error: expected range
var x1: array[int8.low..int8.high, int]
var x2: array[range[int8.low..int8.high], int]
# var x3: array[rangeOf(int8), int] # Error: ordinal type expected so I agree with @Araq, noteit also fails with: arguably, the compiler should work with that definition at least, but it hits one of those buggy parts of compiler (array + range generic instantiation of the 1st argument) that's full of hard-coded special cases. Maybe this PR could be revisited once range + array work with this definition. |
This func returns a slice with the full range of type
T
, basically ashortcut for
low(T)..high(T)
. This is useful for verifying whether avalue of one type can be converted to an another.
The main use case for this would be as a sugar for the initial
conversion between an ordinal and a
range
type, though it's flexibleenough that it can be used for many other situations, like conversions
between int/uint of different sizes.
This is an alternative to #15212 in which runtime values and types are
now properly separated with an explicit function call.
Closes #15212.