Usize trait expects u32?


#1

Hi the following code does not work on the stable branch :

let a  : usize = 4_usize;
let b   : usize = (2_usize).pow(a);

I do not see why pow expects an u32 here and not an usize ? I expect to be calling usize::pow there, isn’t it ?

And indeed, it seems like the definition of pow for usize takes a u32 as an argument, what is the reason for this ?

Thanks for your help!


#2

I think that’s just an artefact of the way the methods on integer types are defined. It uses a macro where the pow method has been hard-coded as a u32.

This means that all integers expect to take a u32 as the exponent, it’s even that way for i8 and u128.

It’d probably be more logical for all integers to use their unsigned variant as the exponent argument (u32 uses u32, i8 uses u8, etc), but fixing it now would break a lot of existing code and there was probably a good reason to do it that way in the first place.


#3

Should signed integers also take a signed exponent?
(Edit: that was a rhetorical question)

Simply put, the base and the exponent play entirely different roles, and there is no reason for them to be the same type. u32 is the type that people are generally encouraged to use for “laughably small” unsigned integers, and exponents certainly fit that bill; all meaningful pow operations on rust primitive types today could be done even with a u8 exponent.


#4

No, because strictly negative exponents always mean a result of 0 on integers (if defined).


#5

Thanks @Michael-F-Bryan & @ExpHP so it is because we expect on any platform u32 to be usually smaller than usize (ridiculously small).


#6

Hi, @antonin,

I’m puzzled by this on two fronts: a) on 32-bit systems (still fairly common), u32 won’t be smaller than usize–they’ll both be 32 bits, and b) what’s the implication if u32 is smaller than usize? I guess I’m not following the implied reasoning… (Personally, I’d have expected pow() to accept f64 or possibly usize; The u32 parameter surprised me as well).

Thanks in advance!


#7

Yes I wanted to restate it to make it obvious that u32 is not all the time smaller than usize, and see if there are more answers about that. I guess @Michael-F-Bryan 's explanation about an historical choice/design is accurate.


#8

It’s not u32 that’s smaller than usize.

It is the number 32 that is smaller than usize.


I spoke too quickly. What I mean is that, when I used the phrase “laughably small”, I was referring to the value of size_of<usize>(), which is never larger than 64, and places an upper limit on meaningful values for the exponent.

Edit: Allow me to leave no room for interpretation:

2u64.pow(64) // thread 'main' panicked at 'attempt to multiply with overflow',

Notice similarly how ::num::pow exclusively takes usize, because it works with BigInts whose value is bounded only by memory.


#9

@antonin @ExpHP thanks to you both. That is much clearer for me now.


#10

Thanks a lot @ExpHP ! I clearly misunderstood your previous message and have a much better understanding now.