]> git.lizzy.rs Git - rust.git/commitdiff
Add operator trait constraints to std::num::{Zero, One} and document their appropriat...
authorBrendan Zabarauskas <bjzaba@yahoo.com.au>
Sat, 18 Jan 2014 06:08:23 +0000 (17:08 +1100)
committerBrendan Zabarauskas <bjzaba@yahoo.com.au>
Mon, 20 Jan 2014 07:09:46 +0000 (18:09 +1100)
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

src/libextra/uuid.rs
src/libstd/bool.rs
src/libstd/char.rs
src/libstd/iter.rs
src/libstd/num/mod.rs
src/libstd/tuple.rs
src/libstd/unit.rs
src/test/run-pass/deriving-zero.rs
src/test/run-pass/issue-5554.rs

index 2c48a7a4d3e5d1b445382a9d1cd2816aac93854c..02930dc9c4c6413530fcafac52679f573fc50ae7 100644 (file)
@@ -57,7 +57,7 @@ fn main() {
 
 use std::str;
 use std::vec;
-use std::num::{FromStrRadix, Zero};
+use std::num::FromStrRadix;
 use std::char::Char;
 use std::container::Container;
 use std::to_str::ToStr;
@@ -158,9 +158,8 @@ fn to_str(&self) -> ~str {
 
 /// UUID support
 impl Uuid {
-
     /// Returns a nil or empty UUID (containing all zeroes)
-    pub fn new_nil() -> Uuid {
+    pub fn nil() -> Uuid {
         let uuid = Uuid{ bytes: [0, .. 16] };
         uuid
     }
@@ -423,24 +422,17 @@ pub fn parse_string(us: &str) -> Result<Uuid, ParseError> {
 
         Ok(Uuid::from_bytes(ub).unwrap())
     }
-}
 
-impl Default for Uuid {
-    /// Returns the nil UUID, which is all zeroes
-    fn default() -> Uuid {
-        Uuid::new_nil()
+    /// Tests if the UUID is nil
+    pub fn is_nil(&self) -> bool {
+        return self.bytes.iter().all(|&b| b == 0);
     }
 }
 
-impl Zero for Uuid {
+impl Default for Uuid {
     /// Returns the nil UUID, which is all zeroes
-    fn zero() -> Uuid {
-        Uuid::new_nil()
-    }
-
-    /// Tests if the UUID is nil or all zeroes
-    fn is_zero(&self) -> bool {
-        return self.bytes.iter().all(|&b| b == 0);
+    fn default() -> Uuid {
+        Uuid::nil()
     }
 }
 
@@ -521,24 +513,15 @@ mod test {
     use super::*;
     use std::str;
     use std::rand;
-    use std::num::Zero;
     use std::io::MemWriter;
 
     #[test]
-    fn test_new_nil() {
-        let nil = Uuid::new_nil();
-        let nb = nil.to_bytes();
-
-        assert!(nb.iter().all(|&b| b == 0));
-    }
-
-    #[test]
-    fn test_zero() {
-        let uz: Uuid = Zero::zero();
-        let nz = Uuid::new_v4();
+    fn test_nil() {
+        let nil = Uuid::nil();
+        let not_nil = Uuid::new_v4();
 
-        assert!(uz.is_zero());
-        assert!(! nz.is_zero());
+        assert!(nil.is_nil());
+        assert!(!not_nil.is_nil());
     }
 
     #[test]
@@ -619,7 +602,7 @@ fn test_parse_uuid_v4() {
         assert!(Uuid::parse_string("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8").is_ok());
 
         // Nil
-        let nil = Uuid::new_nil();
+        let nil = Uuid::nil();
         assert!(Uuid::parse_string("00000000000000000000000000000000").unwrap()  == nil);
         assert!(Uuid::parse_string("00000000-0000-0000-0000-000000000000").unwrap() == nil);
 
index d080262ccc77dcd46f4ea55b5ee7b76541b4461d..af745f94fb519370c291ef82b6beb0fa200a5d11 100644 (file)
@@ -40,7 +40,6 @@
 #[cfg(not(test))] use cmp::{Eq, Ord, TotalOrd, Ordering};
 #[cfg(not(test))] use ops::{Not, BitAnd, BitOr, BitXor};
 #[cfg(not(test))] use default::Default;
-#[cfg(not(test))] use num::Zero;
 
 /////////////////////////////////////////////////////////////////////////////
 // Freestanding functions
@@ -309,12 +308,6 @@ impl Default for bool {
     fn default() -> bool { false }
 }
 
-#[cfg(not(test))]
-impl Zero for bool {
-    fn zero() -> bool { false }
-    fn is_zero(&self) -> bool { *self == false }
-}
-
 #[cfg(test)]
 mod tests {
     use prelude::*;
index 4e9c72de61887580623f07b508e1235b2f693ffa..71a297d71765e2f24b944fadd7d87e1d4e1c9c39 100644 (file)
@@ -22,7 +22,6 @@
 
 #[cfg(not(test))] use cmp::{Eq, Ord};
 #[cfg(not(test))] use default::Default;
-#[cfg(not(test))] use num::Zero;
 
 // UTF-8 ranges and tags for encoding characters
 static TAG_CONT: uint = 128u;
@@ -449,15 +448,6 @@ impl Default for char {
     fn default() -> char { '\x00' }
 }
 
-#[cfg(not(test))]
-impl Zero for char {
-    #[inline]
-    fn zero() -> char { '\x00' }
-
-    #[inline]
-    fn is_zero(&self) -> bool { *self == '\x00' }
-}
-
 #[test]
 fn test_is_lowercase() {
     assert!('a'.is_lowercase());
index fcf0f4f24443c7e0bcf577047dd349c38ab955d8..8081c6ed8db51cad0937c5d10ac9edce6afdc633 100644 (file)
@@ -2872,6 +2872,12 @@ fn clone(&self) -> Foo {
             }
         }
 
+        impl Mul<Foo, Foo> for Foo {
+            fn mul(&self, _: &Foo) -> Foo {
+                Foo
+            }
+        }
+
         impl num::One for Foo {
             fn one() -> Foo {
                 Foo
index c374d6c21574a57eed603995865281e81a3c0d63..23a852cc3579ef9ca809f61d452ab5d836f3d0e2 100644 (file)
@@ -50,19 +50,59 @@ pub trait Orderable: Ord {
 /// Returns the number constrained within the range `mn <= self <= mx`.
 #[inline(always)] pub fn clamp<T: Orderable>(value: T, mn: T, mx: T) -> T { value.clamp(&mn, &mx) }
 
-pub trait Zero {
-    fn zero() -> Self;      // FIXME (#5527): This should be an associated constant
+/// Defines an additive identity element for `Self`.
+///
+/// # Deriving
+///
+/// This trait can be automatically be derived using `#[deriving(Zero)]`
+/// attribute. If you choose to use this, make sure that the laws outlined in
+/// the documentation for `Zero::zero` still hold.
+pub trait Zero: Add<Self, Self> {
+    /// Returns the additive identity element of `Self`, `0`.
+    ///
+    /// # Laws
+    ///
+    /// ~~~
+    /// a + 0 = a       ∀ a ∈ Self
+    /// 0 + a = a       ∀ a ∈ Self
+    /// ~~~
+    ///
+    /// # Purity
+    ///
+    /// This function should return the same result at all times regardless of
+    /// external mutable state, for example values stored in TLS or in
+    /// `static mut`s.
+    // FIXME (#5527): This should be an associated constant
+    fn zero() -> Self;
+
+    /// Returns `true` if `self` is equal to the additive identity.
     fn is_zero(&self) -> bool;
 }
 
-/// Returns `0` of appropriate type.
+/// Returns the additive identity, `0`.
 #[inline(always)] pub fn zero<T: Zero>() -> T { Zero::zero() }
 
-pub trait One {
-    fn one() -> Self;       // FIXME (#5527): This should be an associated constant
+/// Defines a multiplicative identity element for `Self`.
+pub trait One: Mul<Self, Self> {
+    /// Returns the multiplicative identity element of `Self`, `1`.
+    ///
+    /// # Laws
+    ///
+    /// ~~~
+    /// a * 1 = a       ∀ a ∈ Self
+    /// 1 * a = a       ∀ a ∈ Self
+    /// ~~~
+    ///
+    /// # Purity
+    ///
+    /// This function should return the same result at all times regardless of
+    /// external mutable state, for example values stored in TLS or in
+    /// `static mut`s.
+    // FIXME (#5527): This should be an associated constant
+    fn one() -> Self;
 }
 
-/// Returns `1` of appropriate type.
+/// Returns the multiplicative identity, `1`.
 #[inline(always)] pub fn one<T: One>() -> T { One::one() }
 
 pub trait Signed: Num
@@ -993,16 +1033,6 @@ pub fn from_str_radix<T: FromStrRadix>(str: &str, radix: uint) -> Option<T> {
     FromStrRadix::from_str_radix(str, radix)
 }
 
-impl<T: Zero + 'static> Zero for @T {
-    fn zero() -> @T { @Zero::zero() }
-    fn is_zero(&self) -> bool { (**self).is_zero() }
-}
-
-impl<T: Zero> Zero for ~T {
-    fn zero() -> ~T { ~Zero::zero() }
-    fn is_zero(&self) -> bool { (**self).is_zero() }
-}
-
 /// Saturating math operations
 pub trait Saturating {
     /// Saturating addition operator.
index 313fd9c79b46a6768c5eb074503225f98545e1c6..8e278aeb2eab557630aa5b861403d3ba3e43bb02 100644 (file)
@@ -15,7 +15,6 @@
 use clone::Clone;
 #[cfg(not(test))] use cmp::*;
 #[cfg(not(test))] use default::Default;
-#[cfg(not(test))] use num::Zero;
 
 /// Method extensions to pairs where both types satisfy the `Clone` bound
 pub trait CopyableTuple<T, U> {
@@ -177,18 +176,6 @@ fn default() -> ($($T,)+) {
                     ($({ let x: $T = Default::default(); x},)+)
                 }
             }
-
-            #[cfg(not(test))]
-            impl<$($T:Zero),+> Zero for ($($T,)+) {
-                #[inline]
-                fn zero() -> ($($T,)+) {
-                    ($({ let x: $T = Zero::zero(); x},)+)
-                }
-                #[inline]
-                fn is_zero(&self) -> bool {
-                    $(self.$get_ref_fn().is_zero())&&+
-                }
-            }
         )+
     }
 }
index c27f6e3d086b68840794f0f9bdd3433f8b1e8861..786a7f42bb394c72998d8941e817c671eb0ef199 100644 (file)
@@ -12,8 +12,6 @@
 
 #[cfg(not(test))]
 use prelude::*;
-#[cfg(not(test))]
-use num::Zero;
 
 #[cfg(not(test))]
 impl Eq for () {
@@ -46,11 +44,3 @@ impl Default for () {
     #[inline]
     fn default() -> () { () }
 }
-
-#[cfg(not(test))]
-impl Zero for () {
-    #[inline]
-    fn zero() -> () { () }
-    #[inline]
-    fn is_zero(&self) -> bool { true }
-}
index d28e54d57ad4ceafef8740425d74d1f3d6698d4c..9ae72038aa9d9fc13fac13c00e2a9555b56464fa 100644 (file)
 
 #[feature(managed_boxes)];
 
-use std::util;
 use std::num::Zero;
 
 #[deriving(Zero)]
-struct A;
-#[deriving(Zero)]
-struct B(int);
-#[deriving(Zero)]
-struct C(int, int);
-#[deriving(Zero)]
-struct D { a: int }
+struct Vector2<T>(T, T);
+
+impl<T: Add<T, T>> Add<Vector2<T>, Vector2<T>> for Vector2<T> {
+    fn add(&self, other: &Vector2<T>) -> Vector2<T> {
+        match (self, other) {
+            (&Vector2(ref x0, ref y0), &Vector2(ref x1, ref y1)) => {
+                Vector2(*x0 + *x1, *y0 + *y1)
+            }
+        }
+    }
+}
+
 #[deriving(Zero)]
-struct E { a: int, b: int }
+struct Vector3<T> {
+    x: T, y: T, z: T,
+}
+
+impl<T: Add<T, T>> Add<Vector3<T>, Vector3<T>> for Vector3<T> {
+    fn add(&self, other: &Vector3<T>) -> Vector3<T> {
+        Vector3 {
+            x: self.x + other.x,
+            y: self.y + other.y,
+            z: self.z + other.z,
+        }
+    }
+}
 
 #[deriving(Zero)]
-struct Lots {
-    d: u8,
-    e: char,
-    f: f64,
-    g: (f32, char),
-    h: @(int, int),
-    i: bool,
-    j: (),
+struct Matrix3x2<T> {
+    x: Vector2<T>,
+    y: Vector2<T>,
+    z: Vector2<T>,
+}
+
+impl<T: Add<T, T>> Add<Matrix3x2<T>, Matrix3x2<T>> for Matrix3x2<T> {
+    fn add(&self, other: &Matrix3x2<T>) -> Matrix3x2<T> {
+        Matrix3x2 {
+            x: self.x + other.x,
+            y: self.y + other.y,
+            z: self.z + other.z,
+        }
+    }
 }
 
 pub fn main() {
-    let lots: Lots = Zero::zero();
-    assert!(lots.is_zero());
+    let _: Vector2<int> = Zero::zero();
+    let _: Vector3<f64> = Zero::zero();
+    let _: Matrix3x2<u8> = Zero::zero();
 }
index e4ef20a3b0fc4cc24a85d8556da09f8d699b2b98..25293c4dd1beac402a77ca6e92c094fcc12d887a 100644 (file)
 
 #[feature(macro_rules)];
 
-use std::num::Zero;
+use std::default::Default;
 
 pub struct X<T> {
-  a: T
+    a: T,
 }
 
 // reordering these bounds stops the ICE
-impl<T: Zero + Eq + Zero>
-  Zero for X<T> {
-    fn zero() -> X<T> {
-      X { a: Zero::zero() }
-    }
-    fn is_zero(&self) -> bool {
-        self.a.is_zero()
+impl<T: Default + Eq + Default> Default for X<T> {
+    fn default() -> X<T> {
+        X { a: Default::default() }
     }
 }
 
 macro_rules! constants {
-  () => {
-    let _0 : X<int> = Zero::zero();
-   }
+    () => {
+        let _ : X<int> = Default::default();
+    }
 }
 
-
 pub fn main() {
-  constants!();
+    constants!();
 }