Repository: bluss/rust-ndarray (rust)

Issue:
`Default` trait for `ArrayBase`?
What is the opinion on implementing `std::default::Default` for `ArrayBase`? When skipping deserialization of a field with `serde`, it wants to insert the `Default::default()` value in there, so this would be one case where this would be very useful.

We already have a default function for `ArrayBase`, which however expects some kind of shape/dimension:

```rust
    pub fn default<Sh>(shape: Sh) -> ArrayBase<S, D>
        where A: Default,
              Sh: Into<Shape<D>>,
    {
        let shape = shape.into();
        let v = (0..shape.dim.size()).map(|_| A::default()).collect();
        unsafe { Self::from_shape_vec_unchecked(shape, v) }
    }
```

A default in the spirit of `std::default::Default` would look like:

```rust
    pub fn default() -> ArrayBase<S, D>
        where A: Default,
              D: Default + Default,
              Sh: Into<Shape<D>>,
    {
        let shape = <D as Default>::default().into();
        let v = (0..shape.dim.size()).map(|_| A::default()).collect(); // == Vec::new()
        unsafe { Self::from_shape_vec_unchecked(shape, v) }
    }
```

And `Default` impls for the various dimension-like types would be akin to:

```rust
impl Default for Ix {
    fn default() -> Self {
        0 as Ix
    }
}

impl Default for (Ix,Ix) {
    fn default() -> Self {
        (0,0) as (Ix,Ix)
    }
}
```

Is this desirable?

**EDIT:** I just realize that this might not be as straightforward as I thought, since e.g. `Ix` acts as just a type alias, preventing an easy implementation of `Default` for it. :-/

Pull request description:
Implement Default for owned arrays
zero-dimensional arrays (using () or Vec::new() as the dimension/D type
parameter) will have 1 element in the default state.
    
nonzero-dimensional arrays (using Ix, (Ix, Ix) and so on) will have
0 elements in their default state.

Fixes #204


Patch:
diff --git a/src/arraydeserialize.rs b/src/array_serde.rs
similarity index 72%
rename from src/arraydeserialize.rs
rename to src/array_serde.rs
index 97633d15..8aef08d6 100644
--- a/src/arraydeserialize.rs
+++ b/src/array_serde.rs
@@ -5,13 +5,51 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
-use serde::{self, Deserialize};
-
-use std::marker::PhantomData;
+use serde::{self, Serialize, Deserialize};
 
 use imp_prelude::*;
 
 use super::arraytraits::ARRAY_FORMAT_VERSION;
