Skip to content

Commit bf89b68

Browse files
committed
auto merge of #11664 : bjz/rust/identities, r=alexcrichton
`Zero` and `One` have precise definitions in mathematics as the identities of the `Add` and `Mul` operations respectively. As such, types that implement these identities are now also required to implement their respective operator traits. This should reduce their misuse whilst still enabling them to be used in generalized algebraic structures (not just numbers). Existing usages of `#[deriving(Zero)]` in client code could break under these new rules, but this is probably a sign that they should have been using something like `#[deriving(Default)]` in the first place. For more information regarding the mathematical definitions of the additive and multiplicative identities, see the following Wikipedia articles: - http://wikipedia.org/wiki/Additive_identity - http://wikipedia.org/wiki/Multiplicative_identity Note that for floating point numbers the laws specified in the doc comments of `Zero::zero` and `One::one` may not always hold. This is true however for many other traits currently implemented by floating point numbers. What traits floating point numbers should and should not implement is an open question that is beyond the scope of this pull request. The implementation of `std::num::pow` has been made more succinct and no longer requires `Clone`. The coverage of the associated unit test has also been increased to test for more combinations of bases, exponents, and expected results.
2 parents f8efde1 + 509283d commit bf89b68

File tree

9 files changed

+147
-162
lines changed

9 files changed

+147
-162
lines changed

src/libextra/uuid.rs

Lines changed: 14 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ Examples of string representations:
5757

5858
use std::str;
5959
use std::vec;
60-
use std::num::{FromStrRadix, Zero};
60+
use std::num::FromStrRadix;
6161
use std::char::Char;
6262
use std::container::Container;
6363
use std::to_str::ToStr;
@@ -158,9 +158,8 @@ static UuidGroupLens: [uint, ..5] = [8u, 4u, 4u, 4u, 12u];
158158

