Repository: bluss/rust-ndarray
Pull request #304 (2017-04-05 15:20:47)

Implement breaking changes for next version
- Remove Ix, Ixs from prelude (use usize, isize or import directly)
- Encapsulate Vec/RcVec
- Replace `.inner_iter()` with `.inners()`, `.genrows()`, `.gencolumns()`
  + Awkward names!! Because `.rows()` is already the row count, and `.row_iter` is not applicable -- `.genrows()` is an NdProducer + IntoIterator
- Private marker on Data and Dimension
- Stop using # flag in formatting
- Require Rust 1.15
- Add Item associated type to IntoNdProducer


Patch:
diff --git a/.travis.yml b/.travis.yml
index 9cc19bea..7bee622d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,7 +4,7 @@ sudo: required
 dist: trusty
 matrix:
   include:
-    - rust: 1.13.0
+    - rust: 1.15.0
       env:
        - FEATURES='test'
     - rust: stable
diff --git a/README.rst b/README.rst
index 93d9caae..b2055048 100644
--- a/README.rst
+++ b/README.rst
@@ -2,7 +2,7 @@ ndarray
 =========
 
 The ``ndarray`` crate provides an N-dimensional container for general elements
-and for numerics.  Requires Rust 1.13.
+and for numerics.
 
 Please read the API documentation here: `(0.8)`__, `(0.7)`__, `(0.6)`__,
 `(0.5)`__, `(0.4)`__, `(0.3)`__, `(0.2)`__
