-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
typetraits: add toSigned, toUnsigned #18445
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
Conversation
1c54f03 to
a957025
Compare
changelog.md
Outdated
| Added `HoleyEnum` for enums with holes, `OrdinalEnum` for enums without holes. | ||
| Added `hasClosure`. | ||
| Added `pointerBase` to return `T` for `ref T | ptr T`. | ||
| Added `toSigned`, `toUnsigned`. |
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.
Where is the RFC? Who asked for these API extensions? We cannot simply add everything that is occasionally useful...
|
D seems to lack it too: https://dlang.org/spec/traits.html Is that enough of a reason not to include it? I mean, if it's the other way round and D offers something, we always need it too, right... |
that's not true. import std.traits
static assert(is(Unsigned!(int) == uint));
alias S1 = Signed!uint;
static assert(is(S1 == int));this API is totally reasonable to expect in typetraits. C++ also has it: https://en.cppreference.com/w/cpp/types/make_signed etc |
a957025 to
5a9288e
Compare
|
Nevertheless we need some rules for what to add to the stdlib. "X is useful and other languages also have it" is not good enough, it would be a superset of everything some other language has. "X is useful, we have used it ourselves in this place" is not good enough either, the API surface of Nim keeps growing and edge cases we don't have to have spec'ed out need to spec'ed out before it can become a public API. (For example, is |
5a9288e to
bb0ebf0
Compare
see last commit, i'm for now disallowing range because it's unclear what to do with It's a useful API, it's not like the implementation will have to keep changing (apart from maybe adding support for range), and it's the logical module where one would expect to find this. |
Lots of things are useful. That doesn't necessarily mean they should be added to the standard library. For these procedures in particular, I can't actually envision any real-world scenarios where they would be used. The situations where unsigned integers are typically most used are when interfacing with C, or when performing cryptographic/bit-manipulating operations. In both cases, one typically knows the data types they are converting both from and to. If someone does run into scenarios where these kinds of conversions are required often enough to warrant encapsulation into a procedure, the logic isn't difficult to write. In my view, functionality should only be added to the standard library if it is needed often enough, and is above a certain complexity threshold. The degree to which such functionality is already "tested" (such as if an external module were to be incorporated into the standard library) also plays a factor. Special circumstances notwithstanding, it's only when the sum of these factors is large enough, that incorporation into the standard library should be considered. |
what? no, unsigned ints have use cases beyond C interop. when sizeof(T) == 8:
type UT = uint64
elif sizeof(T) == 4:
type UT = uint32
elif sizeof(T) == 2:
type UT = uint16
else:
type UT = uint8by this: likewise, |
bb0ebf0 to
3f152b5
Compare
lib/pure/typetraits.nim
Outdated
| result = hasClosureImpl(fn) | ||
|
|
||
| from std/private/bitops_utils import toUnsigned, toSigned | ||
| export toUnsigned, toSigned |
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 is not a "type trait", it seems wiser to publish "bitops_utils" instead, somehow.
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.
D defines those APIs in std.traits
C++ defines in std::type_traits
and we already have APIs like distinctBase, elementType in std/typetraits; it's much simpler to have these APIs (type => type) in std/typetraits than to create a dedicated bitops_utils module or equivalent (we already have bitops, and toUnsigned/toSigned is a poor fit for bitops) whose scope would be unclear.
type traits don't just cover boolean properties of types, as evidenced both by what std/typetraits already contains, and by descriptions of C++ type traits, eg:
https://www.internalpointers.com/post/quick-primer-type-traits-modern-cpp
Type traits can also apply some transformation to a type. For example, given T, you can add/remove the const specifier, the reference or the pointer, or yet turn it into a signed/unsigned 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.
Can you move them to typetraits directly then?
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.
done
a51a448 to
a0adbb0
Compare
|
PTAL |
a0adbb0 to
0ea4448
Compare
a4db641 to
dbbd9a1
Compare
|
ping @Araq |
lib/std/private/bitops_utils.nim
Outdated
| template toUnsigned*(x: int64): uint64 = cast[uint64](x) | ||
| template toUnsigned*(x: int): uint = cast[uint](x) | ||
| template toUnsigned(T: typedesc[SomeInteger and not range]): untyped = | ||
| # copied/adapted from std/typetraits.toUnsigned to avoid a `system => typetraits` dependency |
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.
If you cannot use typetraits here, there is no need to copy&paste, you can keep the old version of bitops_utils.nim as it's at least shorter.
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.
done, mostly; kept the name castToUnsigned as toUnsigned is misleading (it casts instead of doing a conversion in traditional sense); also the way I'm doing it allows simplifying all call sites by avoiding to branch on whether the input is signed vs unsigned (as evidenced by the diff)
dbbd9a1 to
b2e4f08
Compare
|
PTAL |
In future work, we can improve how
nim doctreats re-exports, but until then nim doc still works (at the cost of an extra click) and the re-export is transparent for client code; this has been discussed elsewhere.note
this would've been a plausible alternative implementation:
with pros: uses generic caching instead of having to evaluate the when .. clauses at each call site at CT
cons: adds auxiliary symbol (seems minor con)
links