159159
/// UUID support
160160
impl Uuid {
161-
162161
/// Returns a nil or empty UUID (containing all zeroes)
163-
pub fn new_nil() -> Uuid {
162+
pub fn nil() -> Uuid {
164163
let uuid = Uuid{ bytes: [0, .. 16] };
165164
uuid
166165
}
@@ -423,24 +422,17 @@ impl Uuid {
423422

424423
Ok(Uuid::from_bytes(ub).unwrap())
425424
}
426-
}
427425

428-
impl Default for Uuid {
429-
/// Returns the nil UUID, which is all zeroes
430-
fn default() -> Uuid {
431-
Uuid::new_nil()
426+
/// Tests if the UUID is nil
427+
pub fn is_nil(&self) -> bool {
428+
return self.bytes.iter().all(|&b| b == 0);
432429
}
433430
}
434431

435-
impl Zero for Uuid {
432+
impl Default for Uuid {
436433
/// Returns the nil UUID, which is all zeroes
437-
fn zero() -> Uuid {
438-
Uuid::new_nil()
439-
}
440-
441-
/// Tests if the UUID is nil or all zeroes
442-
fn is_zero(&self) -> bool {
443-
return self.bytes.iter().all(|&b| b == 0);
434+
fn default() -> Uuid {
435+
Uuid::nil()
444436
}
445437
}
446438

@@ -521,24 +513,15 @@ mod test {
521513
use super::*;
522514
use std::str;
523515
use std::rand;
524-
use std::num::Zero;
525516
use std::io::MemWriter;
526517

527518
#[test]
528-
fn test_new_nil() {
529-
let nil = Uuid::new_nil();
530-
let nb = nil.to_bytes();
531-
532-
assert!(nb.iter().all(|&b| b == 0));
533-
}
534-
535-
#[test]
536-
fn test_zero() {
537-
let uz: Uuid = Zero::zero();
538-
let nz = Uuid::new_v4();
519+
fn test_nil() {
520+
let nil = Uuid::nil();
521+
let not_nil = Uuid::new_v4();
539522

540-
assert!(uz.is_zero());
541-
assert!(! nz.is_zero());
523+
assert!(nil.is_nil());
524+
assert!(!not_nil.is_nil());
542525
}
543526

544527
#[test]
@@ -619,7 +602,7 @@ mod test {
619602
assert!(Uuid::parse_string("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());
620603

621604
// Nil
622-
let nil = Uuid::new_nil();
605+
let nil = Uuid::nil();
623606
assert!(Uuid::parse_string("00000000000000000000000000000000").unwrap() == nil);
624607
assert!(Uuid::parse_string("00000000-0000-0000-0000-000000000000").unwrap() == nil);
625608

src/libstd/bool.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ use num::FromPrimitive;
4040
#[cfg(not(test))] use cmp::{Eq, Ord, TotalOrd, Ordering};
4141
#[cfg(not(test))] use ops::{Not, BitAnd, BitOr, BitXor};
4242
#[cfg(not(test))] use default::Default;
43-
#[cfg(not(test))] use num::Zero;
4443

4544
/////////////////////////////////////////////////////////////////////////////
4645
// Freestanding functions
@@ -309,12 +308,6 @@ impl Default for bool {
309308
fn default() -> bool { false }
310309
}
311310

312-
#[cfg(not(test))]
313-
impl Zero for bool {
314-
fn zero() -> bool { false }
315-
fn is_zero(&self) -> bool { *self == false }
316-
}
317-
318311
#[cfg(test)]
319312
mod tests {
320313
use prelude::*;

src/libstd/char.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ use str;
2222

2323
#[cfg(not(test))] use cmp::{Eq, Ord};
2424
#[cfg(not(test))] use default::Default;
25-
#[cfg(not(test))] use num::Zero;
2625

2726
// UTF-8 ranges and tags for encoding characters
2827
static TAG_CONT: uint = 128u;
@@ -449,15 +448,6 @@ impl Default for char {
449448
fn default() -> char { '\x00' }
450449
}
451450

452-
#[cfg(not(test))]
453-
impl Zero for char {
454-
#[inline]
455-
fn zero() -> char { '\x00' }
456-
457-
#[inline]
458-
fn is_zero(&self) -> bool { *self == '\x00' }
459-
}
460-
461451
#[test]
462452
fn test_is_lowercase() {
463453
assert!('a'.is_lowercase());

src/libstd/iter.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2872,6 +2872,12 @@ mod tests {
28722872
}
28732873
}
28742874

2875+
impl Mul<Foo, Foo> for Foo {
2876+
fn mul(&self, _: &Foo) -> Foo {
2877+
Foo
2878+
}
2879+
}
2880+
28752881
impl num::One for Foo {
28762882
fn one() -> Foo {
28772883
Foo

src/libstd/num/mod.rs

Lines changed: 76 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,59 @@ pub trait Orderable: Ord {
5050
/// Returns the number constrained within the range `mn <= self <= mx`.
5151
#[inline(always)] pub fn clamp<T: Orderable>(value: T, mn: T, mx: T) -> T { value.clamp(&mn, &mx) }
5252

53-
pub trait Zero {
54-
fn zero() -> Self; // FIXME (#5527): This should be an associated constant
53+
/// Defines an additive identity element for `Self`.
54+
///
55+
/// # Deriving
56+
///
57+
/// This trait can be automatically be derived using `#[deriving(Zero)]`
58+
/// attribute. If you choose to use this, make sure that the laws outlined in
59+
/// the documentation for `Zero::zero` still hold.
60+
pub trait Zero: Add<Self, Self> {
61+
/// Returns the additive identity element of `Self`, `0`.
62+
///
63+
/// # Laws
64+
///
65+
/// ~~~
66+
/// a + 0 = a ∀ a ∈ Self
67+
/// 0 + a = a ∀ a ∈ Self
68+
/// ~~~
69+
///
70+
/// # Purity
71+
///
72+
/// This function should return the same result at all times regardless of
73+
/// external mutable state, for example values stored in TLS or in
74+
/// `static mut`s.
75+
// FIXME (#5527): This should be an associated constant
76+
fn zero() -> Self;
77+
78+
/// Returns `true` if `self` is equal to the additive identity.
5579
fn is_zero(&self) -> bool;
5680
}
5781

58-
/// Returns `0` of appropriate type.
82+
/// Returns the additive identity, `0`.
5983
#[inline(always)] pub fn zero<T: Zero>() -> T { Zero::zero() }
6084

61-
pub trait One {
62-
fn one() -> Self; // FIXME (#5527): This should be an associated constant
85+
/// Defines a multiplicative identity element for `Self`.
86+
pub trait One: Mul<Self, Self> {
87+
/// Returns the multiplicative identity element of `Self`, `1`.
88+
///
89+
/// # Laws
90+
///
91+
/// ~~~
92+
/// a * 1 = a ∀ a ∈ Self
93+
/// 1 * a = a ∀ a ∈ Self
94+
/// ~~~
95+
///
96+
/// # Purity
97+
///
98+
/// This function should return the same result at all times regardless of
99+
/// external mutable state, for example values stored in TLS or in
100+
/// `static mut`s.
101+
// FIXME (#5527): This should be an associated constant
102+
fn one() -> Self;
63103
}
64104

65-
/// Returns `1` of appropriate type.
105+
/// Returns the multiplicative identity, `1`.
66106
#[inline(always)] pub fn one<T: One>() -> T { One::one() }
67107

68108
pub trait Signed: Num
@@ -264,48 +304,29 @@ pub trait Real: Signed
264304
fn to_radians(&self) -> Self;
265305
}
266306

267-
/// Raises a value to the power of exp, using
268-
/// exponentiation by squaring.
307+
/// Raises a value to the power of exp, using exponentiation by squaring.
269308
///
270309
/// # Example
271310
///
272311
/// ```rust
273312
/// use std::num;
274313
///
275-
/// let sixteen = num::pow(2, 4u);
276-
/// assert_eq!(sixteen, 16);
314+
/// assert_eq!(num::pow(2, 4), 16);
277315
/// ```
278316
#[inline]
279-
pub fn pow<T: Clone+One+Mul<T, T>>(num: T, exp: uint) -> T {
280-
let one: uint = One::one();
281-
let num_one: T = One::one();
282-
283-
if exp.is_zero() { return num_one; }
284-
if exp == one { return num.clone(); }
285-
286-
let mut i: uint = exp;
287-
let mut v: T;
288-
let mut r: T = num_one;
289-
290-
// This if is to avoid cloning self.
291-
if (i & one) == one {
292-
r = r * num;
293-
i = i - one;
294-
}
295-
296-
i = i >> one;
297-
v = num * num;
298-
299-
while !i.is_zero() {
300-
if (i & one) == one {
301-
r = r * v;
302-
i = i - one;
317+
pub fn pow<T: One + Mul<T, T>>(mut base: T, mut exp: uint) -> T {
318+
if exp == 1 { base }
319+
else {
320+
let mut acc = one::<T>();
321+
while exp > 0 {
322+
if (exp & 1) == 1 {
323+
acc = acc * base;
324+
}
325+
base = base * base;
326+
exp = exp >> 1;
303327
}
304-
i = i >> one;
305-
v = v * v;
328+
acc
306329
}
307-
308-
r
309330
}
310331

311332
/// Raise a number to a power.
@@ -993,16 +1014,6 @@ pub fn from_str_radix<T: FromStrRadix>(str: &str, radix: uint) -> Option<T> {
9931014
FromStrRadix::from_str_radix(str, radix)
9941015
}
9951016

996-
impl<T: Zero + 'static> Zero for @T {
997-
fn zero() -> @T { @Zero::zero() }
998-
fn is_zero(&self) -> bool { (**self).is_zero() }
999-
}
1000-
1001-
impl<T: Zero> Zero for ~T {
1002-
fn zero() -> ~T { ~Zero::zero() }
1003-
fn is_zero(&self) -> bool { (**self).is_zero() }
1004-
}
1005-
10061017
/// Saturating math operations
10071018
pub trait Saturating {
10081019
/// Saturating addition operator.
@@ -1640,17 +1651,24 @@ mod tests {
16401651

16411652
#[test]
16421653
fn test_pow() {
1643-
fn assert_pow<T: Eq+Clone+One+Mul<T, T>>(num: T, exp: uint) -> () {
1644-
assert_eq!(num::pow(num.clone(), exp),
1645-
range(1u, exp).fold(num.clone(), |acc, _| acc * num));
1654+
fn naive_pow<T: One + Mul<T, T>>(base: T, exp: uint) -> T {
1655+
range(0, exp).fold(one::<T>(), |acc, _| acc * base)
16461656
}
1647-
1648-
assert_eq!(num::pow(3, 0), 1);
1649-
assert_eq!(num::pow(5, 1), 5);
1650-
assert_pow(-4, 2);
1651-
assert_pow(8, 3);
1652-
assert_pow(8, 5);
1653-
assert_pow(2u64, 50);
1657+
macro_rules! assert_pow(
1658+
(($num:expr, $exp:expr) => $expected:expr) => {{
1659+
let result = pow($num, $exp);
1660+
assert_eq!(result, $expected);
1661+
assert_eq!(result, naive_pow($num, $exp));
1662+
}}
1663+
)
1664+
assert_pow!((3, 0 ) => 1);
1665+
assert_pow!((5, 1 ) => 5);
1666+
assert_pow!((-4, 2 ) => 16);
1667+
assert_pow!((0.5, 5 ) => 0.03125);
1668+
assert_pow!((8, 3 ) => 512);
1669+
assert_pow!((8.0, 5 ) => 32768.0);
1670+
assert_pow!((8.5, 5 ) => 44370.53125);
1671+
assert_pow!((2u64, 50) => 1125899906842624);
16541672
}
16551673
}
16561674

src/libstd/tuple.rs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
use clone::Clone;
1616
#[cfg(not(test))] use cmp::*;
1717
#[cfg(not(test))] use default::Default;
18-
#[cfg(not(test))] use num::Zero;
1918

2019
/// Method extensions to pairs where both types satisfy the `Clone` bound
2120
pub trait CopyableTuple<T, U> {
@@ -177,18 +176,6 @@ macro_rules! tuple_impls {
177176
($({ let x: $T = Default::default(); x},)+)
178177
}
179178
}
180-
181-
#[cfg(not(test))]
182-
impl<$($T:Zero),+> Zero for ($($T,)+) {
183-
#[inline]
184-
fn zero() -> ($($T,)+) {
185-
($({ let x: $T = Zero::zero(); x},)+)
186-
}
187-
#[inline]
188-
fn is_zero(&self) -> bool {
189-
$(self.$get_ref_fn().is_zero())&&+
190-
}
191-
}
192179
)+
193180
}
194181
}

src/libstd/unit.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
1313
#[cfg(not(test))]
1414
use prelude::*;
15-
#[cfg(not(test))]
16-
use num::Zero;
1715

1816
#[cfg(not(test))]
1917
impl Eq for () {
@@ -46,11 +44,3 @@ impl Default for () {
4644
#[inline]
4745
fn default() -> () { () }
4846
}
49-
50-
#[cfg(not(test))]
51-
impl Zero for () {
52-
#[inline]
53-
fn zero() -> () { () }
54-
#[inline]
55-
fn is_zero(&self) -> bool { true }
56-
}

0 commit comments

Comments
 (0)