diff --git a/benches/bench1.rs b/benches/bench1.rs
index 399a8b12..95376deb 100644
--- a/benches/bench1.rs
+++ b/benches/bench1.rs
@@ -68,7 +68,7 @@ fn iter_sum_2d_by_row(bench: &mut test::Bencher)
     let a = black_box(a);
     bench.iter(|| {
         let mut sum = 0;
-        for row in a.inner_iter() {
+        for row in a.genrows() {
             for &elt in row {
                 sum += elt;
             }
@@ -132,7 +132,7 @@ fn iter_sum_2d_cutout_outer_iter(bench: &mut test::Bencher)
     let a = black_box(av);
     bench.iter(|| {
         let mut sum = 0;
-        for row in a.inner_iter() {
+        for row in a.genrows() {
             for &elt in row {
                 sum += elt;
             }
diff --git a/examples/life.rs b/examples/life.rs
index 11d43d13..dd4106e9 100644
--- a/examples/life.rs
+++ b/examples/life.rs
@@ -13,14 +13,14 @@ type Board = Array2<u8>;
 
 fn parse(x: &[u8]) -> Board {
     // make a border of 0 cells
-    let mut map = Board::from_elem(((N + 2) as Ix, (N + 2) as Ix), 0);
+    let mut map = Board::from_elem(((N + 2), (N + 2)), 0);
     let a = Array::from_iter(x.iter().filter_map(|&b| match b {
         b'#' => Some(1),
         b'.' => Some(0),
         _ => None,
     }));
 
-    let a = a.into_shape((N as Ix, N as Ix)).unwrap();
+    let a = a.into_shape((N, N)).unwrap();
     map.slice_mut(s![1..-1, 1..-1]).assign(&a);
     map
 }
@@ -66,7 +66,7 @@ fn turn_on_corners(z: &mut Board) {
 }
 
 fn render(a: &Board) {
-    for row in a.inner_iter() {
+    for row in a.genrows() {
         for &x in row {
             if x > 0 {
                 print!("#");
@@ -80,7 +80,7 @@ fn render(a: &Board) {
 
 fn main() {
     let mut a = parse(INPUT);
-    let mut scratch = Board::zeros((N as Ix, N as Ix));
+    let mut scratch = Board::zeros((N, N));
     let steps = 100;
     turn_on_corners(&mut a);
     for _ in 0..steps {
diff --git a/src/arrayformat.rs b/src/arrayformat.rs
index 81a51663..26742779 100644
--- a/src/arrayformat.rs
+++ b/src/arrayformat.rs
@@ -55,9 +55,7 @@ fn format_array<A, S, D, F>(view: &ArrayBase<S, D>, f: &mut fmt::Formatter,
                     try!(write!(f, "]"));
                 }
                 try!(write!(f, ","));
-                if !f.alternate() {
-                    try!(write!(f, "\n"));
-                }
+                try!(write!(f, "\n"));
                 for _ in 0..ndim - n {
                     try!(write!(f, " "));
                 }
@@ -89,8 +87,7 @@ fn format_array<A, S, D, F>(view: &ArrayBase<S, D>, f: &mut fmt::Formatter,
 /// Format the array using `Display` and apply the formatting parameters used
 /// to each element.
 ///
-/// The array is shown in multiline style, unless the alternate form 
-/// is used, `{:#}`.
+/// The array is shown in multiline style.
 impl<'a, A: fmt::Display, S, D: Dimension> fmt::Display for ArrayBase<S, D>
     where S: Data<Elem=A>,
 {
@@ -102,8 +99,7 @@ impl<'a, A: fmt::Display, S, D: Dimension> fmt::Display for ArrayBase<S, D>
 /// Format the array using `Debug` and apply the formatting parameters used
 /// to each element.
 ///
-/// The array is shown in multiline style, unless the alternate form 
-/// is used, `{:#?}`.
+/// The array is shown in multiline style.
 impl<'a, A: fmt::Debug, S, D: Dimension> fmt::Debug for ArrayBase<S, D>
     where S: Data<Elem=A>,
 {
@@ -119,8 +115,7 @@ impl<'a, A: fmt::Debug, S, D: Dimension> fmt::Debug for ArrayBase<S, D>
 /// Format the array using `LowerExp` and apply the formatting parameters used
 /// to each element.
 ///
-/// The array is shown in multiline style, unless the alternate form
-/// is used, `{:#e}`.
+/// The array is shown in multiline style.
 impl<'a, A: fmt::LowerExp, S, D: Dimension> fmt::LowerExp for ArrayBase<S, D>
     where S: Data<Elem=A>,
 {
@@ -132,8 +127,7 @@ impl<'a, A: fmt::LowerExp, S, D: Dimension> fmt::LowerExp for ArrayBase<S, D>
 /// Format the array using `UpperExp` and apply the formatting parameters used
 /// to each element.
 ///
-/// The array is shown in multiline style, unless the alternate form
-/// is used, `{:#E}`.
+/// The array is shown in multiline style.
 impl<'a, A: fmt::UpperExp, S, D: Dimension> fmt::UpperExp for ArrayBase<S, D>
     where S: Data<Elem=A>,
 {
@@ -144,8 +138,7 @@ impl<'a, A: fmt::UpperExp, S, D: Dimension> fmt::UpperExp for ArrayBase<S, D>
 /// Format the array using `LowerHex` and apply the formatting parameters used
 /// to each element.
 ///
-/// The array is shown in multiline style, unless the alternate form
-/// is used, `{:#x}`.
+/// The array is shown in multiline style.
 impl<'a, A: fmt::LowerHex, S, D: Dimension> fmt::LowerHex for ArrayBase<S, D>
     where S: Data<Elem=A>,
 {
diff --git a/src/data_traits.rs b/src/data_traits.rs
index 6c647f14..0d8a4c2d 100644
--- a/src/data_traits.rs
+++ b/src/data_traits.rs
@@ -30,6 +30,7 @@ pub unsafe trait Data : Sized {
     #[doc(hidden)]
     // This method is only used for debugging
     fn _data_slice(&self) -> &[Self::Elem];
+    private_decl!{}
 }
 
 /// Array representation trait.
@@ -73,8 +74,9 @@ pub unsafe trait DataClone : Data {
 unsafe impl<A> Data for OwnedRcRepr<A> {
     type Elem = A;
     fn _data_slice(&self) -> &[A] {
-        self
+        &self.0
     }
+    private_impl!{}
 }
 
 // NOTE: Copy on write
@@ -85,10 +87,10 @@ unsafe impl<A> DataMut for OwnedRcRepr<A>
         where Self: Sized,
               D: Dimension
     {
-        if Rc::get_mut(&mut self_.data).is_some() {
+        if Rc::get_mut(&mut self_.data.0).is_some() {
             return;
         }
-        if self_.dim.size() <= self_.data.len() / 2 {
+        if self_.dim.size() <= self_.data.0.len() / 2 {
             // Create a new vec if the current view is less than half of
             // backing data.
             unsafe {
@@ -99,18 +101,19 @@ unsafe impl<A> DataMut for OwnedRcRepr<A>
             }
             return;
         }
+        let rcvec = &mut self_.data.0;
         let a_size = mem::size_of::<A>() as isize;
         let our_off = if a_size != 0 {
-            (self_.ptr as isize - self_.data.as_ptr() as isize) / a_size
+            (self_.ptr as isize - rcvec.as_ptr() as isize) / a_size
         } else { 0 };
-        let rvec = Rc::make_mut(&mut self_.data);
+        let rvec = Rc::make_mut(rcvec);
         unsafe {
             self_.ptr = rvec.as_mut_ptr().offset(our_off);
         }
     }
 
     fn is_unique(&mut self) -> bool {
-        Rc::get_mut(self).is_some()
+        Rc::get_mut(&mut self.0).is_some()
     }
 }
 
@@ -124,8 +127,9 @@ unsafe impl<A> DataClone for OwnedRcRepr<A> {
 unsafe impl<A> Data for OwnedRepr<A> {
     type Elem = A;
     fn _data_slice(&self) -> &[A] {
-        self
+        &self.0
     }
+    private_impl!{}
 }
 
 unsafe impl<A> DataMut for OwnedRepr<A> { }
@@ -135,9 +139,9 @@ unsafe impl<A> DataClone for OwnedRepr<A>
 {
     unsafe fn clone_with_ptr(&self, ptr: *mut Self::Elem) -> (Self, *mut Self::Elem) {
         let mut u = self.clone();
-        let mut new_ptr = u.as_mut_ptr();
+        let mut new_ptr = u.0.as_mut_ptr();
         if size_of::<A>() != 0 {
-            let our_off = (ptr as isize - self.as_ptr() as isize) /
+            let our_off = (ptr as isize - self.0.as_ptr() as isize) /
                           mem::size_of::<A>() as isize;
             new_ptr = new_ptr.offset(our_off);
         }
@@ -146,13 +150,13 @@ unsafe impl<A> DataClone for OwnedRepr<A>
 
     unsafe fn clone_from_with_ptr(&mut self, other: &Self, ptr: *mut Self::Elem) -> *mut Self::Elem {
         let our_off = if size_of::<A>() != 0 {
-            (ptr as isize - other.as_ptr() as isize) /
+            (ptr as isize - other.0.as_ptr() as isize) /
                           mem::size_of::<A>() as isize
         } else {
             0
         };
-        self.clone_from(other);
-        self.as_mut_ptr().offset(our_off)
+        self.0.clone_from(&other.0);
+        self.0.as_mut_ptr().offset(our_off)
     }
 }
 
@@ -161,6 +165,7 @@ unsafe impl<'a, A> Data for ViewRepr<&'a A> {
     fn _data_slice(&self) -> &[A] {
         &[]
     }
+    private_impl!{}
 }
 
 unsafe impl<'a, A> DataClone for ViewRepr<&'a A> {
@@ -174,6 +179,7 @@ unsafe impl<'a, A> Data for ViewRepr<&'a mut A> {
     fn _data_slice(&self) -> &[A] {
         &[]
     }
+    private_impl!{}
 }
 
 unsafe impl<'a, A> DataMut for ViewRepr<&'a mut A> { }
@@ -202,16 +208,16 @@ unsafe impl<'a, A> DataShared for ViewRepr<&'a A> {}
 
 unsafe impl<A> DataOwned for OwnedRepr<A> {
     fn new(elements: Vec<A>) -> Self {
-        elements
+        OwnedRepr(elements)
     }
     fn into_shared(self) -> OwnedRcRepr<A> {
-        Rc::new(self)
+        OwnedRcRepr(Rc::new(self.0))
     }
 }
 
 unsafe impl<A> DataOwned for OwnedRcRepr<A> {
     fn new(elements: Vec<A>) -> Self {
-        Rc::new(elements)
+        OwnedRcRepr(Rc::new(elements))
     }
     fn into_shared(self) -> OwnedRcRepr<A> {
         self
diff --git a/src/dimension/dimension_trait.rs b/src/dimension/dimension_trait.rs
index 0251f13e..f2e7b5fe 100644
--- a/src/dimension/dimension_trait.rs
+++ b/src/dimension/dimension_trait.rs
@@ -32,8 +32,8 @@ use super::axes_of;
 /// This trait defines a number of methods and operations that can be used on
 /// dimensions and indices.
 ///
-/// ***Note:*** *Don't implement this trait.*
-pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default +
+/// **Note:** *This trait can not be implemented outside the crate*
+pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default +
     IndexMut<usize, Output=usize> +
     Add<Self, Output=Self> +
     AddAssign + for<'x> AddAssign<&'x Self> +
@@ -47,13 +47,13 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default +
     /// dimension.
     ///
     /// For the fixed size dimensions it is a fixed size array of the correct
-    /// size, which you pass by reference. For the `Vec` dimension it is
+    /// size, which you pass by reference. For the dynamic dimension it is
     /// a slice.
     ///
     /// - For `Ix1`: `[Si; 1]`
     /// - For `Ix2`: `[Si; 2]`
     /// - and so on..
-    /// - For `IxDyn: `[Si]`
+    /// - For `IxDyn`: `[Si]`
     ///
     /// The easiest way to create a `&SliceArg` is using the macro
     /// [`s![]`](macro.s!.html).
@@ -63,11 +63,10 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default +
     /// - For `Ix1`: `usize`,
     /// - For `Ix2`: `(usize, usize)`
     /// - and so on..
-    /// - For `IxDyn: `IxDyn`
+    /// - For `IxDyn`: `IxDyn`
     type Pattern: IntoDimension<Dim=Self>;
-    // Next smaller dimension (if it exists)
-    #[doc(hidden)]
-    type TrySmaller: Dimension;
+    /// Next smaller dimension (if applicable)
+    type Smaller: Dimension;
     #[doc(hidden)]
     fn ndim(&self) -> usize;
 
@@ -347,7 +346,9 @@ pub unsafe trait Dimension : Clone + Eq + Debug + Send + Sync + Default +
     }
 
     #[doc(hidden)]
-    fn try_remove_axis(&self, axis: Axis) -> Self::TrySmaller;
+    fn try_remove_axis(&self, axis: Axis) -> Self::Smaller;
+
+    private_decl!{}
 }
 
 // utility functions
@@ -365,10 +366,10 @@ fn abs_index(len: Ixs, index: Ixs) -> Ix {
 // Dimension impls
 
 
-unsafe impl Dimension for Dim<[Ix; 0]> {
+impl Dimension for Dim<[Ix; 0]> {
     type SliceArg = [Si; 0];
     type Pattern = ();
-    type TrySmaller = Self;
+    type Smaller = Self;
     // empty product is 1 -> size is 1
     #[inline]
     fn ndim(&self) -> usize { 0 }
@@ -385,16 +386,18 @@ unsafe impl Dimension for Dim<[Ix; 0]> {
         None
     }
     #[inline]
-    fn try_remove_axis(&self, _ignore: Axis) -> Self::TrySmaller {
+    fn try_remove_axis(&self, _ignore: Axis) -> Self::Smaller {
         *self
     }
+
+    private_impl!{}
 }
 
 
-unsafe impl Dimension for Dim<[Ix; 1]> {
+impl Dimension for Dim<[Ix; 1]> {
     type SliceArg = [Si; 1];
     type Pattern = Ix;
-    type TrySmaller = <Self as RemoveAxis>::Smaller;
+    type Smaller = Ix0;
     #[inline]
     fn ndim(&self) -> usize { 1 }
     #[inline]
@@ -470,15 +473,16 @@ unsafe impl Dimension for Dim<[Ix; 1]> {
         }
     }
     #[inline]
-    fn try_remove_axis(&self, axis: Axis) -> Self::TrySmaller {
+    fn try_remove_axis(&self, axis: Axis) -> Self::Smaller {
         self.remove_axis(axis)
     }
+    private_impl!{}
 }
 
-unsafe impl Dimension for Dim<[Ix; 2]> {
+impl Dimension for Dim<[Ix; 2]> {
     type SliceArg = [Si; 2];
     type Pattern = (Ix, Ix);
-    type TrySmaller = <Self as RemoveAxis>::Smaller;
+    type Smaller = Ix1;
     #[inline]
     fn ndim(&self) -> usize { 2 }
     #[inline]
@@ -596,15 +600,16 @@ unsafe impl Dimension for Dim<[Ix; 2]> {
         }
     }
     #[inline]
-    fn try_remove_axis(&self, axis: Axis) -> Self::TrySmaller {
+    fn try_remove_axis(&self, axis: Axis) -> Self::Smaller {
         self.remove_axis(axis)
     }
+    private_impl!{}
 }
 
-unsafe impl Dimension for Dim<[Ix; 3]> {
+impl Dimension for Dim<[Ix; 3]> {
     type SliceArg = [Si; 3];
     type Pattern = (Ix, Ix, Ix);
-    type TrySmaller = <Self as RemoveAxis>::Smaller;
+    type Smaller = Ix2;
     #[inline]
     fn ndim(&self) -> usize { 3 }
     #[inline]
@@ -701,17 +706,18 @@ unsafe impl Dimension for Dim<[Ix; 3]> {
         order
     }
     #[inline]
-    fn try_remove_axis(&self, axis: Axis) -> Self::TrySmaller {
+    fn try_remove_axis(&self, axis: Axis) -> Self::Smaller {
         self.remove_axis(axis)
     }
+    private_impl!{}
 }
 
 macro_rules! large_dim {
     ($n:expr, $name:ident, $($ix:ident),+) => (
-        unsafe impl Dimension for Dim<[Ix; $n]> {
+        impl Dimension for Dim<[Ix; $n]> {
             type SliceArg = [Si; $n];
             type Pattern = ($($ix,)*);
-            type TrySmaller = <Self as RemoveAxis>::Smaller;
+            type Smaller = Dim<[Ix; $n - 1]>;
             #[inline]
             fn ndim(&self) -> usize { $n }
             #[inline]
@@ -723,9 +729,10 @@ macro_rules! large_dim {
             #[inline]
             fn slice_mut(&mut self) -> &mut [Ix] { self.ixm() }
             #[inline]
-            fn try_remove_axis(&self, axis: Axis) -> Self::TrySmaller {
+            fn try_remove_axis(&self, axis: Axis) -> Self::Smaller {
                 self.remove_axis(axis)
             }
+            private_impl!{}
         }
     )
 }
@@ -736,11 +743,11 @@ large_dim!(6, Ix6, Ix, Ix, Ix, Ix, Ix, Ix);
 
 /// IxDyn is a "dynamic" index, pretty hard to use when indexing,
 /// and memory wasteful, but it allows an arbitrary and dynamic number of axes.
-unsafe impl Dimension for IxDyn
+impl Dimension for IxDyn
 {
     type SliceArg = [Si];
     type Pattern = Self;
-    type TrySmaller = <Self as RemoveAxis>::Smaller;
+    type Smaller = Self;
     #[inline]
     fn ndim(&self) -> usize { self.ix().len() }
     #[inline]
@@ -752,13 +759,14 @@ unsafe impl Dimension for IxDyn
         self
     }
     #[inline]
-    fn try_remove_axis(&self, axis: Axis) -> Self::TrySmaller {
+    fn try_remove_axis(&self, axis: Axis) -> Self::Smaller {
         if self.ndim() > 0 {
             self.remove_axis(axis)
         } else {
             self.clone()
         }
     }
+    private_impl!{}
 }
 
 impl<J> Index<J> for Dim<IxDynImpl>
diff --git a/src/dimension/dynindeximpl.rs b/src/dimension/dynindeximpl.rs
index 6f29d578..96e39616 100644
--- a/src/dimension/dynindeximpl.rs
+++ b/src/dimension/dynindeximpl.rs
@@ -203,7 +203,6 @@ impl<'a> IntoIterator for &'a IxDynImpl {
 }
 
 impl RemoveAxis for Dim<IxDynImpl> {
-    type Smaller = Self;
     fn remove_axis(&self, axis: Axis) -> Self {
         debug_assert!(axis.index() < self.ndim());
         Dim::new(self.ix().remove(axis.index()))
diff --git a/src/dimension/remove_axis.rs b/src/dimension/remove_axis.rs
index 83fa3b8b..7325a1cc 100644
--- a/src/dimension/remove_axis.rs
+++ b/src/dimension/remove_axis.rs
@@ -15,18 +15,15 @@ use super::DimPrivate;
 /// `RemoveAxis` defines a larger-than relation for array shapes:
 /// removing one axis from *Self* gives smaller dimension *Smaller*.
 pub trait RemoveAxis : Dimension {
-    type Smaller: Dimension;
     fn remove_axis(&self, axis: Axis) -> Self::Smaller;
 }
 
 impl RemoveAxis for Dim<[Ix; 1]> {
-    type Smaller = Ix0;
     #[inline]
     fn remove_axis(&self, _: Axis) -> Ix0 { Ix0() }
 }
 
 impl RemoveAxis for Dim<[Ix; 2]> {
-    type Smaller = Ix1;
     #[inline]
     fn remove_axis(&self, axis: Axis) -> Ix1 {
         let axis = axis.index();
@@ -40,7 +37,6 @@ macro_rules! impl_remove_axis_array(
     $(
         impl RemoveAxis for Dim<[Ix; $n]>
         {
-            type Smaller = Dim<[Ix; $n - 1]>;
             #[inline]
             fn remove_axis(&self, axis: Axis) -> Self::Smaller {
                 let mut tup = Dim([0; $n - 1]);
diff --git a/src/impl_methods.rs b/src/impl_methods.rs
index 4db0e0c4..ae4a6563 100644
--- a/src/impl_methods.rs
+++ b/src/impl_methods.rs
@@ -27,6 +27,8 @@ use iterators::{
     new_inners_mut,
     whole_chunks_of,
     whole_chunks_mut_of,
+    Inners,
+    InnersMut,
 };
 use zip::Zip;
 
@@ -38,8 +40,6 @@ use {
     IterMut,
     IndexedIter,
     IndexedIterMut,
-    InnerIter,
-    InnerIterMut,
     AxisIter,
     AxisIterMut,
     WholeChunks,
@@ -360,8 +360,7 @@ impl<A, S, D> ArrayBase<S, D> where S: Data<Elem=A>, D: Dimension
     ///     a.subview(Axis(1), 1) == ArrayView::from(&[2., 4., 6.])
     /// );
     /// ```
-    pub fn subview(&self, axis: Axis, index: Ix)
-        -> ArrayView<A, <D as RemoveAxis>::Smaller>
+    pub fn subview(&self, axis: Axis, index: Ix) -> ArrayView<A, D::Smaller>
         where D: RemoveAxis,
     {
         self.view().into_subview(axis, index)
@@ -459,36 +458,130 @@ impl<A, S, D> ArrayBase<S, D> where S: Data<Elem=A>, D: Dimension
         }
     }
 
-    /// Return an iterator that traverses over all dimensions but the innermost,
-    /// and yields each inner row.
+    /// Return a producer and iterable that traverses over all lanes
+    /// pointing in the direction of `axis`.
     ///
     /// For example, in a 2 × 2 × 3 array, the iterator element
     /// is a row of 3 elements (and there are 2 × 2 = 4 rows in total).
     ///
+    /// Iterator element is `ArrayView1<A>` (1D array view); note that it is
+    /// always 1D.
+    ///
+    /// ```
+    /// use ndarray::{arr3, aview1, Axis};
+    ///
+    /// let a = arr3(&[[[ 0,  1,  2],
+    ///                 [ 3,  4,  5]],
+    ///                [[ 6,  7,  8],
+    ///                 [ 9, 10, 11]]]);
+    ///
+    /// let inner0 = a.inners(Axis(0));
+    /// let inner1 = a.inners(Axis(1));
+    /// let inner2 = a.inners(Axis(2));
+    ///
+    /// // The first lane for axis 0 is [0, 6]
+    /// assert_eq!(inner0.into_iter().next().unwrap(), aview1(&[0, 6]));
+    /// // The first lane for axis 1 is [0, 3]
+    /// assert_eq!(inner1.into_iter().next().unwrap(), aview1(&[0, 3]));
+    /// // The first lane for axis 2 is [0, 1, 2]
+    /// assert_eq!(inner2.into_iter().next().unwrap(), aview1(&[0, 1, 2]));
+    /// ```
+    pub fn inners(&self, axis: Axis) -> Inners<A, D::Smaller> {
+        new_inners(self.view(), axis)
+    }
+
+    /// Return a producer and iterable that traverses over all axes but the
+    /// selected axis.
+    ///
+    /// Iterator element is `ArrayViewMut1<A>` (1D read-write array view).
+    pub fn inners_mut(&mut self, axis: Axis) -> InnersMut<A, D::Smaller>
+        where S: DataMut
+    {
+        new_inners_mut(self.view_mut(), axis)
+    }
+
+    /// Return a producer and iterable that traverses over the *generalized*
+    /// rows of the array. For a 2D array these are the regular rows.
+    ///
+    /// This is equivalent to `.inners(Axis(n - 1))` where *n* is `self.ndim()`.
+    ///
+    /// For an array of dimensions *a* × *b* × *c* × ... × *l* × *m*
+    /// it has *a* × *b* × *c* × ... × *l* rows each of length *m*.
+    ///
+    /// For example, in a 2 × 2 × 3 array, each row is 3 elements long
+    /// and there are 2 × 2 = 4 rows in total.
+    ///
     /// Iterator element is `ArrayView1<A>` (1D array view).
     ///
     /// ```
-    /// use ndarray::arr3;
+    /// use ndarray::{arr3, Axis, arr1};
+    ///
     /// let a = arr3(&[[[ 0,  1,  2],    // -- row 0, 0
     ///                 [ 3,  4,  5]],   // -- row 0, 1
     ///                [[ 6,  7,  8],    // -- row 1, 0
     ///                 [ 9, 10, 11]]]); // -- row 1, 1
-    /// // `inner_iter` yields the four inner rows of the 3D array.
-    /// let mut row_sums = a.inner_iter().map(|v| v.scalar_sum());
-    /// assert_eq!(row_sums.collect::<Vec<_>>(), vec![3, 12, 21, 30]);
+    ///
+    /// // `genrows` will yield the four generalized rows of the array.
+    /// for row in a.genrows() {
+    ///     /* loop body */
+    /// }
     /// ```
-    pub fn inner_iter(&self) -> InnerIter<A, D> {
-        iterators::new_inner_iter(self.view())
+    pub fn genrows(&self) -> Inners<A, D::Smaller> {
+        let mut n = self.ndim();
+        if n == 0 { n += 1; }
+        new_inners(self.view(), Axis(n - 1))
     }
 
-    /// Return an iterator that traverses over all dimensions but the innermost,
-    /// and yields each inner row.
+    /// Return a producer and iterable that traverses over the *generalized*
+    /// rows of the array and yields mutable array views.
     ///
-    /// Iterator element is `ArrayViewMut1<A>` (1D read-write array view).
-    pub fn inner_iter_mut(&mut self) -> InnerIterMut<A, D>
+    /// Iterator element is `ArrayView1<A>` (1D read-write array view).
+    pub fn genrows_mut(&mut self) -> InnersMut<A, D::Smaller>
+        where S: DataMut
+    {
+        let mut n = self.ndim();
+        if n == 0 { n += 1; }
+        new_inners_mut(self.view_mut(), Axis(n - 1))
+    }
+
+    /// Return a producer and iterable that traverses over the *generalized*
+    /// columns of the array. For a 2D array these are the regular columns.
+    ///
+    /// This is equivalent to `.inners(Axis(0))`.
+    ///
+    /// For an array of dimensions *a* × *b* × *c* × ... × *l* × *m*
+    /// it has *b* × *c* × ... × *l* × *m* columns each of length *a*.
+    ///
+    /// For example, in a 2 × 2 × 3 array, each column is 2 elements long
+    /// and there are 2 × 3 = 6 columns in total.
+    ///
+    /// Iterator element is `ArrayView1<A>` (1D array view).
+    ///
+    /// ```
+    /// use ndarray::{arr3, Axis, arr1};
+    ///
+    /// // The generalized columns of a 3D array:
+    /// // are directed along the 0th axis: 0 and 6, 1 and 7 and so on...
+    /// let a = arr3(&[[[ 0,  1,  2], [ 3,  4,  5]],
+    ///                [[ 6,  7,  8], [ 9, 10, 11]]]);
+    ///
+    /// // Here `gencolumns` will yield the six generalized columns of the array.
+    /// for row in a.gencolumns() {
+    ///     /* loop body */
+    /// }
+    /// ```
+    pub fn gencolumns(&self) -> Inners<A, D::Smaller> {
+        new_inners(self.view(), Axis(0))
+    }
+
+    /// Return a producer and iterable that traverses over the *generalized*
+    /// columns of the array and yields mutable array views.
+    ///
+    /// Iterator element is `ArrayView1<A>` (1D read-write array view).
+    pub fn gencolumns_mut(&mut self) -> InnersMut<A, D::Smaller>
         where S: DataMut
     {
-        iterators::new_inner_iter_mut(self.view_mut())
+        new_inners_mut(self.view_mut(), Axis(0))
     }
 
     /// Return an iterator that traverses over the outermost dimension
diff --git a/src/impl_owned_array.rs b/src/impl_owned_array.rs
index 5d90c023..9ac644aa 100644
--- a/src/impl_owned_array.rs
+++ b/src/impl_owned_array.rs
@@ -16,7 +16,7 @@ impl<A, D> ArrayBase<OwnedRepr<A>, D>
     /// If the array is in standard memory layout, the logical element order
     /// of the array (`.iter()` order) and of the returned vector will be the same.
     pub fn into_raw_vec(self) -> Vec<A> {
-        self.data
+        self.data.0
     }
 }
 
@@ -29,7 +29,7 @@ impl<A, D> ArrayBase<OwnedRcRepr<A>, D>
     /// them if necessary.
     pub fn into_owned(mut self) -> Array<A, D> {
         <_>::ensure_unique(&mut self);
-        let data = Rc::try_unwrap(self.data).ok().unwrap();
+        let data = OwnedRepr(Rc::try_unwrap(self.data.0).ok().unwrap());
         ArrayBase {
             data: data,
             ptr: self.ptr,
diff --git a/src/iterators/inners.rs b/src/iterators/inners.rs
index b8dd4e4b..7513d558 100644
--- a/src/iterators/inners.rs
+++ b/src/iterators/inners.rs
@@ -22,6 +22,8 @@ impl_ndproducer! {
     }
 }
 
+/// See [`.inners()`](struct.ArrayBase.html#method.inners)
+/// for more information.
 pub struct Inners<'a, A: 'a, D> {
     base: ArrayView<'a, A, D>,
     inner_len: Ix,
@@ -30,7 +32,7 @@ pub struct Inners<'a, A: 'a, D> {
 
 
 pub fn new_inners<A, D>(v: ArrayView<A, D>, axis: Axis)
-    -> Inners<A, D::TrySmaller>
+    -> Inners<A, D::Smaller>
     where D: Dimension
 {
     let ndim = v.ndim();
@@ -86,6 +88,8 @@ impl<'a, A, D> IntoIterator for Inners<'a, A, D>
     }
 }
 
+/// See [`.inners_mut()`](struct.ArrayBase.html#method.inners_mut)
+/// for more information.
 pub struct InnersMut<'a, A: 'a, D> {
     base: ArrayViewMut<'a, A, D>,
     inner_len: Ix,
@@ -94,7 +98,7 @@ pub struct InnersMut<'a, A: 'a, D> {
 
 
 pub fn new_inners_mut<A, D>(v: ArrayViewMut<A, D>, axis: Axis)
-    -> InnersMut<A, D::TrySmaller>
+    -> InnersMut<A, D::Smaller>
     where D: Dimension
 {
     let ndim = v.ndim();
diff --git a/src/iterators/mod.rs b/src/iterators/mod.rs
index ff69b113..80c2a9a0 100644
--- a/src/iterators/mod.rs
+++ b/src/iterators/mod.rs
@@ -417,36 +417,13 @@ impl<'a, A, D> ExactSizeIterator for IndexedIterMut<'a, A, D>
 /// An iterator that traverses over all dimensions but the innermost,
 /// and yields each inner row.
 ///
-/// See [`.inner_iter()`](struct.ArrayBase.html#method.inner_iter) for more information.
+/// See [`.inners()`](struct.ArrayBase.html#method.inners) for more information.
 pub struct InnerIter<'a, A: 'a, D> {
     inner_len: Ix,
     inner_stride: Ixs,
     iter: Baseiter<'a, A, D>,
 }
 
-pub fn new_inner_iter<A, D>(mut v: ArrayView<A, D>) -> InnerIter<A, D>
-    where D: Dimension
-{
-    let ndim = v.ndim();
-    if ndim == 0 {
-        InnerIter {
-            inner_len: 1,
-            inner_stride: 1,
-            iter: v.into_base_iter(),
-        }
-    } else {
-        // Set length of innerest dimension to 1, start iteration
-        let len = v.dim.last_elem();
-        let stride = v.strides.last_elem() as isize;
-        v.dim.set_last_elem(1);
-        InnerIter {
-            inner_len: len,
-            inner_stride: stride,
-            iter: v.into_base_iter(),
-        }
-    }
-}
-
 impl<'a, A, D> Iterator for InnerIter<'a, A, D>
     where D: Dimension
 {
@@ -477,7 +454,7 @@ impl<'a, A, D> ExactSizeIterator for InnerIter<'a, A, D>
 /// An iterator that traverses over all dimensions but the innermost,
 /// and yields each inner row (mutable).
 ///
-/// See [`.inner_iter_mut()`](struct.ArrayBase.html#method.inner_iter_mut)
+/// See [`.inners_mut()`](struct.ArrayBase.html#method.inners_mut)
 /// for more information.
 pub struct InnerIterMut<'a, A: 'a, D> {
     inner_len: Ix,
@@ -485,29 +462,6 @@ pub struct InnerIterMut<'a, A: 'a, D> {
     iter: Baseiter<'a, A, D>,
 }
 
-pub fn new_inner_iter_mut<A, D>(mut v: ArrayViewMut<A, D>) -> InnerIterMut<A, D>
-    where D: Dimension,
-{
-    let ndim = v.ndim();
-    if ndim == 0 {
-        InnerIterMut {
-            inner_len: 1,
-            inner_stride: 1,
-            iter: v.into_base_iter(),
-        }
-    } else {
-        // Set length of innerest dimension to 1, start iteration
-        let len = v.dim.last_elem();
-        let stride = v.strides.last_elem() as isize;
-        v.dim.set_last_elem(1);
-        InnerIterMut {
-            inner_len: len,
-            inner_stride: stride,
-            iter: v.into_base_iter(),
-        }
-    }
-}
-
 impl<'a, A, D> Iterator for InnerIterMut<'a, A, D>
     where D: Dimension,
 {
@@ -534,57 +488,6 @@ impl<'a, A, D> ExactSizeIterator for InnerIterMut<'a, A, D>
     }
 }
 
-#[cfg(next_version)]
-/// Create an InnerIter one dimension smaller than D (if possible)
-pub fn new_inner_iter_smaller<A, D>(v: ArrayView<A, D>)
-    -> InnerIter<A, D::TrySmaller>
-    where D: Dimension
-{
-    let ndim = v.ndim();
-    let len;
-    let stride;
-    let iter_v;
-    if ndim == 0 {
-        len = 1;
-        stride = 0;
-        iter_v = v.try_remove_axis(Axis(0))
-    } else {
-        len = v.dim.last_elem();
-        stride = v.strides.last_elem() as isize;
-        iter_v = v.try_remove_axis(Axis(ndim - 1))
-    }
-    InnerIter {
-        inner_len: len,
-        inner_stride: stride,
-        iter: iter_v.into_base_iter(),
-    }
-}
-
-#[cfg(next_version)]
-pub fn new_inner_iter_smaller_mut<A, D>(v: ArrayViewMut<A, D>)
-    -> InnerIterMut<A, D::TrySmaller>
-    where D: Dimension,
-{
-    let ndim = v.ndim();
-    let len;
-    let stride;
-    let iter_v;
-    if ndim == 0 {
-        len = 1;
-        stride = 0;
-        iter_v = v.try_remove_axis(Axis(0))
-    } else {
-        len = v.dim.last_elem();
-        stride = v.strides.last_elem() as isize;
-        iter_v = v.try_remove_axis(Axis(ndim - 1))
-    }
-    InnerIterMut {
-        inner_len: len,
-        inner_stride: stride,
-        iter: iter_v.into_base_iter(),
-    }
-}
-
 #[derive(Debug)]
 pub struct OuterIterCore<A, D> {
     index: Ix,
diff --git a/src/lib.rs b/src/lib.rs
index 7b161179..5b9f9745 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -45,6 +45,7 @@
 //!     needs matching memory layout to be efficient (with some exceptions).
 //!   + Efficient floating point matrix multiplication even for very large
 //!     matrices; can optionally use BLAS to improve it further.
+//! - Requires Rust 1.15
 //!
 //! ## Crate Feature Flags
 //!
@@ -102,6 +103,8 @@ pub use si::{Si, S};
 
 use iterators::Baseiter;
 pub use iterators::{
+    Inners,
+    InnersMut,
     InnerIter,
     InnerIterMut,
     AxisIter,
@@ -177,6 +180,7 @@ mod imp_prelude {
         DataOwned,
         DataShared,
         ViewRepr,
+        Ix, Ixs,
     };
     pub use dimension::DimensionExt;
     /// Wrapper type for private methods
@@ -572,10 +576,19 @@ pub type ArrayView<'a, A, D> = ArrayBase<ViewRepr<&'a A>, D>;
 pub type ArrayViewMut<'a, A, D> = ArrayBase<ViewRepr<&'a mut A>, D>;
 
 /// Array's representation.
-type OwnedRepr<A> = Vec<A>;
+#[derive(Clone, Debug)]
+pub struct OwnedRepr<A>(Vec<A>);
 
 /// RcArray's representation.
-type OwnedRcRepr<A> = Rc<Vec<A>>;
+#[derive(Debug)]
+pub struct OwnedRcRepr<A>(Rc<Vec<A>>);
+
+
+impl<A> Clone for OwnedRcRepr<A> {
+    fn clone(&self) -> Self {
+        OwnedRcRepr(self.0.clone())
+    }
+}
 
 /// Array view’s representation.
 #[derive(Copy, Clone)]
@@ -661,7 +674,7 @@ impl<A, S, D> ArrayBase<S, D>
     }
 
     /// Remove array axis `axis` and return the result.
-    fn try_remove_axis(self, axis: Axis) -> ArrayBase<S, D::TrySmaller>
+    fn try_remove_axis(self, axis: Axis) -> ArrayBase<S, D::Smaller>
     {
         let d = self.dim.try_remove_axis(axis);
         let s = self.strides.try_remove_axis(axis);
@@ -674,14 +687,14 @@ impl<A, S, D> ArrayBase<S, D>
     }
 
     /// n-d generalization of rows, just like inner iter
-    fn inner_rows(&self) -> iterators::Inners<A, D::TrySmaller>
+    fn inner_rows(&self) -> iterators::Inners<A, D::Smaller>
     {
         let n = self.ndim();
         iterators::new_inners(self.view(), Axis(n.saturating_sub(1)))
     }
 
     /// n-d generalization of rows, just like inner iter
-    fn inner_rows_mut(&mut self) -> iterators::InnersMut<A, D::TrySmaller>
+    fn inner_rows_mut(&mut self) -> iterators::InnersMut<A, D::Smaller>
         where S: DataMut
     {
         let n = self.ndim();
diff --git a/src/numeric/impl_numeric.rs b/src/numeric/impl_numeric.rs
index e02e7eaf..4f23ab0a 100644
--- a/src/numeric/impl_numeric.rs
+++ b/src/numeric/impl_numeric.rs
@@ -66,7 +66,7 @@ impl<A, S, D> ArrayBase<S, D>
     /// ```
     ///
     /// **Panics** if `axis` is out of bounds.
-    pub fn sum(&self, axis: Axis) -> Array<A, <D as RemoveAxis>::Smaller>
+    pub fn sum(&self, axis: Axis) -> Array<A, D::Smaller>
         where A: Clone + Zero + Add<Output=A>,
               D: RemoveAxis,
     {
@@ -102,7 +102,7 @@ impl<A, S, D> ArrayBase<S, D>
     ///     a.mean(Axis(1)) == aview1(&[1.5, 3.5])
     /// );
     /// ```
-    pub fn mean(&self, axis: Axis) -> Array<A, <D as RemoveAxis>::Smaller>
+    pub fn mean(&self, axis: Axis) -> Array<A, D::Smaller>
         where A: LinalgScalar,
               D: RemoveAxis,
     {
diff --git a/src/prelude.rs b/src/prelude.rs
index b2572d92..9c281386 100644
--- a/src/prelude.rs
+++ b/src/prelude.rs
@@ -31,7 +31,6 @@ pub use {
 pub use {
     Axis,
     Dim,
-    Ix, Ixs,
     Dimension,
 };
 
diff --git a/src/zip/mod.rs b/src/zip/mod.rs
index 3931a0fe..0aedfd0f 100644
--- a/src/zip/mod.rs
+++ b/src/zip/mod.rs
@@ -118,12 +118,16 @@ impl<D> Splittable for D
 ///
 /// Slices and vectors can be used (equivalent to 1-dimensional array views).
 pub trait IntoNdProducer {
+    /// The element produced per iteration.
+    type Item;
+    /// Dimension type of the producer
     type Dim: Dimension;
-    type Output: NdProducer<Dim=Self::Dim>;
+    type Output: NdProducer<Dim=Self::Dim, Item=Self::Item>;
     fn into_producer(self) -> Self::Output;
 }
 
 impl<P> IntoNdProducer for P where P: NdProducer {
+    type Item = P::Item;
     type Dim = P::Dim;
     type Output = Self;
     fn into_producer(self) -> Self::Output { self }
@@ -189,6 +193,7 @@ impl<'a, A: 'a, S, D> IntoNdProducer for &'a ArrayBase<S, D>
 {
     type Dim = D;
     type Output = ArrayView<'a, A, D>;
+    type Item = &'a A;
     fn into_producer(self) -> Self::Output {
         self.view()
     }
@@ -202,6 +207,7 @@ impl<'a, A: 'a, S, D> IntoNdProducer for &'a mut ArrayBase<S, D>
 {
     type Dim = D;
     type Output = ArrayViewMut<'a, A, D>;
+    type Item = &'a mut A;
     fn into_producer(self) -> Self::Output {
         self.view_mut()
     }
@@ -211,6 +217,7 @@ impl<'a, A: 'a, S, D> IntoNdProducer for &'a mut ArrayBase<S, D>
 impl<'a, A: 'a> IntoNdProducer for &'a [A] {
     type Dim = Ix1;
     type Output = ArrayView1<'a, A>;
+    type Item = <Self::Output as NdProducer>::Item;
     fn into_producer(self) -> Self::Output {
         <_>::from(self)
     }
@@ -220,6 +227,7 @@ impl<'a, A: 'a> IntoNdProducer for &'a [A] {
 impl<'a, A: 'a> IntoNdProducer for &'a mut [A] {
     type Dim = Ix1;
     type Output = ArrayViewMut1<'a, A>;
+    type Item = <Self::Output as NdProducer>::Item;
     fn into_producer(self) -> Self::Output {
         <_>::from(self)
     }
@@ -229,6 +237,7 @@ impl<'a, A: 'a> IntoNdProducer for &'a mut [A] {
 impl<'a, A: 'a> IntoNdProducer for &'a Vec<A> {
     type Dim = Ix1;
     type Output = ArrayView1<'a, A>;
+    type Item = <Self::Output as NdProducer>::Item;
     fn into_producer(self) -> Self::Output {
         <_>::from(self)
     }
@@ -238,6 +247,7 @@ impl<'a, A: 'a> IntoNdProducer for &'a Vec<A> {
 impl<'a, A: 'a> IntoNdProducer for &'a mut Vec<A> {
     type Dim = Ix1;
     type Output = ArrayViewMut1<'a, A>;
+    type Item = <Self::Output as NdProducer>::Item;
     fn into_producer(self) -> Self::Output {
         <_>::from(self)
     }
@@ -362,8 +372,8 @@ impl<'a, A, D> NdProducer for ArrayViewMut<'a, A, D>
 /// have to have the same element type.
 ///
 /// The `Zip` has two methods for function application: `apply` and
-/// `fold_while`. These can be called several times on the same zip object. The
-/// zip object can be split, which allows parallelization.
+/// `fold_while`. The zip object can be split, which allows parallelization.
+/// A read-only zip object (no mutable producers) can be cloned.
 ///
 /// See also the [`azip!()` macro][az] which offers a convenient shorthand
 /// to common ways to use `Zip`.
@@ -405,7 +415,7 @@ impl<P, D> Zip<(P, ), D>
     /// The Zip will take the exact dimension of `p` and all inputs
     /// must have the same dimensions (or be broadcast to them).
     pub fn from<IP>(p: IP) -> Self
-        where IP: IntoNdProducer<Dim=D, Output=P>
+        where IP: IntoNdProducer<Dim=D, Output=P, Item=P::Item>
     {
         let array = p.into_producer();
         let dim = array.raw_dim();
@@ -649,7 +659,7 @@ macro_rules! map_impl {
         impl<D: Dimension, $($p: NdProducer<Dim=D>),*> Zip<($($p,)*), D> {
             /// Apply a function to all elements of the input arrays,
             /// visiting elements in lock step.
-            pub fn apply<F>(&mut self, mut function: F)
+            pub fn apply<F>(mut self, mut function: F)
                 where F: FnMut($($p::Item),*)
             {
                 self.apply_core((), move |(), args| {
@@ -663,7 +673,7 @@ macro_rules! map_impl {
             ///
             /// The fold continues while the return value is a
             /// `FoldWhile::Continue`.
-            pub fn fold_while<F, Acc>(&mut self, acc: Acc, mut function: F)
+            pub fn fold_while<F, Acc>(mut self, acc: Acc, mut function: F)
                 -> FoldWhile<Acc>
                 where F: FnMut(Acc, $($p::Item),*) -> FoldWhile<Acc>
             {
@@ -699,7 +709,7 @@ macro_rules! map_impl {
             /// ***Panics*** if broadcasting isn’t possible.
             pub fn and_broadcast<'a, P, D2, Elem>(self, p: P)
                 -> Zip<($($p,)* ArrayView<'a, Elem, D>, ), D>
-                where P: IntoNdProducer<Dim=D2, Output=ArrayView<'a, Elem, D2>>,
+                where P: IntoNdProducer<Dim=D2, Output=ArrayView<'a, Elem, D2>, Item=&'a Elem>,
                       D2: Dimension,
             {
                 let array = p.into_producer().broadcast_unwrap(self.dimension.clone());


Test patch:
diff --git a/tests/array.rs b/tests/array.rs
index f0770aa5..ec614238 100644
--- a/tests/array.rs
+++ b/tests/array.rs
@@ -925,7 +925,7 @@ fn test_f_order() {
     assert_eq!(c.strides(), &[3, 1]);
     assert_eq!(f.strides(), &[1, 2]);
     itertools::assert_equal(f.iter(), c.iter());
-    itertools::assert_equal(f.inner_iter(), c.inner_iter());
+    itertools::assert_equal(f.genrows(), c.genrows());
     itertools::assert_equal(f.outer_iter(), c.outer_iter());
     itertools::assert_equal(f.axis_iter(Axis(0)), c.axis_iter(Axis(0)));
     itertools::assert_equal(f.axis_iter(Axis(1)), c.axis_iter(Axis(1)));
diff --git a/tests/azip.rs b/tests/azip.rs
index fe2a5cab..4586f1a2 100644
--- a/tests/azip.rs
+++ b/tests/azip.rs
@@ -131,3 +131,21 @@ fn test_contiguous_but_not_c_or_f() {
     assert_eq!(ans[[0, 1, 2]], correct_012);
     assert_eq!(ans, correct);
 }
+
+
+#[test]
+fn test_clone() {
+    let a = Array::from_iter(0..27).into_shape((3, 3, 3)).unwrap();
+
+    let z = Zip::from(&a).and(a.whole_chunks((1, 1, 1)));
+    let w = z.clone();
+    let mut result = Vec::new();
+    z.apply(|x, y| {
+        result.push((x, y));
+    });
+    let mut i = 0;
+    w.apply(|x, y| {
+        assert_eq!(result[i], (x, y));
+        i += 1;
+    });
+}
diff --git a/tests/format.rs b/tests/format.rs
index c3adb2a2..d5c8e4d7 100644
--- a/tests/format.rs
+++ b/tests/format.rs
@@ -21,8 +21,8 @@ fn formatting()
                "[[1, 2],\n [3, 4]]");
     assert_eq!(format!("{}", a),
                "[[1, 2],\n [3, 4]]");
-    assert_eq!(format!("{:#4}", a),
-               "[[   1,    2], [   3,    4]]");
+    assert_eq!(format!("{:4}", a),
+               "[[   1,    2],\n [   3,    4]]");
 
     let b = arr0::<f32>(3.5);
     assert_eq!(format!("{}", b),
diff --git a/tests/iterators.rs b/tests/iterators.rs
index 9c9d58c4..8333d07b 100644
--- a/tests/iterators.rs
+++ b/tests/iterators.rs
@@ -129,13 +129,13 @@ fn inner_iter() {
     //  [[6, 7],
     //   [8, 9],
     //    ...
-    assert_equal(a.inner_iter(),
+    assert_equal(a.genrows(),
                  vec![aview1(&[0, 1]), aview1(&[2, 3]), aview1(&[4, 5]),
                       aview1(&[6, 7]), aview1(&[8, 9]), aview1(&[10, 11])]);
     let mut b = RcArray::zeros((2, 3, 2));
     b.swap_axes(0, 2);
     b.assign(&a);
-    assert_equal(b.inner_iter(),
+    assert_equal(b.genrows(),
                  vec![aview1(&[0, 1]), aview1(&[2, 3]), aview1(&[4, 5]),
                       aview1(&[6, 7]), aview1(&[8, 9]), aview1(&[10, 11])]);
 }
@@ -143,14 +143,14 @@ fn inner_iter() {
 #[test]
 fn inner_iter_corner_cases() {
     let a0 = RcArray::zeros(());
-    assert_equal(a0.inner_iter(), vec![aview1(&[0])]);
+    assert_equal(a0.genrows(), vec![aview1(&[0])]);
 
     let a2 = RcArray::<i32, _>::zeros((0, 3));
-    assert_equal(a2.inner_iter(),
+    assert_equal(a2.genrows(),
                  vec![aview1(&[]); 0]);
 
     let a2 = RcArray::<i32, _>::zeros((3, 0));
-    assert_equal(a2.inner_iter(),
+    assert_equal(a2.genrows(),
                  vec![aview1(&[]); 3]);
 }
 
@@ -159,7 +159,7 @@ fn inner_iter_size_hint() {
     // Check that the size hint is correctly computed
     let a = RcArray::from_iter(0..24).reshape((2, 3, 4));
     let mut len = 6;
-    let mut it = a.inner_iter();
+    let mut it = a.genrows().into_iter();
     assert_eq!(it.len(), len);
     while len > 0 {
         it.next();
@@ -193,7 +193,7 @@ fn outer_iter() {
             found_rows.push(row);
         }
     }
-    assert_equal(a.inner_iter(), found_rows.clone());
+    assert_equal(a.genrows(), found_rows.clone());
 
     let mut found_rows_rev = Vec::new();
     for sub in b.outer_iter().rev() {
@@ -219,7 +219,7 @@ fn outer_iter() {
         }
     }
     println!("{:#?}", found_rows);
-    assert_equal(a.inner_iter(), found_rows);
+    assert_equal(a.genrows(), found_rows);
 }
 
 #[test]
@@ -272,7 +272,7 @@ fn outer_iter_mut() {
             found_rows.push(row);
         }
     }
-    assert_equal(a.inner_iter(), found_rows);
+    assert_equal(a.genrows(), found_rows);
 }
 
 #[test]
@@ -471,8 +471,8 @@ fn iterators_are_send_sync() {
     _send_sync(&a.iter_mut());
     _send_sync(&a.indexed_iter());
     _send_sync(&a.indexed_iter_mut());
-    _send_sync(&a.inner_iter());
-    _send_sync(&a.inner_iter_mut());
+    _send_sync(&a.genrows());
+    _send_sync(&a.genrows_mut());
     _send_sync(&a.outer_iter());
     _send_sync(&a.outer_iter_mut());
     _send_sync(&a.axis_iter(Axis(1)));
diff --git a/tests/oper.rs b/tests/oper.rs
index 201cb906..400bd89c 100644
--- a/tests/oper.rs
+++ b/tests/oper.rs
@@ -6,6 +6,7 @@ use ndarray::{rcarr1, rcarr2};
 use ndarray::{LinalgScalar, Data};
 use ndarray::linalg::general_mat_mul;
 use ndarray::Si;
+use ndarray::{Ix, Ixs};
 
 use std::fmt;
 use num_traits::Float;