+use super::Elements;
+
+use std::marker::PhantomData;
+
+/// **Requires crate feature `"serde"`**
+impl<A, D, S> Serialize for ArrayBase<S, D>
+    where A: Serialize,
+          D: Dimension + Serialize,
+          S: Data<Elem = A>
+
+{
+    fn serialize<Se>(&self, serializer: &mut Se) -> Result<(), Se::Error>
+        where Se: serde::Serializer
+    {
+        let mut struct_state = try!(serializer.serialize_struct("Array", 3));
+        try!(serializer.serialize_struct_elt(&mut struct_state, "v", ARRAY_FORMAT_VERSION));
+        try!(serializer.serialize_struct_elt(&mut struct_state, "dim", self.dim()));
+        try!(serializer.serialize_struct_elt(&mut struct_state, "data", Sequence(self.iter())));
+        serializer.serialize_struct_end(struct_state)
+    }
+}
+
+// private iterator wrapper
+struct Sequence<'a, A: 'a, D>(Elements<'a, A, D>);
+
+impl<'a, A, D> Serialize for Sequence<'a, A, D>
+    where A: Serialize,
+          D: Dimension + Serialize
+{
+    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
+        where S: serde::Serializer
+    {
+        let iter = &self.0;
+        let mut seq_state = try!(serializer.serialize_seq(Some(iter.len())));
+        for elt in iter.clone() {
+            try!(serializer.serialize_seq_elt(&mut seq_state, elt));
+        }
+        serializer.serialize_seq_end(seq_state)
+    }
+}
 
 struct ArrayVisitor<S, Di> {
     _marker_a: PhantomData<S>,
diff --git a/src/array_serialize.rs b/src/array_serialize.rs
new file mode 100644
index 00000000..60003934
--- /dev/null
+++ b/src/array_serialize.rs
@@ -0,0 +1,76 @@
+// Copyright 2014-2016 bluss and ndarray developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use serialize::{Encodable, Encoder, Decodable, Decoder};
+use super::arraytraits::ARRAY_FORMAT_VERSION;
+
+use imp_prelude::*;
+
+/// **Requires crate feature `"rustc-serialize"`**
+impl<A, S, D> Encodable for ArrayBase<S, D>
+    where A: Encodable,
+          D: Dimension + Encodable,
+          S: Data<Elem = A>
+{
+    fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> {
+        s.emit_struct("Array", 3, |e| {
+            try!(e.emit_struct_field("v", 0, |e| ARRAY_FORMAT_VERSION.encode(e)));
+            // FIXME: Write self.dim as a slice (self.shape)
+            // The problem is decoding it.
+            try!(e.emit_struct_field("dim", 1, |e| self.dim.encode(e)));
+            try!(e.emit_struct_field("data", 2, |e| {
+                let sz = self.dim.size();
+                e.emit_seq(sz, |e| {
+                    for (i, elt) in self.iter().enumerate() {
+                        try!(e.emit_seq_elt(i, |e| elt.encode(e)))
+                    }
+                    Ok(())
+                })
+            }));
+            Ok(())
+        })
+    }
+}
+
+/// **Requires crate feature `"rustc-serialize"`**
+impl<A, S, D> Decodable for ArrayBase<S, D>
+    where A: Decodable,
+          D: Dimension + Decodable,
+          S: DataOwned<Elem = A>
+{
+    fn decode<E: Decoder>(d: &mut E) -> Result<ArrayBase<S, D>, E::Error> {
+        d.read_struct("Array", 3, |d| {
+            let version: u8 = try!(d.read_struct_field("v", 0, Decodable::decode));
+            if version > ARRAY_FORMAT_VERSION {
+                return Err(d.error("unknown array version"))
+            }
+            let dim: D = try!(d.read_struct_field("dim", 1, |d| {
+                Decodable::decode(d)
+            }));
+
+            let elements = try!(
+                d.read_struct_field("data", 2, |d| {
+                    d.read_seq(|d, len| {
+                        if len != dim.size() {
+                            Err(d.error("data and dimension must match in size"))
+                        } else {
+                            let mut elements = Vec::with_capacity(len);
+                            for i in 0..len {
+                                elements.push(try!(d.read_seq_elt::<A, _>(i, Decodable::decode)))
+                            }
+                            Ok(elements)
+                        }
+                    })
+            }));
+            unsafe {
+                Ok(ArrayBase::from_shape_vec_unchecked(dim, elements))
+            }
+        })
+    }
+}
+
diff --git a/src/arrayserialize.rs b/src/arrayserialize.rs
deleted file mode 100644
index 8341aee2..00000000
--- a/src/arrayserialize.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2014-2016 bluss and ndarray developers.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-use serde::{self, Serialize};
-
-use imp_prelude::*;
-
-use super::arraytraits::ARRAY_FORMAT_VERSION;
-use super::Elements;
-
-/// **Requires crate feature `"serde"`**
-impl<A, D, S> Serialize for ArrayBase<S, D>
-    where A: Serialize,
-          D: Dimension + Serialize,
-          S: Data<Elem = A>
-
-{
-    fn serialize<Se>(&self, serializer: &mut Se) -> Result<(), Se::Error>
-        where Se: serde::Serializer
-    {
-        let mut struct_state = try!(serializer.serialize_struct("Array", 3));
-        try!(serializer.serialize_struct_elt(&mut struct_state, "v", ARRAY_FORMAT_VERSION));
-        try!(serializer.serialize_struct_elt(&mut struct_state, "dim", self.dim()));
-        try!(serializer.serialize_struct_elt(&mut struct_state, "data", Sequence(self.iter())));
-        serializer.serialize_struct_end(struct_state)
-    }
-}
-
-// private iterator wrapper
-struct Sequence<'a, A: 'a, D>(Elements<'a, A, D>);
-
-impl<'a, A, D> Serialize for Sequence<'a, A, D>
-    where A: Serialize,
-          D: Dimension + Serialize
-{
-    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
-        where S: serde::Serializer
-    {
-        let iter = &self.0;
-        let mut seq_state = try!(serializer.serialize_seq(Some(iter.len())));
-        for elt in iter.clone() {
-            try!(serializer.serialize_seq_elt(&mut seq_state, elt));
-        }
-        serializer.serialize_seq_end(seq_state)
-    }
-}
diff --git a/src/arraytraits.rs b/src/arraytraits.rs
index 64bbf9e5..6b4e0699 100644
--- a/src/arraytraits.rs
+++ b/src/arraytraits.rs
@@ -212,71 +212,6 @@ unsafe impl<S, D> Send for ArrayBase<S, D>
 // Use version number so we can add a packed format later.
 pub const ARRAY_FORMAT_VERSION: u8 = 1u8;
 
-/// **Requires crate feature `"rustc-serialize"`**
-#[cfg(feature = "rustc-serialize")]
-impl<A, S, D> Encodable for ArrayBase<S, D>
-    where A: Encodable,
-          D: Dimension + Encodable,
-          S: Data<Elem = A>
-{
-    fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> {
-        s.emit_struct("Array", 3, |e| {
-            try!(e.emit_struct_field("v", 0, |e| ARRAY_FORMAT_VERSION.encode(e)));
-            // FIXME: Write self.dim as a slice (self.shape)
-            // The problem is decoding it.
-            try!(e.emit_struct_field("dim", 1, |e| self.dim.encode(e)));
-            try!(e.emit_struct_field("data", 2, |e| {
-                let sz = self.dim.size();
-                e.emit_seq(sz, |e| {
-                    for (i, elt) in self.iter().enumerate() {
-                        try!(e.emit_seq_elt(i, |e| elt.encode(e)))
-                    }
-                    Ok(())
-                })
-            }));
-            Ok(())
-        })
-    }
-}
-
-/// **Requires crate feature `"rustc-serialize"`**
-#[cfg(feature = "rustc-serialize")]
-impl<A, S, D> Decodable for ArrayBase<S, D>
-    where A: Decodable,
-          D: Dimension + Decodable,
-          S: DataOwned<Elem = A>
-{
-    fn decode<E: Decoder>(d: &mut E) -> Result<ArrayBase<S, D>, E::Error> {
-        d.read_struct("Array", 3, |d| {
-            let version: u8 = try!(d.read_struct_field("v", 0, Decodable::decode));
-            if version > ARRAY_FORMAT_VERSION {
-                return Err(d.error("unknown array version"))
-            }
-            let dim: D = try!(d.read_struct_field("dim", 1, |d| {
-                Decodable::decode(d)
-            }));
-
-            let elements = try!(
-                d.read_struct_field("data", 2, |d| {
-                    d.read_seq(|d, len| {
-                        if len != dim.size() {
-                            Err(d.error("data and dimension must match in size"))
-                        } else {
-                            let mut elements = Vec::with_capacity(len);
-                            for i in 0..len {
-                                elements.push(try!(d.read_seq_elt::<A, _>(i, Decodable::decode)))
-                            }
-                            Ok(elements)
-                        }
-                    })
-            }));
-            unsafe {
-                Ok(ArrayBase::from_shape_vec_unchecked(dim, elements))
-            }
-        })
-    }
-}
-
 
 // use "raw" form instead of type aliases here so that they show up in docs
 /// Implementation of `ArrayView::from(&S)` where `S` is a slice or slicable.
@@ -357,3 +292,25 @@ impl<'a, A: 'a, D, T> AsArray<'a, A, D> for T
     where T: Into<ArrayView<'a, A, D>>,
           D: Dimension,
 { }
+
+/// Create an owned array with a default state.
+///
+/// The array is created with dimension `D::default()`, which results
+/// in for example dimensions `0` and `(0, 0)` with zero elements for the
+/// one-dimensional and two-dimensional cases respectively, while for example
+/// the zero dimensional case uses `()` (or `Vec::new()`) which
+/// results in an array with one element.
+///
+/// Since arrays cannot grow, the intention is to use the default value as
+/// placeholder.
+impl<A, S, D> Default for ArrayBase<S, D>
+    where S: DataOwned<Elem=A>,
+          D: Dimension,
+          A: Default,
+{
+    // NOTE: We can implement Default for non-zero dimensional array views by
+    // using an empty slice, however we need a trait for nonzero Dimension.
+    fn default() -> Self {
+        ArrayBase::default(D::default())
+    }
+}
diff --git a/src/dimension.rs b/src/dimension.rs
index 4b9e62b5..09ad21b6 100644
--- a/src/dimension.rs
+++ b/src/dimension.rs
@@ -124,7 +124,7 @@ fn stride_offset_checked_arithmetic<D>(dim: &D, strides: &D, index: &D)
 ///
 /// ***Don't implement or call methods in this trait, its interface is internal
 /// to the crate and will evolve at will.***
-pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync {
+pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default {
     /// `SliceArg` is the type which is used to specify slicing for this
     /// dimension.
     ///
diff --git a/src/lib.rs b/src/lib.rs
index 262e8ed6..d93a0886 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -116,9 +116,9 @@ pub use shape_builder::{ ShapeBuilder };
 
 mod arraytraits;
 #[cfg(feature = "serde")]
-mod arrayserialize;
-#[cfg(feature = "serde")]
-mod arraydeserialize;
+mod array_serde;
+#[cfg(feature = "rustc-serialize")]
+mod array_serialize;
 mod arrayformat;
 mod data_traits;
 


Test patch:
diff --git a/tests/array.rs b/tests/array.rs
index fa496953..225dd87b 100644
--- a/tests/array.rs
+++ b/tests/array.rs
@@ -1050,3 +1050,15 @@ fn test_view_from_shape_ptr() {
     view[[0, 1]] = 0;
     assert_eq!(view, aview2(&[[0, 0, 2], [3, 4, 6]]));
 }
+
+#[test]
+fn test_default() {
+    let a = <Array<f32, (Ix, Ix)> as Default>::default();
+    assert_eq!(a, aview2(&[[0.0; 0]; 0]));
+
+
+    #[derive(Default, Debug, PartialEq)]
+    struct Foo(i32);
+    let b = <Array<Foo, ()> as Default>::default();
+    assert_eq!(b, arr0(Foo::default()));
+}