Skip to content

Commit cf56624

Browse files
committed
Add operator trait constraints to std::num::{Zero, One} and document their appropriate use
Zero and One have precise definitions in mathematics. Documentation has been added to describe the appropriate uses for these traits and the laws that they should satisfy. For more information regarding these identities, see the following wikipedia pages: - http://wikipedia.org/wiki/Additive_identity - http://wikipedia.org/wiki/Multiplicative_identity
1 parent 764f2cb commit cf56624

File tree

9 files changed

+117
-120
lines changed

9 files changed

+117
-120
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: 46 additions & 16 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
@@ -993,16 +1033,6 @@ pub fn from_str_radix<T: FromStrRadix>(str: &str, radix: uint) -> Option<T> {
9931033
FromStrRadix::from_str_radix(str, radix)
9941034
}
9951035

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-
10061036
/// Saturating math operations
10071037
pub trait Saturating {
10081038
/// Saturating addition operator.

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-
}

src/test/run-pass/deriving-zero.rs

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,32 +10,55 @@
1010

1111
#[feature(managed_boxes)];
1212

13-
use std::util;
1413
use std::num::Zero;
1514

1615
#[deriving(Zero)]
17-
struct A;
18-
#[deriving(Zero)]
19-
struct B(int);
20-
#[deriving(Zero)]
21-
struct C(int, int);
22-
#[deriving(Zero)]
23-
struct D { a: int }
16+
struct Vector2<T>(T, T);
17+
18+
impl<T: Add<T, T>> Add<Vector2<T>, Vector2<T>> for Vector2<T> {
19+
fn add(&self, other: &Vector2<T>) -> Vector2<T> {
20+
match (self, other) {
21+
(&Vector2(ref x0, ref y0), &Vector2(ref x1, ref y1)) => {
22+
Vector2(*x0 + *x1, *y0 + *y1)
23+
}
24+
}
25+
}
26+
}
27+
2428
#[deriving(Zero)]
25-
struct E { a: int, b: int }
29+
struct Vector3<T> {
30+
x: T, y: T, z: T,
31+
}
32+
33+
impl<T: Add<T, T>> Add<Vector3<T>, Vector3<T>> for Vector3<T> {
34+
fn add(&self, other: &Vector3<T>) -> Vector3<T> {
35+
Vector3 {
36+
x: self.x + other.x,
37+
y: self.y + other.y,
38+
z: self.z + other.z,
39+
}
40+
}
41+
}
2642

2743
#[deriving(Zero)]
28-
struct Lots {
29-
d: u8,
30-
e: char,
31-
f: f64,
32-
g: (f32, char),
33-
h: @(int, int),
34-
i: bool,
35-
j: (),
44+
struct Matrix3x2<T> {
45+
x: Vector2<T>,
46+
y: Vector2<T>,
47+
z: Vector2<T>,
48+
}
49+
50+
impl<T: Add<T, T>> Add<Matrix3x2<T>, Matrix3x2<T>> for Matrix3x2<T> {
51+
fn add(&self, other: &Matrix3x2<T>) -> Matrix3x2<T> {
52+
Matrix3x2 {
53+
x: self.x + other.x,
54+
y: self.y + other.y,
55+
z: self.z + other.z,
56+
}
57+
}
3658
}
3759

3860
pub fn main() {
39-
let lots: Lots = Zero::zero();
40-
assert!(lots.is_zero());
61+
let _: Vector2<int> = Zero::zero();
62+
let _: Vector3<f64> = Zero::zero();
63+
let _: Matrix3x2<u8> = Zero::zero();
4164
}

src/test/run-pass/issue-5554.rs

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,25 @@
1010

1111
#[feature(macro_rules)];
1212

13-
use std::num::Zero;
13+
use std::default::Default;
1414

1515
pub struct X<T> {
16-
a: T
16+
a: T,
1717
}
1818

1919
// reordering these bounds stops the ICE
20-
impl<T: Zero + Eq + Zero>
21-
Zero for X<T> {
22-
fn zero() -> X<T> {
23-
X { a: Zero::zero() }
24-
}
25-
fn is_zero(&self) -> bool {
26-
self.a.is_zero()
20+
impl<T: Default + Eq + Default> Default for X<T> {
21+
fn default() -> X<T> {
22+
X { a: Default::default() }
2723
}
2824
}
2925

3026
macro_rules! constants {
31-
() => {
32-
let _0 : X<int> = Zero::zero();
33-
}
27+
() => {
28+
let _ : X<int> = Default::default();
29+
}
3430
}
3531

36-
3732
pub fn main() {
38-
constants!();
33+
constants!();
3934
}

0 commit comments

Comments
 (0)