Repository: rust-ndarray/ndarray
Pull request #1310 (2023-07-25 22:09:26)

Better shape: Deprecate reshape, into_shape
into_shape has some slightly questionable default behaviour w.r.t how it handles memory layout. The newer to_shape() fixes those problems! You should use to_shape() if you can.

Into shape doesn't do it /wrong/ but when it has a successful result, it preserves memory layout. C in gives C out. F in gives F out. But if you don't know what memory layout you have going in, into_shape can surprise you.

----

In this PR:

- `into_shape()`  *deprecated*
- `into_shape_with_order()` *new*
- `reshape()`  *deprecated*
- `into_shape_clone()` *new*

It's not a breaking change, but it introduces deprecations that will be quite loud.

Examples:

- `into_shape` unchanged but deprecated
- `.into_shape_with_order((2, 3))`  same as `Order::RowMajor` below
- `.into_shape_with_order(((2, 3), Order::RowMajor))`  reshapes row major arrays, errors on other.
- `.into_shape_with_order(((2, 3), Order::ColMajor))`  reshapes col major arrays, errors on other.

----

Into shape tries to be too great method:

- User doesn't have to specify index ordering, it just guesses
- It doesn't fall back to copy or clone
  - Useful for: Owned arrays with non-clonable elements
  - Useful for views: We can't fall back to cloning when reshaping a view

Into shape has a niche. Especially the no-copy shape transformation of views is very useful.
But the interface is not great about communicating the magic, in some ways.

This PR is a draft because it's not yet decided exactly what the into shape interface should be.
If we could, the order argument should always have been present. But we'd like to be backwards compatible as far as possible as we can, there must be many thousands of into shape calls out there.


bluss: to_shape assumes RowMajor when nothing is specified by the caller, while into_shape picks whichever seems to fit with the array that is given (true for into_shape both before this PR and after it in its current shape).

to_shape is great because its only precondition for success (not error) is that the requested shape has the same number of elements. It can handle either ordering request. Simple math for the user :)

into_shape is great because it can reshape views. But it has a precondition that the input array is exactly C-contig or F-contig, unfortunately.

Reshaping by following RowMajor or ColumnMajor index ordering has different effects, it has a different result. This is why it's quite dangerous to do what `into_shape` does, which is to just pick whatever seems to fit with the given array. The distinction might have been invisible to the user.

It's a documentation and API issue, how to, for `into_shape` and reshaping in general

- Continue providing easy to use APIs
- Make the preconditions clear
- Find the right level of "Do What I Mean"
bluss: If I could, I would deprecate and remove into_shape (because it has the "wrong" ordering defaults.). Then add it back with the right defaults.

But I think that causes too much churn in user code, so I'm looking for the second best option.
nilgoyette: > If I could, I would deprecate and remove into_shape (because it has the "wrong" ordering defaults.). Then add it back with the right defaults.

I hesitate to give feedback on subjects that I don't feel confident in, but in this particular case... IMO, you should do exactly what you wrote
- having a "sleeping footgun" is **much** worse than deprecating a method.
- you're not at v1 so a breaking change is not unexpected for the users
- "now" is the best time to do something that could/should have been done ealier :)
bluss: For me, into_shape is a very commonly used method so it feels like it would break every program out there. Hence I'm looking for a smoother transition than this.

Even contemplating doing something like 

- `into_shape()`  *deprecated*
- `into_shape_with_order()` *new*

And after the deprecation period, `into_shape_with_order` is renamed to `into_shape`. Maybe the same dance for `reshape`.
bluss: @adamreichold if you have time, would be cool if you had a look. I think it's ready to go
adamreichold: I plan to but I am not sure when this weekend I will be able to look into it. Are you on a schedule here or would merging it the beginning of next still be fine?
bluss: @adamreichold no stress. It's not on any schedule. I've been away for months and so on, would be weird and rude if I asked that anything would suddenly move at a faster pace(!) so I'm not going to do that :slightly_smiling_face:  As one of the main maintainers I will continue to sometimes just decide to merge some changes on my own, which is a way I want all the maintainers to work, merge if they think it doesn't require more feedback.

Patch:
diff --git a/README-quick-start.md b/README-quick-start.md
index 81129965..ad13acc7 100644
--- a/README-quick-start.md
+++ b/README-quick-start.md
@@ -169,7 +169,7 @@ fn main() {
     println!("a shape {:?}", &a.shape());
     println!("b shape {:?}", &b.shape());
     
-    let b = b.into_shape((4,1)).unwrap(); // reshape b to shape [4, 1]
+    let b = b.into_shape_with_order((4,1)).unwrap(); // reshape b to shape [4, 1]
     println!("b shape after reshape {:?}", &b.shape());
     
     println!("{}", a.dot(&b));            // [1, 4] x [4, 1] -> [1, 1] 
@@ -295,7 +295,7 @@ row: [[100, 101, 102],
 ## Shape Manipulation
 
 ### Changing the shape of an array
-The shape of an array can be changed with `into_shape` method.
+The shape of an array can be changed with the `into_shape_with_order` or `to_shape` method.
 
 ````rust
 use ndarray::prelude::*;
@@ -319,7 +319,7 @@ fn main() {
     let b = Array::from_iter(a.iter());
     println!("b = \n{:?}\n", b);
     
-    let c = b.into_shape([6, 2]).unwrap(); // consume b and generate c with new shape
+    let c = b.into_shape_with_order([6, 2]).unwrap(); // consume b and generate c with new shape
     println!("c = \n{:?}", c);
 }
 ````
@@ -459,7 +459,7 @@ use ndarray::{Array, Axis};
 
 fn main() {
 
-    let mut a = Array::range(0., 12., 1.).into_shape([3 ,4]).unwrap();
+    let mut a = Array::range(0., 12., 1.).into_shape_with_order([3 ,4]).unwrap();
     println!("a = \n{}\n", a);
     
     {
@@ -519,7 +519,7 @@ use ndarray::Array;
 
 fn main() {
 
-    let mut a = Array::range(0., 4., 1.).into_shape([2 ,2]).unwrap();
+    let mut a = Array::range(0., 4., 1.).into_shape_with_order([2 ,2]).unwrap();
     let b = a.clone();
     
     println!("a = \n{}\n", a);
diff --git a/benches/bench1.rs b/benches/bench1.rs
index c7f18e3c..6b686419 100644
--- a/benches/bench1.rs
+++ b/benches/bench1.rs
@@ -915,7 +915,7 @@ const MEAN_SUM_N: usize = 127;
 fn range_mat(m: Ix, n: Ix) -> Array2<f32> {
     assert!(m * n != 0);
     Array::linspace(0., (m * n - 1) as f32, m * n)
-        .into_shape((m, n))
+        .into_shape_with_order((m, n))
         .unwrap()
 }
 
diff --git a/benches/construct.rs b/benches/construct.rs
index 3d77a89e..c3603ce7 100644
--- a/benches/construct.rs
+++ b/benches/construct.rs
@@ -22,13 +22,13 @@ fn zeros_f64(bench: &mut Bencher) {
 
 #[bench]
 fn map_regular(bench: &mut test::Bencher) {
-    let a = Array::linspace(0., 127., 128).into_shape((8, 16)).unwrap();
+    let a = Array::linspace(0., 127., 128).into_shape_with_order((8, 16)).unwrap();
     bench.iter(|| a.map(|&x| 2. * x));
 }
 
 #[bench]
 fn map_stride(bench: &mut test::Bencher) {
-    let a = Array::linspace(0., 127., 256).into_shape((8, 32)).unwrap();
+    let a = Array::linspace(0., 127., 256).into_shape_with_order((8, 32)).unwrap();
     let av = a.slice(s![.., ..;2]);
     bench.iter(|| av.map(|&x| 2. * x));
 }
diff --git a/benches/higher-order.rs b/benches/higher-order.rs
index 6bbd5717..f593cd02 100644
--- a/benches/higher-order.rs
+++ b/benches/higher-order.rs
@@ -17,7 +17,7 @@ const Y: usize = 16;
 
 #[bench]
 fn map_regular(bench: &mut Bencher) {
-    let a = Array::linspace(0., 127., N).into_shape((X, Y)).unwrap();
+    let a = Array::linspace(0., 127., N).into_shape_with_order((X, Y)).unwrap();
     bench.iter(|| a.map(|&x| 2. * x));
 }
 
@@ -28,7 +28,7 @@ pub fn double_array(mut a: ArrayViewMut2<'_, f64>) {
 #[bench]
 fn map_stride_double_f64(bench: &mut Bencher) {
     let mut a = Array::linspace(0., 127., N * 2)
-        .into_shape([X, Y * 2])
+        .into_shape_with_order([X, Y * 2])
         .unwrap();
     let mut av = a.slice_mut(s![.., ..;2]);
     bench.iter(|| {
@@ -39,7 +39,7 @@ fn map_stride_double_f64(bench: &mut Bencher) {
 #[bench]
 fn map_stride_f64(bench: &mut Bencher) {
     let a = Array::linspace(0., 127., N * 2)
-        .into_shape([X, Y * 2])
+        .into_shape_with_order([X, Y * 2])
         .unwrap();
     let av = a.slice(s![.., ..;2]);
     bench.iter(|| av.map(|&x| 2. * x));
@@ -48,7 +48,7 @@ fn map_stride_f64(bench: &mut Bencher) {
 #[bench]
 fn map_stride_u32(bench: &mut Bencher) {
     let a = Array::linspace(0., 127., N * 2)
-        .into_shape([X, Y * 2])
+        .into_shape_with_order([X, Y * 2])
         .unwrap();
     let b = a.mapv(|x| x as u32);
     let av = b.slice(s![.., ..;2]);
@@ -58,7 +58,7 @@ fn map_stride_u32(bench: &mut Bencher) {
 #[bench]
 fn fold_axis(bench: &mut Bencher) {
     let a = Array::linspace(0., 127., N * 2)
-        .into_shape([X, Y * 2])
+        .into_shape_with_order([X, Y * 2])
         .unwrap();
     bench.iter(|| a.fold_axis(Axis(0), 0., |&acc, &elt| acc + elt));
 }
@@ -69,7 +69,7 @@ const MASZ: usize = MA * MA;
 #[bench]
 fn map_axis_0(bench: &mut Bencher) {
     let a = Array::from_iter(0..MASZ as i32)
-        .into_shape([MA, MA])
+        .into_shape_with_order([MA, MA])
         .unwrap();
     bench.iter(|| a.map_axis(Axis(0), black_box));
 }
@@ -77,7 +77,7 @@ fn map_axis_0(bench: &mut Bencher) {
 #[bench]
 fn map_axis_1(bench: &mut Bencher) {
     let a = Array::from_iter(0..MASZ as i32)
-        .into_shape([MA, MA])
+        .into_shape_with_order([MA, MA])
         .unwrap();
     bench.iter(|| a.map_axis(Axis(1), black_box));
 }
diff --git a/benches/iter.rs b/benches/iter.rs
index d8c716dc..22c8b8d1 100644
--- a/benches/iter.rs
+++ b/benches/iter.rs
@@ -46,21 +46,21 @@ fn iter_sum_2d_transpose(bench: &mut Bencher) {
 
 #[bench]
 fn iter_filter_sum_2d_u32(bench: &mut Bencher) {
-    let a = Array::linspace(0., 1., 256).into_shape((16, 16)).unwrap();
+    let a = Array::linspace(0., 1., 256).into_shape_with_order((16, 16)).unwrap();
     let b = a.mapv(|x| (x * 100.) as u32);
     bench.iter(|| b.iter().filter(|&&x| x < 75).sum::<u32>());
 }
 
 #[bench]
 fn iter_filter_sum_2d_f32(bench: &mut Bencher) {
-    let a = Array::linspace(0., 1., 256).into_shape((16, 16)).unwrap();
+    let a = Array::linspace(0., 1., 256).into_shape_with_order((16, 16)).unwrap();
     let b = a * 100.;
     bench.iter(|| b.iter().filter(|&&x| x < 75.).sum::<f32>());
 }
 
 #[bench]
 fn iter_filter_sum_2d_stride_u32(bench: &mut Bencher) {
-    let a = Array::linspace(0., 1., 256).into_shape((16, 16)).unwrap();
+    let a = Array::linspace(0., 1., 256).into_shape_with_order((16, 16)).unwrap();
     let b = a.mapv(|x| (x * 100.) as u32);
     let b = b.slice(s![.., ..;2]);
     bench.iter(|| b.iter().filter(|&&x| x < 75).sum::<u32>());
@@ -68,7 +68,7 @@ fn iter_filter_sum_2d_stride_u32(bench: &mut Bencher) {
 
 #[bench]
 fn iter_filter_sum_2d_stride_f32(bench: &mut Bencher) {
-    let a = Array::linspace(0., 1., 256).into_shape((16, 16)).unwrap();
+    let a = Array::linspace(0., 1., 256).into_shape_with_order((16, 16)).unwrap();
     let b = a * 100.;
     let b = b.slice(s![.., ..;2]);
     bench.iter(|| b.iter().filter(|&&x| x < 75.).sum::<f32>());
@@ -321,7 +321,7 @@ fn indexed_iter_3d_dyn(bench: &mut Bencher) {
     for ((i, j, k), elt) in a.indexed_iter_mut() {
         *elt = (i + 100 * j + 10000 * k) as _;
     }
-    let a = a.into_shape(&[ISZ; 3][..]).unwrap();
+    let a = a.into_shape_with_order(&[ISZ; 3][..]).unwrap();
 
     bench.iter(|| {
         for (i, &_elt) in a.indexed_iter() {
diff --git a/benches/numeric.rs b/benches/numeric.rs
index 4c579eb7..d9b9187f 100644
--- a/benches/numeric.rs
+++ b/benches/numeric.rs
@@ -12,7 +12,7 @@ const Y: usize = 16;
 #[bench]
 fn clip(bench: &mut Bencher) {
     let mut a = Array::linspace(0., 127., N * 2)
-        .into_shape([X, Y * 2])
+        .into_shape_with_order([X, Y * 2])
         .unwrap();
     let min = 2.;
     let max = 5.;
diff --git a/examples/axis_ops.rs b/examples/axis_ops.rs
index 0b2c3dec..e84d112c 100644
--- a/examples/axis_ops.rs
+++ b/examples/axis_ops.rs
@@ -74,7 +74,7 @@ fn main() {
     }
     regularize(&mut b).unwrap();
 
-    let mut b = b.into_shape(a.len()).unwrap();
+    let mut b = b.into_shape_with_order(a.len()).unwrap();
     regularize(&mut b).unwrap();
 
     b.invert_axis(Axis(0));
diff --git a/examples/life.rs b/examples/life.rs
index 48f1d609..e0675ae1 100644
--- a/examples/life.rs
+++ b/examples/life.rs
@@ -22,7 +22,7 @@ fn parse(x: &[u8]) -> Board {
         _ => None,
     }));
 
-    let a = a.into_shape((N, N)).unwrap();
+    let a = a.into_shape_with_order((N, N)).unwrap();
     map.slice_mut(s![1..-1, 1..-1]).assign(&a);
     map
 }
diff --git a/examples/sort-axis.rs b/examples/sort-axis.rs
index ee5ff346..2ff6ceb3 100644
--- a/examples/sort-axis.rs
+++ b/examples/sort-axis.rs
@@ -166,7 +166,7 @@ where
 
 #[cfg(feature = "std")]
 fn main() {
-    let a = Array::linspace(0., 63., 64).into_shape((8, 8)).unwrap();
+    let a = Array::linspace(0., 63., 64).into_shape_with_order((8, 8)).unwrap();
     let strings = a.map(|x| x.to_string());
 
     let perm = a.sort_axis_by(Axis(1), |i, j| a[[i, 0]] > a[[j, 0]]);
diff --git a/src/free_functions.rs b/src/free_functions.rs
index e9c3abff..6deaafcb 100644
--- a/src/free_functions.rs
+++ b/src/free_functions.rs
@@ -77,7 +77,7 @@ pub fn aview0<A>(x: &A) -> ArrayView0<'_, A> {
 /// let data = [1.0; 1024];
 ///
 /// // Create a 2D array view from borrowed data
-/// let a2d = aview1(&data).into_shape((32, 32)).unwrap();
+/// let a2d = aview1(&data).into_shape_with_order((32, 32)).unwrap();
 ///
 /// assert_eq!(a2d.sum(), 1024.0);
 /// ```
@@ -100,7 +100,7 @@ pub fn aview2<A, const N: usize>(xs: &[[A; N]]) -> ArrayView2<'_, A> {
 /// // Create an array view over some data, then slice it and modify it.
 /// let mut data = [0; 1024];
 /// {
-///     let mut a = aview_mut1(&mut data).into_shape((32, 32)).unwrap();
+///     let mut a = aview_mut1(&mut data).into_shape_with_order((32, 32)).unwrap();
 ///     a.slice_mut(s![.., ..;3]).fill(5);
 /// }
 /// assert_eq!(&data[..10], [5, 0, 0, 5, 0, 0, 5, 0, 0, 5]);
diff --git a/src/impl_constructors.rs b/src/impl_constructors.rs
index 2779e27d..94ddebcd 100644
--- a/src/impl_constructors.rs
+++ b/src/impl_constructors.rs
@@ -329,7 +329,7 @@ where
         A: Clone,
         Sh: ShapeBuilder<Dim = D>,
     {
-        let shape = shape.into_shape();
+        let shape = shape.into_shape_with_order();
         let size = size_of_shape_checked_unwrap!(&shape.dim);
         let v = vec![elem; size];
         unsafe { Self::from_shape_vec_unchecked(shape, v) }
@@ -383,7 +383,7 @@ where
         Sh: ShapeBuilder<Dim = D>,
         F: FnMut() -> A,
     {
-        let shape = shape.into_shape();
+        let shape = shape.into_shape_with_order();
         let len = size_of_shape_checked_unwrap!(&shape.dim);
         let v = to_vec_mapped(0..len, move |_| f());
         unsafe { Self::from_shape_vec_unchecked(shape, v) }
@@ -414,7 +414,7 @@ where
         Sh: ShapeBuilder<Dim = D>,
         F: FnMut(D::Pattern) -> A,
     {
-        let shape = shape.into_shape();
+        let shape = shape.into_shape_with_order();
         let _ = size_of_shape_checked_unwrap!(&shape.dim);
         if shape.is_c() {
             let v = to_vec_mapped(indices(shape.dim.clone()).into_iter(), f);
@@ -591,7 +591,7 @@ where
         Sh: ShapeBuilder<Dim = D>,
     {
         unsafe {
-            let shape = shape.into_shape();
+            let shape = shape.into_shape_with_order();
             let size = size_of_shape_checked_unwrap!(&shape.dim);
             let mut v = Vec::with_capacity(size);
             v.set_len(size);
@@ -664,7 +664,7 @@ where
         A: Copy,
         Sh: ShapeBuilder<Dim = D>,
     {
-        let shape = shape.into_shape();
+        let shape = shape.into_shape_with_order();
         let size = size_of_shape_checked_unwrap!(&shape.dim);
         let mut v = Vec::with_capacity(size);
         v.set_len(size);
@@ -687,7 +687,7 @@ where
         Sh: ShapeBuilder<Dim = D>,
     {
         unsafe {
-            let shape = shape.into_shape();
+            let shape = shape.into_shape_with_order();
             let size = size_of_shape_checked_unwrap!(&shape.dim);
             let mut v = Vec::with_capacity(size);
             v.set_len(size);
diff --git a/src/impl_methods.rs b/src/impl_methods.rs
index 9186cd76..caeed225 100644
--- a/src/impl_methods.rs
+++ b/src/impl_methods.rs
@@ -1323,7 +1323,7 @@ where
     /// use ndarray::Array;
     /// use ndarray::{arr3, Axis};
     ///
-    /// let a = Array::from_iter(0..28).into_shape((2, 7, 2)).unwrap();
+    /// let a = Array::from_iter(0..28).into_shape_with_order((2, 7, 2)).unwrap();
     /// let mut iter = a.axis_chunks_iter(Axis(1), 2);
     ///
     /// // first iteration yields a 2 × 2 × 2 view
@@ -1815,9 +1815,20 @@ where
     /// number of rows and columns (or more axes if applicable), it is important to pick an index
     /// ordering, and that's the reason for the function parameter for `order`.
     ///
+    /// The `new_shape` parameter should be a dimension and an optional order like these examples:
+    ///
+    /// ```text
+    /// (3, 4)                          // Shape 3 x 4 with default order (RowMajor)
+    /// ((3, 4), Order::RowMajor))      // use specific order
+    /// ((3, 4), Order::ColumnMajor))   // use specific order
+    /// ((3, 4), Order::C))             // use shorthand for order - shorthands C and F
+    /// ```
+    ///
     /// **Errors** if the new shape doesn't have the same number of elements as the array's current
     /// shape.
     ///
+    /// # Example
+    ///
     /// ```
     /// use ndarray::array;
     /// use ndarray::Order;
@@ -1885,10 +1896,95 @@ where
         }
     }
 
+    /// Transform the array into `shape`; any shape with the same number of
+    /// elements is accepted, but the source array must be contiguous.
+    ///
+    /// If an index ordering is not specified, the default is `RowMajor`.
+    /// The operation will only succeed if the array's memory layout is compatible with
+    /// the index ordering, so that the array elements can be rearranged in place.
+    ///
+    /// If required use `.to_shape()` or `.into_shape_clone` instead for more flexible reshaping of
+    /// arrays, which allows copying elements if required.
+    ///
+    /// **Errors** if the shapes don't have the same number of elements.<br>
+    /// **Errors** if order RowMajor is given but input is not c-contiguous.
+    /// **Errors** if order ColumnMajor is given but input is not f-contiguous.
+    ///
+    /// If shape is not given: use memory layout of incoming array. Row major arrays are
+    /// reshaped using row major index ordering, column major arrays with column major index
+    /// ordering.
+    ///
+    /// The `new_shape` parameter should be a dimension and an optional order like these examples:
+    ///
+    /// ```text
+    /// (3, 4)                          // Shape 3 x 4 with default order (RowMajor)
+    /// ((3, 4), Order::RowMajor))      // use specific order
+    /// ((3, 4), Order::ColumnMajor))   // use specific order
+    /// ((3, 4), Order::C))             // use shorthand for order - shorthands C and F
+    /// ```
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use ndarray::{aview1, aview2};
+    /// use ndarray::Order;
+    ///
+    /// assert!(
+    ///     aview1(&[1., 2., 3., 4.]).into_shape_with_order((2, 2)).unwrap()
+    ///     == aview2(&[[1., 2.],
+    ///                 [3., 4.]])
+    /// );
+    ///
+    /// assert!(
+    ///     aview1(&[1., 2., 3., 4.]).into_shape_with_order(((2, 2), Order::ColumnMajor)).unwrap()
+    ///     == aview2(&[[1., 3.],
+    ///                 [2., 4.]])
+    /// );
+    /// ```
+    pub fn into_shape_with_order<E>(self, shape: E) -> Result<ArrayBase<S, E::Dim>, ShapeError>
+    where
+        E: ShapeArg,
+    {
+        let (shape, order) = shape.into_shape_and_order();
+        self.into_shape_with_order_impl(shape, order.unwrap_or(Order::RowMajor))
+    }
+
+    fn into_shape_with_order_impl<E>(self, shape: E, order: Order)
+        -> Result<ArrayBase<S, E>, ShapeError>
+    where
+        E: Dimension,
+    {
+        let shape = shape.into_dimension();
+        if size_of_shape_checked(&shape) != Ok(self.dim.size()) {
+            return Err(error::incompatible_shapes(&self.dim, &shape));
+        }
+
+        // Check if contiguous, then we can change shape
+        unsafe {
+            // safe because arrays are contiguous and len is unchanged
+            match order {
+                Order::RowMajor if self.is_standard_layout() => {
+                    Ok(self.with_strides_dim(shape.default_strides(), shape))
+                }
+                Order::ColumnMajor if self.raw_view().reversed_axes().is_standard_layout() => {
+                    Ok(self.with_strides_dim(shape.fortran_strides(), shape))
+                }
+                _otherwise => Err(error::from_kind(error::ErrorKind::IncompatibleLayout))
+            }
+        }
+    }
+
     /// Transform the array into `shape`; any shape with the same number of
     /// elements is accepted, but the source array or view must be in standard
     /// or column-major (Fortran) layout.
     ///
+    /// **Note** that `.into_shape()` "moves" elements differently depending on if the input array
+    /// is C-contig or F-contig, it follows the index order that corresponds to the memory order.
+    /// Prefer to use `.to_shape()` or `.into_shape_with_order()`.
+    ///
+    /// Because of this, the method **is deprecated**. That reshapes depend on memory order is not
+    /// intuitive.
+    ///
     /// **Errors** if the shapes don't have the same number of elements.<br>
     /// **Errors** if the input array is not c- or f-contiguous.
     ///
@@ -1901,6 +1997,7 @@ where
     ///                 [3., 4.]])
     /// );
     /// ```
+    #[deprecated = "Use `.into_shape_with_order()` or `.to_shape()`"]
     pub fn into_shape<E>(self, shape: E) -> Result<ArrayBase<S, E::Dim>, ShapeError>
     where
         E: IntoDimension,
@@ -1922,7 +2019,75 @@ where
         }
     }
 
-    /// *Note: Reshape is for `ArcArray` only. Use `.into_shape()` for
+    /// Transform the array into `shape`; any shape with the same number of
+    /// elements is accepted. Array elements are reordered in place if
+    /// possible, otherwise they are copied to create a new array.
+    ///
+    /// If an index ordering is not specified, the default is `RowMajor`.
+    /// The operation will only succeed if the array's memory layout is compatible with
+    /// the index ordering, so that the array elements can be rearranged in place.
+    ///
+    /// # `.to_shape` vs `.into_shape_clone`
+    ///
+    /// - `to_shape` supports views and outputting views
+    /// - `to_shape` borrows the original array, `into_shape_clone` consumes the original
+    /// - `into_shape_clone` preserves array type (Array vs ArcArray), but does not support views.
+    ///
+    /// **Errors** if the shapes don't have the same number of elements.<br>
+    pub fn into_shape_clone<E>(self, shape: E) -> Result<ArrayBase<S, E::Dim>, ShapeError>
+    where
+        S: DataOwned,
+        A: Clone,
+        E: ShapeArg,
+    {
+        let (shape, order) = shape.into_shape_and_order();
+        let order = order.unwrap_or(Order::RowMajor);
+        self.into_shape_clone_order(shape, order)
+    }
+
+    fn into_shape_clone_order<E>(self, shape: E, order: Order)
+        -> Result<ArrayBase<S, E>, ShapeError>
+    where
+        S: DataOwned,
+        A: Clone,
+        E: Dimension,
+    {
+        let len = self.dim.size();
+        if size_of_shape_checked(&shape) != Ok(len) {
+            return Err(error::incompatible_shapes(&self.dim, &shape));
+        }
+
+        // Safe because the array and new shape is empty.
+        if len == 0 {
+            unsafe {
+                return Ok(self.with_strides_dim(shape.default_strides(), shape));
+            }
+        }
+
+        // Try to reshape the array's current data
+        match reshape_dim(&self.dim, &self.strides, &shape, order) {
+            Ok(to_strides) => unsafe {
+                return Ok(self.with_strides_dim(to_strides, shape));
+            }
+            Err(err) if err.kind() == ErrorKind::IncompatibleShape => {
+                return Err(error::incompatible_shapes(&self.dim, &shape));
+            }
+            _otherwise => { }
+        }
+
+        // otherwise, clone and allocate a new array
+        unsafe {
+            let (shape, view) = match order {
+                Order::RowMajor => (shape.set_f(false), self.view()),
+                Order::ColumnMajor => (shape.set_f(true), self.t()),
+            };
+
+            Ok(ArrayBase::from_shape_trusted_iter_unchecked(
+                        shape, view.into_iter(), A::clone))
+        }
+    }
+
+    /// *Note: Reshape is for `ArcArray` only. Use `.into_shape_with_order()` for
     /// other arrays and array views.*
     ///
     /// Transform the array into `shape`; any shape with the same number of
@@ -1933,6 +2098,9 @@ where
     ///
     /// **Panics** if shapes are incompatible.
     ///
+    /// *This method is obsolete, because it is inflexible in how logical order
+    /// of the array is handled. See [`.to_shape()`].*
+    ///
     /// ```
     /// use ndarray::{rcarr1, rcarr2};
     ///
@@ -1942,6 +2110,7 @@ where
     ///                 [3., 4.]])
     /// );
     /// ```
+    #[deprecated(note="Obsolete, use `to_shape` or `into_shape_with_order` instead.", since="0.15.2")]
     pub fn reshape<E>(&self, shape: E) -> ArrayBase<S, E::Dim>
     where
         S: DataShared + DataOwned,
diff --git a/src/impl_owned_array.rs b/src/impl_owned_array.rs
index aaa9f30b..3e900113 100644
--- a/src/impl_owned_array.rs
+++ b/src/impl_owned_array.rs
@@ -232,7 +232,7 @@ impl<A, D> Array<A, D>
     /// ```
     /// use ndarray::Array;
     ///
-    /// let a = Array::from_iter(0..100).into_shape((10, 10)).unwrap();
+    /// let a = Array::from_iter(0..100).into_shape_with_order((10, 10)).unwrap();
     /// let mut b = Array::uninit((10, 10));
     /// a.move_into_uninit(&mut b);
     /// unsafe {
@@ -448,8 +448,8 @@ impl<A, D> Array<A, D>
     ///
     /// // create an empty array and append two rows at a time
     /// let mut a = Array::zeros((0, 4));
-    /// let ones  = ArrayView::from(&[1.; 8]).into_shape((2, 4)).unwrap();
-    /// let zeros = ArrayView::from(&[0.; 8]).into_shape((2, 4)).unwrap();
+    /// let ones  = ArrayView::from(&[1.; 8]).into_shape_with_order((2, 4)).unwrap();
+    /// let zeros = ArrayView::from(&[0.; 8]).into_shape_with_order((2, 4)).unwrap();
     /// a.append(Axis(0), ones).unwrap();
     /// a.append(Axis(0), zeros).unwrap();
     /// a.append(Axis(0), ones).unwrap();
diff --git a/src/impl_views/indexing.rs b/src/impl_views/indexing.rs
index adb911a4..c30f97e0 100644
--- a/src/impl_views/indexing.rs
+++ b/src/impl_views/indexing.rs
@@ -33,7 +33,7 @@ use crate::NdIndex;
 /// let data = [0.; 256];
 /// let long_life_ref = {
 ///     // make a 16 × 16 array view
-///     let view = ArrayView::from(&data[..]).into_shape((16, 16)).unwrap();
+///     let view = ArrayView::from(&data[..]).into_shape_with_order((16, 16)).unwrap();
 ///
 ///     // index the view and with `IndexLonger`.
 ///     // Note here that we get a reference with a life that is derived from
diff --git a/src/parallel/mod.rs b/src/parallel/mod.rs
index 48e97be4..552515f1 100644
--- a/src/parallel/mod.rs
+++ b/src/parallel/mod.rs
@@ -65,7 +65,7 @@
 //! use ndarray::Axis;
 //! use ndarray::parallel::prelude::*;
 //!
-//! let a = Array::linspace(0., 63., 64).into_shape((4, 16)).unwrap();
+//! let a = Array::linspace(0., 63., 64).into_shape_with_order((4, 16)).unwrap();
 //! let mut sums = Vec::new();
 //! a.axis_iter(Axis(0))
 //!  .into_par_iter()
@@ -84,7 +84,7 @@
 //! use ndarray::Axis;
 //! use ndarray::parallel::prelude::*;
 //!
-//! let a = Array::linspace(0., 63., 64).into_shape((4, 16)).unwrap();
+//! let a = Array::linspace(0., 63., 64).into_shape_with_order((4, 16)).unwrap();
 //! let mut shapes = Vec::new();
 //! a.axis_chunks_iter(Axis(0), 3)
 //!  .into_par_iter()
diff --git a/src/shape_builder.rs b/src/shape_builder.rs
index 47037407..877102b5 100644
--- a/src/shape_builder.rs
+++ b/src/shape_builder.rs
@@ -90,7 +90,7 @@ pub trait ShapeBuilder {
     type Dim: Dimension;
     type Strides;
 
-    fn into_shape(self) -> Shape<Self::Dim>;
+    fn into_shape_with_order(self) -> Shape<Self::Dim>;
     fn f(self) -> Shape<Self::Dim>;
     fn set_f(self, is_f: bool) -> Shape<Self::Dim>;
     fn strides(self, strides: Self::Strides) -> StrideShape<Self::Dim>;
@@ -102,7 +102,7 @@ where
 {
     /// Create a `Shape` from `dimension`, using the default memory layout.
     fn from(dimension: D) -> Shape<D> {
-        dimension.into_shape()
+        dimension.into_shape_with_order()
     }
 }
 
@@ -112,7 +112,7 @@ where
     T: ShapeBuilder<Dim = D>,
 {
     fn from(value: T) -> Self {
-        let shape = value.into_shape();
+        let shape = value.into_shape_with_order();
         let st = if shape.is_c() { Strides::C } else { Strides::F };
         StrideShape {
             strides: st,
@@ -127,7 +127,7 @@ where
 {
     type Dim = T::Dim;
     type Strides = T;
-    fn into_shape(self) -> Shape<Self::Dim> {
+    fn into_shape_with_order(self) -> Shape<Self::Dim> {
         Shape {
             dim: self.into_dimension(),
             strides: Strides::C,
@@ -137,10 +137,10 @@ where
         self.set_f(true)
     }
     fn set_f(self, is_f: bool) -> Shape<Self::Dim> {
-        self.into_shape().set_f(is_f)
+        self.into_shape_with_order().set_f(is_f)
     }
     fn strides(self, st: T) -> StrideShape<Self::Dim> {
-        self.into_shape().strides(st.into_dimension())
+        self.into_shape_with_order().strides(st.into_dimension())
     }
 }
 
@@ -151,7 +151,7 @@ where
     type Dim = D;
     type Strides = D;
 
-    fn into_shape(self) -> Shape<D> {
+    fn into_shape_with_order(self) -> Shape<D> {
         self
     }
 


Test patch:
diff --git a/tests/append.rs b/tests/append.rs
index dcebcf50..cbb10d85 100644
--- a/tests/append.rs
+++ b/tests/append.rs
@@ -282,8 +282,8 @@ fn append_array_3d() {
 fn test_append_2d() {
     // create an empty array and append
     let mut a = Array::zeros((0, 4));
-    let ones = ArrayView::from(&[1.; 12]).into_shape((3, 4)).unwrap();
-    let zeros = ArrayView::from(&[0.; 8]).into_shape((2, 4)).unwrap();
+    let ones = ArrayView::from(&[1.; 12]).into_shape_with_order((3, 4)).unwrap();
+    let zeros = ArrayView::from(&[0.; 8]).into_shape_with_order((2, 4)).unwrap();
     a.append(Axis(0), ones).unwrap();
     a.append(Axis(0), zeros).unwrap();
     a.append(Axis(0), ones).unwrap();
@@ -314,16 +314,16 @@ fn test_append_2d() {
 fn test_append_middle_axis() {
     // ensure we can append to Axis(1) by letting it become outermost
     let mut a = Array::<i32, _>::zeros((3, 0, 2));
-    a.append(Axis(1), Array::from_iter(0..12).into_shape((3, 2, 2)).unwrap().view()).unwrap();
+    a.append(Axis(1), Array::from_iter(0..12).into_shape_with_order((3, 2, 2)).unwrap().view()).unwrap();
     println!("{:?}", a);
-    a.append(Axis(1), Array::from_iter(12..24).into_shape((3, 2, 2)).unwrap().view()).unwrap();
+    a.append(Axis(1), Array::from_iter(12..24).into_shape_with_order((3, 2, 2)).unwrap().view()).unwrap();
     println!("{:?}", a);
 
     // ensure we can append to Axis(1) by letting it become outermost
     let mut a = Array::<i32, _>::zeros((3, 1, 2));
-    a.append(Axis(1), Array::from_iter(0..12).into_shape((3, 2, 2)).unwrap().view()).unwrap();
+    a.append(Axis(1), Array::from_iter(0..12).into_shape_with_order((3, 2, 2)).unwrap().view()).unwrap();
     println!("{:?}", a);
-    a.append(Axis(1), Array::from_iter(12..24).into_shape((3, 2, 2)).unwrap().view()).unwrap();
+    a.append(Axis(1), Array::from_iter(12..24).into_shape_with_order((3, 2, 2)).unwrap().view()).unwrap();
     println!("{:?}", a);
 }
 
@@ -339,8 +339,8 @@ fn test_append_zero_size() {
 
     {
         let mut a = Array::<i32, _>::zeros((0, 0));
-        a.append(Axis(1), ArrayView::from(&[]).into_shape((0, 1)).unwrap()).unwrap();
-        a.append(Axis(1), ArrayView::from(&[]).into_shape((0, 1)).unwrap()).unwrap();
+        a.append(Axis(1), ArrayView::from(&[]).into_shape_with_order((0, 1)).unwrap()).unwrap();
+        a.append(Axis(1), ArrayView::from(&[]).into_shape_with_order((0, 1)).unwrap()).unwrap();
         assert_eq!(a.len(), 0);
         assert_eq!(a.shape(), &[0, 2]);
     }
diff --git a/tests/array-construct.rs b/tests/array-construct.rs
index 420a9d92..a3949fca 100644
--- a/tests/array-construct.rs
+++ b/tests/array-construct.rs
@@ -60,7 +60,7 @@ fn test_uninit() {
         assert_eq!(a.dim(), (3, 4));
         assert_eq!(a.strides(), &[1, 3]);
         let b = Array::<f32, _>::linspace(0., 25., a.len())
-            .into_shape(a.dim())
+            .into_shape_with_order(a.dim())
             .unwrap();
         a.assign(&b);
         assert_eq!(&a, &b);
@@ -214,7 +214,7 @@ fn deny_wraparound_zeros() {
 fn deny_wraparound_reshape() {
     //2^64 + 5 = 18446744073709551621 = 3×7×29×36760123×823996703  (5 distinct prime factors)
     let five = Array::<f32, _>::zeros(5);
-    let _five_large = five.into_shape((3, 7, 29, 36760123, 823996703)).unwrap();
+    let _five_large = five.into_shape_with_order((3, 7, 29, 36760123, 823996703)).unwrap();
 }
 
 #[should_panic]
diff --git a/tests/array.rs b/tests/array.rs
index d770d782..56128486 100644
--- a/tests/array.rs
+++ b/tests/array.rs
@@ -74,7 +74,7 @@ fn arrayviewmut_shrink_lifetime<'a, 'b: 'a>(
 fn test_mat_mul() {
     // smoke test, a big matrix multiplication of uneven size
     let (n, m) = (45, 33);
-    let a = ArcArray::linspace(0., ((n * m) - 1) as f32, n as usize * m as usize).reshape((n, m));
+    let a = ArcArray::linspace(0., ((n * m) - 1) as f32, n as usize * m as usize).into_shape_with_order((n, m)).unwrap();
     let b = ArcArray::eye(m);
     assert_eq!(a.dot(&b), a);
     let c = ArcArray::eye(n);
@@ -149,7 +149,7 @@ fn test_slice_with_many_dim() {
         [A[&[0, 0, 0, 0, 0, 1, 0][..]], A[&[0, 0, 2, 0, 0, 1, 0][..]]],
         [A[&[1, 0, 0, 0, 0, 1, 0][..]], A[&[1, 0, 2, 0, 0, 1, 0][..]]]
     ]
-    .into_shape(new_shape)
+    .into_shape_with_order(new_shape)
     .unwrap();
     assert_eq!(vi, correct);
 
@@ -404,7 +404,7 @@ fn test_multislice() {
         };
     }
 
-    let mut arr = Array1::from_iter(0..48).into_shape((8, 6)).unwrap();
+    let mut arr = Array1::from_iter(0..48).into_shape_with_order((8, 6)).unwrap();
 
     assert_eq!(
         (arr.clone().view_mut(),),
@@ -518,9 +518,9 @@ fn test_index() {
 fn test_index_arrays() {
     let a = Array1::from_iter(0..12);
     assert_eq!(a[1], a[[1]]);
-    let v = a.view().into_shape((3, 4)).unwrap();
+    let v = a.view().into_shape_with_order((3, 4)).unwrap();
     assert_eq!(a[1], v[[0, 1]]);
-    let w = v.into_shape((2, 2, 3)).unwrap();
+    let w = v.into_shape_with_order((2, 2, 3)).unwrap();
     assert_eq!(a[1], w[[0, 0, 1]]);
 }
 
@@ -542,7 +542,7 @@ fn test_add() {
 
 #[test]
 fn test_multidim() {
-    let mut mat = ArcArray::zeros(2 * 3 * 4 * 5 * 6).reshape((2, 3, 4, 5, 6));
+    let mut mat = ArcArray::zeros(2 * 3 * 4 * 5 * 6).into_shape_with_order((2, 3, 4, 5, 6)).unwrap();
     mat[(0, 0, 0, 0, 0)] = 22u8;
     {
         for (i, elt) in mat.iter_mut().enumerate() {
@@ -604,7 +604,7 @@ fn test_cow() {
     assert_eq!(n[[0, 0]], 1);
     assert_eq!(n[[0, 1]], 0);
     assert_eq!(n.get((0, 1)), Some(&0));
-    let mut rev = mat.reshape(4);
+    let mut rev = mat.into_shape_with_order(4).unwrap();
     rev.slice_collapse(s![..;-1]);
     assert_eq!(rev[0], 4);
     assert_eq!(rev[1], 3);
@@ -643,7 +643,7 @@ fn test_cow_shrink() {
     assert_eq!(n[[0, 1]], 0);
     assert_eq!(n.get((0, 1)), Some(&0));
     // small has non-C strides this way
-    let mut small = mat.reshape(6);
+    let mut small = mat.into_shape_with_order(6).unwrap();
     small.slice_collapse(s![4..;-1]);
     assert_eq!(small[0], 6);
     assert_eq!(small[1], 5);
@@ -660,14 +660,14 @@ fn test_cow_shrink() {
 #[test]
 #[cfg(feature = "std")]
 fn test_sub() {
-    let mat = ArcArray::linspace(0., 15., 16).reshape((2, 4, 2));
+    let mat = ArcArray::linspace(0., 15., 16).into_shape_with_order((2, 4, 2)).unwrap();
     let s1 = mat.index_axis(Axis(0), 0);
     let s2 = mat.index_axis(Axis(0), 1);
     assert_eq!(s1.shape(), &[4, 2]);
     assert_eq!(s2.shape(), &[4, 2]);
-    let n = ArcArray::linspace(8., 15., 8).reshape((4, 2));
+    let n = ArcArray::linspace(8., 15., 8).into_shape_with_order((4, 2)).unwrap();
     assert_eq!(n, s2);
-    let m = ArcArray::from(vec![2., 3., 10., 11.]).reshape((2, 2));
+    let m = ArcArray::from(vec![2., 3., 10., 11.]).into_shape_with_order((2, 2)).unwrap();
     assert_eq!(m, mat.index_axis(Axis(1), 1));
 }
 
@@ -675,7 +675,7 @@ fn test_sub() {
 #[test]
 #[cfg(feature = "std")]
 fn test_sub_oob_1() {
-    let mat = ArcArray::linspace(0., 15., 16).reshape((2, 4, 2));
+    let mat = ArcArray::linspace(0., 15., 16).into_shape_with_order((2, 4, 2)).unwrap();
     mat.index_axis(Axis(0), 2);
 }
 
@@ -855,7 +855,7 @@ fn permuted_axes() {
     let permuted = a.view().permuted_axes([0]);
     assert_eq!(a, permuted);
 
-    let a = Array::from_iter(0..24).into_shape((2, 3, 4)).unwrap();
+    let a = Array::from_iter(0..24).into_shape_with_order((2, 3, 4)).unwrap();
     let permuted = a.view().permuted_axes([2, 1, 0]);
     for ((i0, i1, i2), elem) in a.indexed_iter() {
         assert_eq!(*elem, permuted[(i2, i1, i0)]);
@@ -865,7 +865,7 @@ fn permuted_axes() {
         assert_eq!(*elem, permuted[&[i0, i2, i1][..]]);
     }
 
-    let a = Array::from_iter(0..120).into_shape((2, 3, 4, 5)).unwrap();
+    let a = Array::from_iter(0..120).into_shape_with_order((2, 3, 4, 5)).unwrap();
     let permuted = a.view().permuted_axes([1, 0, 3, 2]);
     for ((i0, i1, i2, i3), elem) in a.indexed_iter() {
         assert_eq!(*elem, permuted[(i1, i0, i3, i2)]);
@@ -879,7 +879,7 @@ fn permuted_axes() {
 #[should_panic]
 #[test]
 fn permuted_axes_repeated_axis() {
-    let a = Array::from_iter(0..24).into_shape((2, 3, 4)).unwrap();
+    let a = Array::from_iter(0..24).into_shape_with_order((2, 3, 4)).unwrap();
     a.view().permuted_axes([1, 0, 1]);
 }
 
@@ -887,7 +887,7 @@ fn permuted_axes_repeated_axis() {
 #[test]
 fn permuted_axes_missing_axis() {
     let a = Array::from_iter(0..24)
-        .into_shape((2, 3, 4))
+        .into_shape_with_order((2, 3, 4))
         .unwrap()
         .into_dyn();
     a.view().permuted_axes(&[2, 0][..]);
@@ -896,7 +896,7 @@ fn permuted_axes_missing_axis() {
 #[should_panic]
 #[test]
 fn permuted_axes_oob() {
-    let a = Array::from_iter(0..24).into_shape((2, 3, 4)).unwrap();
+    let a = Array::from_iter(0..24).into_shape_with_order((2, 3, 4)).unwrap();
     a.view().permuted_axes([1, 0, 3]);
 }
 
@@ -1055,7 +1055,7 @@ fn as_slice_memory_order_mut_contiguous_cowarray() {
 fn to_slice_memory_order() {
     for shape in vec![[2, 0, 3, 5], [2, 1, 3, 5], [2, 4, 3, 5]] {
         let data: Vec<usize> = (0..shape.iter().product()).collect();
-        let mut orig = Array1::from(data.clone()).into_shape(shape).unwrap();
+        let mut orig = Array1::from(data.clone()).into_shape_with_order(shape).unwrap();
         for perm in vec![[0, 1, 2, 3], [0, 2, 1, 3], [2, 0, 1, 3]] {
             let mut a = orig.view_mut().permuted_axes(perm);
             assert_eq!(a.as_slice_memory_order().unwrap(), &data);
@@ -1337,7 +1337,7 @@ fn from_vec_dim_stride_2d_rejects() {
 
 #[test]
 fn views() {
-    let a = ArcArray::from(vec![1, 2, 3, 4]).reshape((2, 2));
+    let a = ArcArray::from(vec![1, 2, 3, 4]).into_shape_with_order((2, 2)).unwrap();
     let b = a.view();
     assert_eq!(a, b);
     assert_eq!(a.shape(), b.shape());
@@ -1354,7 +1354,7 @@ fn views() {
 
 #[test]
 fn view_mut() {
-    let mut a = ArcArray::from(vec![1, 2, 3, 4]).reshape((2, 2));
+    let mut a = ArcArray::from(vec![1, 2, 3, 4]).into_shape_with_order((2, 2)).unwrap();
     for elt in &mut a.view_mut() {
         *elt = 0;
     }
@@ -1373,7 +1373,7 @@ fn view_mut() {
 
 #[test]
 fn slice_mut() {
-    let mut a = ArcArray::from(vec![1, 2, 3, 4]).reshape((2, 2));
+    let mut a = ArcArray::from(vec![1, 2, 3, 4]).into_shape_with_order((2, 2)).unwrap();
     for elt in a.slice_mut(s![.., ..]) {
         *elt = 0;
     }
@@ -1424,7 +1424,7 @@ fn aview() {
 fn aview_mut() {
     let mut data = [0; 16];
     {
-        let mut a = aview_mut1(&mut data).into_shape((4, 4)).unwrap();
+        let mut a = aview_mut1(&mut data).into_shape_with_order((4, 4)).unwrap();
         {
             let mut slc = a.slice_mut(s![..2, ..;2]);
             slc += 1;
@@ -1680,7 +1680,7 @@ fn arithmetic_broadcast() {
 #[test]
 fn char_array() {
     // test compilation & basics of non-numerical array
-    let cc = ArcArray::from_iter("alphabet".chars()).reshape((4, 2));
+    let cc = ArcArray::from_iter("alphabet".chars()).into_shape_with_order((4, 2)).unwrap();
     assert!(cc.index_axis(Axis(1), 0) == ArcArray::from_iter("apae".chars()));
 }
 
@@ -1740,7 +1740,7 @@ fn split_at() {
     }
     assert_eq!(a, arr2(&[[1., 5.], [8., 4.]]));
 
-    let b = ArcArray::linspace(0., 59., 60).reshape((3, 4, 5));
+    let b = ArcArray::linspace(0., 59., 60).into_shape_with_order((3, 4, 5)).unwrap();
 
     let (left, right) = b.view().split_at(Axis(2), 2);
     assert_eq!(left.shape(), [3, 4, 2]);
@@ -1906,7 +1906,7 @@ fn map_mut_with_unsharing() {
 fn test_view_from_shape() {
     let s = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
     let a = ArrayView::from_shape((2, 3, 2), &s).unwrap();
-    let mut answer = Array::from(s.to_vec()).into_shape((2, 3, 2)).unwrap();
+    let mut answer = Array::from(s.to_vec()).into_shape_with_order((2, 3, 2)).unwrap();
     assert_eq!(a, answer);
 
     // custom strides (row major)
@@ -2240,7 +2240,7 @@ fn test_array_clone_unalias() {
 
 #[test]
 fn test_array_clone_same_view() {
-    let mut a = Array::from_iter(0..9).into_shape((3, 3)).unwrap();
+    let mut a = Array::from_iter(0..9).into_shape_with_order((3, 3)).unwrap();
     a.slice_collapse(s![..;-1, ..;-1]);
     let b = a.clone();
     assert_eq!(a, b);
diff --git a/tests/azip.rs b/tests/azip.rs
index 6f0327f5..d41c019d 100644
--- a/tests/azip.rs
+++ b/tests/azip.rs
@@ -263,7 +263,7 @@ fn test_zip_dim_mismatch_1() {
 // where A is F-contiguous and B contiguous but neither F nor C contiguous.
 #[test]
 fn test_contiguous_but_not_c_or_f() {
-    let a = Array::from_iter(0..27).into_shape((3, 3, 3)).unwrap();
+    let a = Array::from_iter(0..27).into_shape_with_order((3, 3, 3)).unwrap();
 
     // both F order
     let a = a.reversed_axes();
@@ -287,7 +287,7 @@ fn test_contiguous_but_not_c_or_f() {
 
 #[test]
 fn test_clone() {
-    let a = Array::from_iter(0..27).into_shape((3, 3, 3)).unwrap();
+    let a = Array::from_iter(0..27).into_shape_with_order((3, 3, 3)).unwrap();
 
     let z = Zip::from(&a).and(a.exact_chunks((1, 1, 1)));
     let w = z.clone();
diff --git a/tests/broadcast.rs b/tests/broadcast.rs
index 5416e901..6dee901e 100644
--- a/tests/broadcast.rs
+++ b/tests/broadcast.rs
@@ -5,12 +5,12 @@ use ndarray::prelude::*;
 fn broadcast_1() {
     let a_dim = Dim([2, 4, 2, 2]);
     let b_dim = Dim([2, 1, 2, 1]);
-    let a = ArcArray::linspace(0., 1., a_dim.size()).reshape(a_dim);
-    let b = ArcArray::linspace(0., 1., b_dim.size()).reshape(b_dim);
+    let a = ArcArray::linspace(0., 1., a_dim.size()).into_shape_with_order(a_dim).unwrap();
+    let b = ArcArray::linspace(0., 1., b_dim.size()).into_shape_with_order(b_dim).unwrap();
     assert!(b.broadcast(a.dim()).is_some());
 
     let c_dim = Dim([2, 1]);
-    let c = ArcArray::linspace(0., 1., c_dim.size()).reshape(c_dim);
+    let c = ArcArray::linspace(0., 1., c_dim.size()).into_shape_with_order(c_dim).unwrap();
     assert!(c.broadcast(1).is_none());
     assert!(c.broadcast(()).is_none());
     assert!(c.broadcast((2, 1)).is_some());
@@ -31,8 +31,8 @@ fn broadcast_1() {
 fn test_add() {
     let a_dim = Dim([2, 4, 2, 2]);
     let b_dim = Dim([2, 1, 2, 1]);
-    let mut a = ArcArray::linspace(0.0, 1., a_dim.size()).reshape(a_dim);
-    let b = ArcArray::linspace(0.0, 1., b_dim.size()).reshape(b_dim);
+    let mut a = ArcArray::linspace(0.0, 1., a_dim.size()).into_shape_with_order(a_dim).unwrap();
+    let b = ArcArray::linspace(0.0, 1., b_dim.size()).into_shape_with_order(b_dim).unwrap();
     a += &b;
     let t = ArcArray::from_elem((), 1.0f32);
     a += &t;
@@ -43,7 +43,7 @@ fn test_add() {
 #[cfg(feature = "std")]
 fn test_add_incompat() {
     let a_dim = Dim([2, 4, 2, 2]);
-    let mut a = ArcArray::linspace(0.0, 1., a_dim.size()).reshape(a_dim);
+    let mut a = ArcArray::linspace(0.0, 1., a_dim.size()).into_shape_with_order(a_dim).unwrap();
     let incompat = ArcArray::from_elem(3, 1.0f32);
     a += &incompat;
 }
diff --git a/tests/dimension.rs b/tests/dimension.rs
index 939b4f0e..5dae5b5a 100644
--- a/tests/dimension.rs
+++ b/tests/dimension.rs
@@ -55,14 +55,14 @@ fn remove_axis() {
     let a = ArcArray::<f32, _>::zeros(vec![4, 5, 6]);
     let _b = a
         .index_axis_move(Axis(1), 0)
-        .reshape((4, 6))
-        .reshape(vec![2, 3, 4]);
+        .to_shape((4, 6)).unwrap()
+        .to_shape(vec![2, 3, 4]).unwrap();
 }
 
 #[test]
 #[allow(clippy::eq_op)]
 fn dyn_dimension() {
-    let a = arr2(&[[1., 2.], [3., 4.0]]).into_shape(vec![2, 2]).unwrap();
+    let a = arr2(&[[1., 2.], [3., 4.0]]).into_shape_with_order(vec![2, 2]).unwrap();
     assert_eq!(&a - &a, Array::zeros(vec![2, 2]));
     assert_eq!(a[&[0, 0][..]], 1.);
     assert_eq!(a[[0, 0]], 1.);
diff --git a/tests/format.rs b/tests/format.rs
index 422fa295..4b21fe39 100644
--- a/tests/format.rs
+++ b/tests/format.rs
@@ -6,7 +6,7 @@ fn formatting() {
     let a = rcarr1::<f32>(&[1., 2., 3., 4.]);
     assert_eq!(format!("{}", a), "[1, 2, 3, 4]");
     assert_eq!(format!("{:4}", a), "[   1,    2,    3,    4]");
-    let a = a.reshape((4, 1, 1));
+    let a = a.into_shape_clone((4, 1, 1)).unwrap();
     assert_eq!(
         format!("{}", a),
         "\
@@ -30,7 +30,7 @@ fn formatting() {
  [[   4]]]",
     );
 
-    let a = a.reshape((2, 2));
+    let a = a.into_shape_clone((2, 2)).unwrap();
     assert_eq!(
         format!("{}", a),
         "\
diff --git a/tests/indices.rs b/tests/indices.rs
index 3e2c0796..ca6ca988 100644
--- a/tests/indices.rs
+++ b/tests/indices.rs
@@ -1,15 +1,16 @@
 use ndarray::indices_of;
 use ndarray::prelude::*;
+use ndarray::Order;
 
 #[test]
 fn test_ixdyn_index_iterate() {
-    for &rev in &[false, true] {
-        let mut a = Array::zeros((2, 3, 4).set_f(rev));
+    for &order in &[Order::C, Order::F] {
+        let mut a = Array::zeros((2, 3, 4).set_f(order.is_column_major()));
         let dim = a.shape().to_vec();
         for ((i, j, k), elt) in a.indexed_iter_mut() {
             *elt = i + 10 * j + 100 * k;
         }
-        let a = a.into_shape(dim).unwrap();
+        let a = a.into_shape_with_order((dim, order)).unwrap();
         println!("{:?}", a.dim());
         let mut c = 0;
         for i in indices_of(&a) {
diff --git a/tests/iterator_chunks.rs b/tests/iterator_chunks.rs
index 67ddd1e3..bf3af2d5 100644
--- a/tests/iterator_chunks.rs
+++ b/tests/iterator_chunks.rs
@@ -13,7 +13,7 @@ use ndarray::prelude::*;
 fn chunks() {
     use ndarray::NdProducer;
     let a = <Array1<f32>>::linspace(1., 100., 10 * 10)
-        .into_shape((10, 10))
+        .into_shape_with_order((10, 10))
         .unwrap();
 
     let (m, n) = a.dim();
diff --git a/tests/iterators.rs b/tests/iterators.rs
index addd59ad..fd071603 100644
--- a/tests/iterators.rs
+++ b/tests/iterators.rs
@@ -42,7 +42,7 @@ fn double_ended() {
 #[test]
 fn iter_size_hint() {
     // Check that the size hint is correctly computed
-    let a = ArcArray::from_iter(0..24).reshape((2, 3, 4));
+    let a = ArcArray::from_iter(0..24).into_shape_with_order((2, 3, 4)).unwrap();
     let mut data = [0; 24];
     for (i, elt) in enumerate(&mut data) {
         *elt = i as i32;
@@ -64,7 +64,7 @@ fn indexed() {
     for (i, elt) in a.indexed_iter() {
         assert_eq!(i, *elt as usize);
     }
-    let a = a.reshape((2, 4, 1));
+    let a = a.into_shape_with_order((2, 4, 1)).unwrap();
     let (mut i, mut j, k) = (0, 0, 0);
     for (idx, elt) in a.indexed_iter() {
         assert_eq!(idx, (i, j, k));
@@ -96,11 +96,11 @@ fn as_slice() {
     }
 
     let a = ArcArray::linspace(0., 7., 8);
-    let a = a.reshape((2, 4, 1));
+    let a = a.into_shape_with_order((2, 4, 1)).unwrap();
 
     assert_slice_correct(&a);
 
-    let a = a.reshape((2, 4));
+    let a = a.into_shape_with_order((2, 4)).unwrap();
     assert_slice_correct(&a);
 
     assert!(a.view().index_axis(Axis(1), 0).as_slice().is_none());
@@ -123,7 +123,7 @@ fn as_slice() {
     assert!(u.as_slice().is_some());
     assert_slice_correct(&u);
 
-    let a = a.reshape((8, 1));
+    let a = a.into_shape_with_order((8, 1)).unwrap();
     assert_slice_correct(&a);
     let u = a.slice(s![..;2, ..]);
     println!(
@@ -138,7 +138,7 @@ fn as_slice() {
 #[test]
 fn inner_iter() {
     let a = ArcArray::from_iter(0..12);
-    let a = a.reshape((2, 3, 2));
+    let a = a.into_shape_with_order((2, 3, 2)).unwrap();
     // [[[0, 1],
     //   [2, 3],
     //   [4, 5]],
@@ -187,7 +187,7 @@ fn inner_iter_corner_cases() {
 #[test]
 fn inner_iter_size_hint() {
     // Check that the size hint is correctly computed
-    let a = ArcArray::from_iter(0..24).reshape((2, 3, 4));
+    let a = ArcArray::from_iter(0..24).into_shape_with_order((2, 3, 4)).unwrap();
     let mut len = 6;
     let mut it = a.rows().into_iter();
     assert_eq!(it.len(), len);
@@ -202,7 +202,7 @@ fn inner_iter_size_hint() {
 #[test]
 fn outer_iter() {
     let a = ArcArray::from_iter(0..12);
-    let a = a.reshape((2, 3, 2));
+    let a = a.into_shape_with_order((2, 3, 2)).unwrap();
     // [[[0, 1],
     //   [2, 3],
     //   [4, 5]],
@@ -261,7 +261,7 @@ fn outer_iter() {
 #[test]
 fn axis_iter() {
     let a = ArcArray::from_iter(0..12);
-    let a = a.reshape((2, 3, 2));
+    let a = a.into_shape_with_order((2, 3, 2)).unwrap();
     // [[[0, 1],
     //   [2, 3],
     //   [4, 5]],
@@ -353,7 +353,7 @@ fn outer_iter_corner_cases() {
 #[test]
 fn outer_iter_mut() {
     let a = ArcArray::from_iter(0..12);
-    let a = a.reshape((2, 3, 2));
+    let a = a.into_shape_with_order((2, 3, 2)).unwrap();
     // [[[0, 1],
     //   [2, 3],
     //   [4, 5]],
@@ -380,7 +380,7 @@ fn outer_iter_mut() {
 #[test]
 fn axis_iter_mut() {
     let a = ArcArray::from_iter(0..12);
-    let a = a.reshape((2, 3, 2));
+    let a = a.into_shape_with_order((2, 3, 2)).unwrap();
     // [[[0, 1],
     //   [2, 3],
     //   [4, 5]],
@@ -400,7 +400,7 @@ fn axis_iter_mut() {
 #[test]
 fn axis_chunks_iter() {
     let a = ArcArray::from_iter(0..24);
-    let a = a.reshape((2, 6, 2));
+    let a = a.into_shape_with_order((2, 6, 2)).unwrap();
 
     let it = a.axis_chunks_iter(Axis(1), 2);
     assert_equal(
@@ -413,7 +413,7 @@ fn axis_chunks_iter() {
     );
 
     let a = ArcArray::from_iter(0..28);
-    let a = a.reshape((2, 7, 2));
+    let a = a.into_shape_with_order((2, 7, 2)).unwrap();
 
     let it = a.axis_chunks_iter(Axis(1), 2);
     assert_equal(
@@ -535,7 +535,7 @@ fn axis_chunks_iter_corner_cases() {
     // and enable checking if no pointer offsetting is out of bounds. However
     // checking the absence of of out of bounds offsetting cannot (?) be
     // done automatically, so one has to launch this test in a debugger.
-    let a = ArcArray::<f32, _>::linspace(0., 7., 8).reshape((8, 1));
+    let a = ArcArray::<f32, _>::linspace(0., 7., 8).into_shape_with_order((8, 1)).unwrap();
     let it = a.axis_chunks_iter(Axis(0), 4);
     assert_equal(it, vec![a.slice(s![..4, ..]), a.slice(s![4.., ..])]);
     let a = a.slice(s![..;-1,..]);
@@ -564,7 +564,7 @@ fn axis_chunks_iter_corner_cases() {
 fn axis_chunks_iter_zero_stride() {
     {
         // stride 0 case
-        let b = Array::from(vec![0f32; 0]).into_shape((5, 0, 3)).unwrap();
+        let b = Array::from(vec![0f32; 0]).into_shape_with_order((5, 0, 3)).unwrap();
         let shapes: Vec<_> = b
             .axis_chunks_iter(Axis(0), 2)
             .map(|v| v.raw_dim())
@@ -574,7 +574,7 @@ fn axis_chunks_iter_zero_stride() {
 
     {
         // stride 0 case reverse
-        let b = Array::from(vec![0f32; 0]).into_shape((5, 0, 3)).unwrap();
+        let b = Array::from(vec![0f32; 0]).into_shape_with_order((5, 0, 3)).unwrap();
         let shapes: Vec<_> = b
             .axis_chunks_iter(Axis(0), 2)
             .rev()
@@ -634,7 +634,7 @@ fn axis_chunks_iter_split_at() {
 #[test]
 fn axis_chunks_iter_mut() {
     let a = ArcArray::from_iter(0..24);
-    let mut a = a.reshape((2, 6, 2));
+    let mut a = a.into_shape_with_order((2, 6, 2)).unwrap();
 
     let mut it = a.axis_chunks_iter_mut(Axis(1), 2);
     let mut col0 = it.next().unwrap();
@@ -658,7 +658,7 @@ fn axis_chunks_iter_mut_zero_axis_len() {
 #[test]
 fn outer_iter_size_hint() {
     // Check that the size hint is correctly computed
-    let a = ArcArray::from_iter(0..24).reshape((4, 3, 2));
+    let a = ArcArray::from_iter(0..24).into_shape_with_order((4, 3, 2)).unwrap();
     let mut len = 4;
     let mut it = a.outer_iter();
     assert_eq!(it.len(), len);
@@ -690,7 +690,7 @@ fn outer_iter_size_hint() {
 
 #[test]
 fn outer_iter_split_at() {
-    let a = ArcArray::from_iter(0..30).reshape((5, 3, 2));
+    let a = ArcArray::from_iter(0..30).into_shape_with_order((5, 3, 2)).unwrap();
 
     let it = a.outer_iter();
     let (mut itl, mut itr) = it.clone().split_at(2);
@@ -712,7 +712,7 @@ fn outer_iter_split_at() {
 #[test]
 #[should_panic]
 fn outer_iter_split_at_panics() {
-    let a = ArcArray::from_iter(0..30).reshape((5, 3, 2));
+    let a = ArcArray::from_iter(0..30).into_shape_with_order((5, 3, 2)).unwrap();
 
     let it = a.outer_iter();
     it.split_at(6);
@@ -720,7 +720,7 @@ fn outer_iter_split_at_panics() {
 
 #[test]
 fn outer_iter_mut_split_at() {
-    let mut a = ArcArray::from_iter(0..30).reshape((5, 3, 2));
+    let mut a = ArcArray::from_iter(0..30).into_shape_with_order((5, 3, 2)).unwrap();
 
     {
         let it = a.outer_iter_mut();
@@ -744,7 +744,7 @@ fn iterators_are_send_sync() {
     // are too.
     fn _send_sync<T: Send + Sync>(_: &T) {}
 
-    let mut a = ArcArray::from_iter(0..30).into_shape((5, 3, 2)).unwrap();
+    let mut a = ArcArray::from_iter(0..30).into_shape_with_order((5, 3, 2)).unwrap();
 
     _send_sync(&a.view());
     _send_sync(&a.view_mut());
@@ -904,11 +904,11 @@ fn test_into_iter() {
 
 #[test]
 fn test_into_iter_2d() {
-    let a = Array1::from(vec![1, 2, 3, 4]).into_shape((2, 2)).unwrap();
+    let a = Array1::from(vec![1, 2, 3, 4]).into_shape_with_order((2, 2)).unwrap();
     let v = a.into_iter().collect::<Vec<_>>();
     assert_eq!(v, [1, 2, 3, 4]);
 
-    let a = Array1::from(vec![1, 2, 3, 4]).into_shape((2, 2)).unwrap().reversed_axes();
+    let a = Array1::from(vec![1, 2, 3, 4]).into_shape_with_order((2, 2)).unwrap().reversed_axes();
     let v = a.into_iter().collect::<Vec<_>>();
     assert_eq!(v, [1, 3, 2, 4]);
 }
@@ -930,7 +930,7 @@ fn test_into_iter_sliced() {
                         let j2 = j2 as isize;
                         let mut a = Array1::from_iter(0..(m * n) as i32)
                             .mapv(|v| DropCount::new(v, &drops))
-                            .into_shape((m, n)).unwrap();
+                            .into_shape_with_order((m, n)).unwrap();
                         a.slice_collapse(s![i..i2, j..j2]);
                         if invert < a.ndim() {
                             a.invert_axis(Axis(invert));
diff --git a/tests/ixdyn.rs b/tests/ixdyn.rs
index 11af2c97..5b7ef932 100644
--- a/tests/ixdyn.rs
+++ b/tests/ixdyn.rs
@@ -10,6 +10,7 @@ use ndarray::Array;
 use ndarray::IntoDimension;
 use ndarray::ShapeBuilder;
 use ndarray::Ix3;
+use ndarray::Order;
 
 #[test]
 fn test_ixdyn() {
@@ -39,14 +40,14 @@ fn test_ixdyn_out_of_bounds() {
 
 #[test]
 fn test_ixdyn_iterate() {
-    for &rev in &[false, true] {
-        let mut a = Array::zeros((2, 3, 4).set_f(rev));
+    for &order in &[Order::C, Order::F] {
+        let mut a = Array::zeros((2, 3, 4).set_f(order.is_column_major()));
         let dim = a.shape().to_vec();
         for (i, elt) in a.iter_mut().enumerate() {
             *elt = i;
         }
         println!("{:?}", a.dim());
-        let mut a = a.into_shape(dim).unwrap();
+        let mut a = a.into_shape_with_order((dim, order)).unwrap();
         println!("{:?}", a.dim());
         let mut c = 0;
         for (i, elt) in a.iter_mut().enumerate() {
@@ -59,13 +60,13 @@ fn test_ixdyn_iterate() {
 
 #[test]
 fn test_ixdyn_index_iterate() {
-    for &rev in &[false, true] {
-        let mut a = Array::zeros((2, 3, 4).set_f(rev));
+    for &order in &[Order::C, Order::F] {
+        let mut a = Array::zeros((2, 3, 4).set_f(order.is_column_major()));
         let dim = a.shape().to_vec();
         for ((i, j, k), elt) in a.indexed_iter_mut() {
             *elt = i + 10 * j + 100 * k;
         }
-        let a = a.into_shape(dim).unwrap();
+        let a = a.into_shape_with_order((dim, order)).unwrap();
         println!("{:?}", a.dim());
         let mut c = 0;
         for (i, elt) in a.indexed_iter() {
@@ -159,8 +160,8 @@ fn test_0_add_broad() {
 fn test_into_dimension() {
     use ndarray::{Ix0, Ix1, Ix2, IxDyn};
 
-    let a = Array::linspace(0., 41., 6 * 7).into_shape((6, 7)).unwrap();
-    let a2 = a.clone().into_shape(IxDyn(&[6, 7])).unwrap();
+    let a = Array::linspace(0., 41., 6 * 7).into_shape_with_order((6, 7)).unwrap();
+    let a2 = a.clone().into_shape_with_order(IxDyn(&[6, 7])).unwrap();
     let b = a2.clone().into_dimensionality::<Ix2>().unwrap();
     assert_eq!(a, b);
 
diff --git a/tests/oper.rs b/tests/oper.rs
index 05172868..12e822cb 100644
--- a/tests/oper.rs
+++ b/tests/oper.rs
@@ -17,24 +17,24 @@ use approx::assert_abs_diff_eq;
 use defmac::defmac;
 
 fn test_oper(op: &str, a: &[f32], b: &[f32], c: &[f32]) {
-    let aa = rcarr1(a);
-    let bb = rcarr1(b);
-    let cc = rcarr1(c);
+    let aa = CowArray::from(arr1(a));
+    let bb = CowArray::from(arr1(b));
+    let cc = CowArray::from(arr1(c));
     test_oper_arr::<f32, _>(op, aa.clone(), bb.clone(), cc.clone());
     let dim = (2, 2);
-    let aa = aa.reshape(dim);
-    let bb = bb.reshape(dim);
-    let cc = cc.reshape(dim);
+    let aa = aa.to_shape(dim).unwrap();
+    let bb = bb.to_shape(dim).unwrap();
+    let cc = cc.to_shape(dim).unwrap();
     test_oper_arr::<f32, _>(op, aa.clone(), bb.clone(), cc.clone());
     let dim = (1, 2, 1, 2);
-    let aa = aa.reshape(dim);
-    let bb = bb.reshape(dim);
-    let cc = cc.reshape(dim);
+    let aa = aa.to_shape(dim).unwrap();
+    let bb = bb.to_shape(dim).unwrap();
+    let cc = cc.to_shape(dim).unwrap();
     test_oper_arr::<f32, _>(op, aa.clone(), bb.clone(), cc.clone());
 }
 
 
-fn test_oper_arr<A, D>(op: &str, mut aa: ArcArray<f32, D>, bb: ArcArray<f32, D>, cc: ArcArray<f32, D>)
+fn test_oper_arr<A, D>(op: &str, mut aa: CowArray<f32, D>, bb: CowArray<f32, D>, cc: CowArray<f32, D>)
 where
     D: Dimension,
 {
@@ -66,7 +66,7 @@ where
         }
         "neg" => {
             assert_eq!(-&aa, cc);
-            assert_eq!(-aa.clone(), cc);
+            assert_eq!(-aa.into_owned(), cc);
         }
         _ => panic!(),
     }
@@ -237,7 +237,7 @@ fn dot_product_neg_stride() {
 
 #[test]
 fn fold_and_sum() {
-    let a = Array::linspace(0., 127., 128).into_shape((8, 16)).unwrap();
+    let a = Array::linspace(0., 127., 128).into_shape_with_order((8, 16)).unwrap();
     assert_abs_diff_eq!(a.fold(0., |acc, &x| acc + x), a.sum(), epsilon = 1e-5);
 
     // test different strides
@@ -276,7 +276,7 @@ fn fold_and_sum() {
 
 #[test]
 fn product() {
-    let a = Array::linspace(0.5, 2., 128).into_shape((8, 16)).unwrap();
+    let a = Array::linspace(0.5, 2., 128).into_shape_with_order((8, 16)).unwrap();
     assert_abs_diff_eq!(a.fold(1., |acc, &x| acc * x), a.product(), epsilon = 1e-5);
 
     // test different strides
@@ -296,13 +296,13 @@ fn product() {
 
 fn range_mat(m: Ix, n: Ix) -> Array2<f32> {
     Array::linspace(0., (m * n) as f32 - 1., m * n)
-        .into_shape((m, n))
+        .into_shape_with_order((m, n))
         .unwrap()
 }
 
 fn range_mat64(m: Ix, n: Ix) -> Array2<f64> {
     Array::linspace(0., (m * n) as f64 - 1., m * n)
-        .into_shape((m, n))
+        .into_shape_with_order((m, n))
         .unwrap()
 }
 
@@ -313,7 +313,7 @@ fn range1_mat64(m: Ix) -> Array1<f64> {
 
 fn range_i32(m: Ix, n: Ix) -> Array2<i32> {
     Array::from_iter(0..(m * n) as i32)
-        .into_shape((m, n))
+        .into_shape_with_order((m, n))
         .unwrap()
 }
 
@@ -593,7 +593,7 @@ fn scaled_add_3() {
                     ]
                 };
 
-                let c = range_mat64(n, q).into_shape(cdim).unwrap();
+                let c = range_mat64(n, q).into_shape_with_order(cdim).unwrap();
 
                 {
                     let mut av = a.slice_mut(s![..;s1, ..;s2]);
@@ -711,8 +711,8 @@ fn gen_mat_vec_mul() {
         S2: Data<Elem = A>,
     {
         let ((m, _), k) = (lhs.dim(), rhs.dim());
-        reference_mat_mul(lhs, &rhs.as_standard_layout().into_shape((k, 1)).unwrap())
-            .into_shape(m)
+        reference_mat_mul(lhs, &rhs.as_standard_layout().into_shape_with_order((k, 1)).unwrap())
+            .into_shape_with_order(m)
             .unwrap()
     }
 
@@ -776,8 +776,8 @@ fn vec_mat_mul() {
         S2: Data<Elem = A>,
     {
         let (m, (_, n)) = (lhs.dim(), rhs.dim());
-        reference_mat_mul(&lhs.as_standard_layout().into_shape((1, m)).unwrap(), rhs)
-            .into_shape(n)
+        reference_mat_mul(&lhs.as_standard_layout().into_shape_with_order((1, m)).unwrap(), rhs)
+            .into_shape_with_order(n)
             .unwrap()
     }
 
diff --git a/tests/par_rayon.rs b/tests/par_rayon.rs
index 4d5a8f1a..40670c6b 100644
--- a/tests/par_rayon.rs
+++ b/tests/par_rayon.rs
@@ -25,7 +25,7 @@ fn test_axis_iter() {
 fn test_axis_iter_mut() {
     use approx::assert_abs_diff_eq;
     let mut a = Array::linspace(0., 1.0f64, M * N)
-        .into_shape((M, N))
+        .into_shape_with_order((M, N))
         .unwrap();
     let b = a.mapv(|x| x.exp());
     a.axis_iter_mut(Axis(0))
@@ -77,7 +77,7 @@ fn test_axis_chunks_iter() {
 fn test_axis_chunks_iter_mut() {
     use approx::assert_abs_diff_eq;
     let mut a = Array::linspace(0., 1.0f64, M * N)
-        .into_shape((M, N))
+        .into_shape_with_order((M, N))
         .unwrap();
     let b = a.mapv(|x| x.exp());
     a.axis_chunks_iter_mut(Axis(0), CHUNK_SIZE)
diff --git a/tests/reshape.rs b/tests/reshape.rs
index 21fe407e..24e7d01f 100644
--- a/tests/reshape.rs
+++ b/tests/reshape.rs
@@ -8,13 +8,13 @@ use ndarray::Order;
 fn reshape() {
     let data = [1, 2, 3, 4, 5, 6, 7, 8];
     let v = aview1(&data);
-    let u = v.into_shape((3, 3));
+    let u = v.into_shape_with_order((3, 3));
     assert!(u.is_err());
-    let u = v.into_shape((2, 2, 2));
+    let u = v.into_shape_with_order((2, 2, 2));
     assert!(u.is_ok());
     let u = u.unwrap();
     assert_eq!(u.shape(), &[2, 2, 2]);
-    let s = u.into_shape((4, 2)).unwrap();
+    let s = u.into_shape_with_order((4, 2)).unwrap();
     assert_eq!(s.shape(), &[4, 2]);
     assert_eq!(s, aview2(&[[1, 2], [3, 4], [5, 6], [7, 8]]));
 }
@@ -24,7 +24,7 @@ fn reshape() {
 fn reshape_error1() {
     let data = [1, 2, 3, 4, 5, 6, 7, 8];
     let v = aview1(&data);
-    let _u = v.into_shape((2, 5)).unwrap();
+    let _u = v.into_shape_with_order((2, 5)).unwrap();
 }
 
 #[test]
@@ -32,9 +32,9 @@ fn reshape_error1() {
 fn reshape_error2() {
     let data = [1, 2, 3, 4, 5, 6, 7, 8];
     let v = aview1(&data);
-    let mut u = v.into_shape((2, 2, 2)).unwrap();
+    let mut u = v.into_shape_with_order((2, 2, 2)).unwrap();
     u.swap_axes(0, 1);
-    let _s = u.into_shape((2, 4)).unwrap();
+    let _s = u.into_shape_with_order((2, 4)).unwrap();
 }
 
 #[test]
@@ -47,16 +47,16 @@ fn reshape_f() {
     println!("{:?}", v);
 
     // noop ok
-    let v2 = v.into_shape((3, 4));
+    let v2 = v.into_shape_with_order(((3, 4), Order::F));
     assert!(v2.is_ok());
     assert_eq!(v, v2.unwrap());
 
-    let u = v.into_shape((3, 2, 2));
+    let u = v.into_shape_with_order(((3, 2, 2), Order::F));
     assert!(u.is_ok());
     let u = u.unwrap();
     println!("{:?}", u);
     assert_eq!(u.shape(), &[3, 2, 2]);
-    let s = u.into_shape((4, 3)).unwrap();
+    let s = u.into_shape_with_order(((4, 3), Order::F)).unwrap();
     println!("{:?}", s);
     assert_eq!(s.shape(), &[4, 3]);
     assert_eq!(s, aview2(&[[0, 4, 8], [1, 5, 9], [2, 6, 10], [3, 7, 11]]));
@@ -230,3 +230,89 @@ fn to_shape_broadcast() {
         }
     }
 }
+
+
+#[test]
+fn into_shape_with_order() {
+    // 1D -> C -> C
+    let data = [1, 2, 3, 4, 5, 6, 7, 8];
+    let v = aview1(&data);
+    let u = v.into_shape_with_order(((3, 3), Order::RowMajor));
+    assert!(u.is_err());
+
+    let u = v.into_shape_with_order(((2, 2, 2), Order::C));
+    assert!(u.is_ok());
+
+    let u = u.unwrap();
+    assert_eq!(u.shape(), &[2, 2, 2]);
+    assert_eq!(u, array![[[1, 2], [3, 4]], [[5, 6], [7, 8]]]);
+
+    let s = u.into_shape_with_order((4, 2)).unwrap();
+    assert_eq!(s.shape(), &[4, 2]);
+    assert_eq!(s, aview2(&[[1, 2], [3, 4], [5, 6], [7, 8]]));
+
+    // 1D -> F -> F
+    let data = [1, 2, 3, 4, 5, 6, 7, 8];
+    let v = aview1(&data);
+    let u = v.into_shape_with_order(((3, 3), Order::ColumnMajor));
+    assert!(u.is_err());
+
+    let u = v.into_shape_with_order(((2, 2, 2), Order::ColumnMajor));
+    assert!(u.is_ok());
+
+    let u = u.unwrap();
+    assert_eq!(u.shape(), &[2, 2, 2]);
+    assert_eq!(u, array![[[1, 5], [3, 7]], [[2, 6], [4, 8]]]);
+
+    let s = u.into_shape_with_order(((4, 2), Order::ColumnMajor)).unwrap();
+    assert_eq!(s.shape(), &[4, 2]);
+    assert_eq!(s, array![[1, 5], [2, 6], [3, 7], [4, 8]]);
+}
+
+#[test]
+fn into_shape_clone() {
+    // 1D -> C -> C
+    {
+        let data = [1, 2, 3, 4, 5, 6, 7, 8];
+        let v = Array::from(data.to_vec());
+        let u = v.clone().into_shape_clone(((3, 3), Order::RowMajor));
+        assert!(u.is_err());
+
+        let u = v.clone().into_shape_clone(((2, 2, 2), Order::C));
+        assert!(u.is_ok());
+
+        let u = u.unwrap();
+        assert_eq!(u.shape(), &[2, 2, 2]);
+        assert_eq!(u, array![[[1, 2], [3, 4]], [[5, 6], [7, 8]]]);
+
+        let s = u.into_shape_clone((4, 2)).unwrap();
+        assert_eq!(s.shape(), &[4, 2]);
+        assert_eq!(s, aview2(&[[1, 2], [3, 4], [5, 6], [7, 8]]));
+
+        let u = v.clone().into_shape_clone(((2, 2, 2), Order::F));
+        assert!(u.is_ok());
+
+        let u = u.unwrap();
+        assert_eq!(u.shape(), &[2, 2, 2]);
+        assert_eq!(u, array![[[1, 5], [3, 7]], [[2, 6], [4, 8]]]);
+    }
+
+    // 1D -> F -> F
+    {
+        let data = [1, 2, 3, 4, 5, 6, 7, 8];
+        let v = Array::from(data.to_vec());
+        let u = v.clone().into_shape_clone(((3, 3), Order::ColumnMajor));
+        assert!(u.is_err());
+
+        let u = v.into_shape_clone(((2, 2, 2), Order::ColumnMajor));
+        assert!(u.is_ok());
+
+        let u = u.unwrap();
+        assert_eq!(u.shape(), &[2, 2, 2]);
+        assert_eq!(u, array![[[1, 5], [3, 7]], [[2, 6], [4, 8]]]);
+
+        let s = u.into_shape_clone(((4, 2), Order::ColumnMajor)).unwrap();
+        assert_eq!(s.shape(), &[4, 2]);
+        assert_eq!(s, array![[1, 5], [2, 6], [3, 7], [4, 8]]);
+    }
+}
diff --git a/tests/windows.rs b/tests/windows.rs
index 095976ea..c24a47ef 100644
--- a/tests/windows.rs
+++ b/tests/windows.rs
@@ -26,14 +26,14 @@ use ndarray::{arr3, Zip};
 #[test]
 #[should_panic]
 fn windows_iterator_zero_size() {
-    let a = Array::from_iter(10..37).into_shape((3, 3, 3)).unwrap();
+    let a = Array::from_iter(10..37).into_shape_with_order((3, 3, 3)).unwrap();
     a.windows(Dim((0, 0, 0)));
 }
 
 /// Test that verifies that no windows are yielded on oversized window sizes.
 #[test]
 fn windows_iterator_oversized() {
-    let a = Array::from_iter(10..37).into_shape((3, 3, 3)).unwrap();
+    let a = Array::from_iter(10..37).into_shape_with_order((3, 3, 3)).unwrap();
     let mut iter = a.windows((4, 3, 2)).into_iter(); // (4,3,2) doesn't fit into (3,3,3) => oversized!
     assert_eq!(iter.next(), None);
 }
@@ -41,7 +41,7 @@ fn windows_iterator_oversized() {
 /// Simple test for iterating 1d-arrays via `Windows`.
 #[test]
 fn windows_iterator_1d() {
-    let a = Array::from_iter(10..20).into_shape(10).unwrap();
+    let a = Array::from_iter(10..20).into_shape_with_order(10).unwrap();
     itertools::assert_equal(
         a.windows(Dim(4)),
         vec![
@@ -59,7 +59,7 @@ fn windows_iterator_1d() {
 /// Simple test for iterating 2d-arrays via `Windows`.
 #[test]
 fn windows_iterator_2d() {
-    let a = Array::from_iter(10..30).into_shape((5, 4)).unwrap();
+    let a = Array::from_iter(10..30).into_shape_with_order((5, 4)).unwrap();
     itertools::assert_equal(
         a.windows(Dim((3, 2))),
         vec![
@@ -79,7 +79,7 @@ fn windows_iterator_2d() {
 /// Simple test for iterating 3d-arrays via `Windows`.
 #[test]
 fn windows_iterator_3d() {
-    let a = Array::from_iter(10..37).into_shape((3, 3, 3)).unwrap();
+    let a = Array::from_iter(10..37).into_shape_with_order((3, 3, 3)).unwrap();
     itertools::assert_equal(
         a.windows(Dim((2, 2, 2))),
         vec![
@@ -99,14 +99,14 @@ fn windows_iterator_3d() {
 #[test]
 #[should_panic]
 fn windows_iterator_stride_axis_zero() {
-    let a = Array::from_iter(10..37).into_shape((3, 3, 3)).unwrap();
+    let a = Array::from_iter(10..37).into_shape_with_order((3, 3, 3)).unwrap();
     a.windows_with_stride((2, 2, 2), (0, 2, 2));
 }
 
 /// Test that verifies that only first window is yielded when stride is oversized on every axis.
 #[test]
 fn windows_iterator_only_one_valid_window_for_oversized_stride() {
-    let a = Array::from_iter(10..135).into_shape((5, 5, 5)).unwrap();
+    let a = Array::from_iter(10..135).into_shape_with_order((5, 5, 5)).unwrap();
     let mut iter = a.windows_with_stride((2, 2, 2), (8, 8, 8)).into_iter(); // (4,3,2) doesn't fit into (3,3,3) => oversized!
     itertools::assert_equal(
         iter.next(),
@@ -117,7 +117,7 @@ fn windows_iterator_only_one_valid_window_for_oversized_stride() {
 /// Simple test for iterating 1d-arrays via `Windows` with stride.
 #[test]
 fn windows_iterator_1d_with_stride() {
-    let a = Array::from_iter(10..20).into_shape(10).unwrap();
+    let a = Array::from_iter(10..20).into_shape_with_order(10).unwrap();
     itertools::assert_equal(
         a.windows_with_stride(4, 2),
         vec![
@@ -132,7 +132,7 @@ fn windows_iterator_1d_with_stride() {
 /// Simple test for iterating 2d-arrays via `Windows` with stride.
 #[test]
 fn windows_iterator_2d_with_stride() {
-    let a = Array::from_iter(10..30).into_shape((5, 4)).unwrap();
+    let a = Array::from_iter(10..30).into_shape_with_order((5, 4)).unwrap();
     itertools::assert_equal(
         a.windows_with_stride((3, 2), (2, 1)),
         vec![
@@ -149,7 +149,7 @@ fn windows_iterator_2d_with_stride() {
 /// Simple test for iterating 3d-arrays via `Windows` with stride.
 #[test]
 fn windows_iterator_3d_with_stride() {
-    let a = Array::from_iter(10..74).into_shape((4, 4, 4)).unwrap();
+    let a = Array::from_iter(10..74).into_shape_with_order((4, 4, 4)).unwrap();
     itertools::assert_equal(
         a.windows_with_stride((2, 2, 2), (2, 2, 2)),
         vec![
@@ -167,7 +167,7 @@ fn windows_iterator_3d_with_stride() {
 
 #[test]
 fn test_window_zip() {
-    let a = Array::from_iter(0..64).into_shape((4, 4, 4)).unwrap();
+    let a = Array::from_iter(0..64).into_shape_with_order((4, 4, 4)).unwrap();
 
     for x in 1..4 {
         for y in 1..4 {
@@ -190,7 +190,7 @@ fn test_window_zip() {
 #[test]
 #[should_panic]
 fn axis_windows_outofbound() {
-    let a = Array::from_iter(10..37).into_shape((3, 3, 3)).unwrap();
+    let a = Array::from_iter(10..37).into_shape_with_order((3, 3, 3)).unwrap();
     a.axis_windows(Axis(4), 2);
 }
 
@@ -198,14 +198,14 @@ fn axis_windows_outofbound() {
 #[test]
 #[should_panic]
 fn axis_windows_zero_size() {
-    let a = Array::from_iter(10..37).into_shape((3, 3, 3)).unwrap();
+    let a = Array::from_iter(10..37).into_shape_with_order((3, 3, 3)).unwrap();
     a.axis_windows(Axis(0), 0);
 }
 
 /// Test verifies that over sized windows yield nothing
 #[test]
 fn axis_windows_oversized() {
-    let a = Array::from_iter(10..37).into_shape((3, 3, 3)).unwrap();
+    let a = Array::from_iter(10..37).into_shape_with_order((3, 3, 3)).unwrap();
     let mut iter = a.axis_windows(Axis(2), 4).into_iter();
     assert_eq!(iter.next(), None);
 }
@@ -213,7 +213,7 @@ fn axis_windows_oversized() {
 /// Simple test for iterating 1d-arrays via `Axis Windows`.
 #[test]
 fn test_axis_windows_1d() {
-    let a = Array::from_iter(10..20).into_shape(10).unwrap();
+    let a = Array::from_iter(10..20).into_shape_with_order(10).unwrap();
 
     itertools::assert_equal(
         a.axis_windows(Axis(0), 5),
@@ -231,7 +231,7 @@ fn test_axis_windows_1d() {
 /// Simple test for iterating 2d-arrays via `Axis Windows`.
 #[test]
 fn test_axis_windows_2d() {
-    let a = Array::from_iter(10..30).into_shape((5, 4)).unwrap();
+    let a = Array::from_iter(10..30).into_shape_with_order((5, 4)).unwrap();
 
     itertools::assert_equal(
         a.axis_windows(Axis(0), 2),
@@ -247,7 +247,7 @@ fn test_axis_windows_2d() {
 /// Simple test for iterating 3d-arrays via `Axis Windows`.
 #[test]
 fn test_axis_windows_3d() {
-    let a = Array::from_iter(0..27).into_shape((3, 3, 3)).unwrap();
+    let a = Array::from_iter(0..27).into_shape_with_order((3, 3, 3)).unwrap();
 
     itertools::assert_equal(
         a.axis_windows(Axis(1), 2),
@@ -269,14 +269,14 @@ fn test_axis_windows_3d() {
 
 #[test]
 fn test_window_neg_stride() {
-    let array = Array::from_iter(1..10).into_shape((3, 3)).unwrap();
+    let array = Array::from_iter(1..10).into_shape_with_order((3, 3)).unwrap();
 
     // window neg/pos stride combinations
     
     // Make a 2 x 2 array of the windows of the 3 x 3 array
     // and compute test answers from here
     let mut answer = Array::from_iter(array.windows((2, 2)).into_iter().map(|a| a.to_owned()))
-        .into_shape((2, 2)).unwrap();
+        .into_shape_with_order((2, 2)).unwrap();
 
     answer.invert_axis(Axis(1));
     answer.map_inplace(|a| a.invert_axis(Axis(1)));
@@ -305,7 +305,7 @@ fn test_window_neg_stride() {
 
 #[test]
 fn test_windows_with_stride_on_inverted_axis() {
-    let mut array = Array::from_iter(1..17).into_shape((4, 4)).unwrap();
+    let mut array = Array::from_iter(1..17).into_shape_with_order((4, 4)).unwrap();
     
     // inverting axis results in negative stride
     array.invert_axis(Axis(0));
diff --git a/xtest-blas/tests/oper.rs b/xtest-blas/tests/oper.rs
index 120626d0..5f11893d 100644
--- a/xtest-blas/tests/oper.rs
+++ b/xtest-blas/tests/oper.rs
@@ -45,26 +45,26 @@ fn mat_vec_product_1d_inverted_axis() {
 
 fn range_mat(m: Ix, n: Ix) -> Array2<f32> {
     Array::linspace(0., (m * n) as f32 - 1., m * n)
-        .into_shape((m, n))
+        .into_shape_with_order((m, n))
         .unwrap()
 }
 
 fn range_mat64(m: Ix, n: Ix) -> Array2<f64> {
     Array::linspace(0., (m * n) as f64 - 1., m * n)
-        .into_shape((m, n))
+        .into_shape_with_order((m, n))
         .unwrap()
 }
 
 fn range_mat_complex(m: Ix, n: Ix) -> Array2<Complex32> {
     Array::linspace(0., (m * n) as f32 - 1., m * n)
-        .into_shape((m, n))
+        .into_shape_with_order((m, n))
         .unwrap()
         .map(|&f| Complex32::new(f, 0.))
 }
 
 fn range_mat_complex64(m: Ix, n: Ix) -> Array2<Complex64> {
     Array::linspace(0., (m * n) as f64 - 1., m * n)
-        .into_shape((m, n))
+        .into_shape_with_order((m, n))
         .unwrap()
         .map(|&f| Complex64::new(f, 0.))
 }
@@ -75,7 +75,7 @@ fn range1_mat64(m: Ix) -> Array1<f64> {
 
 fn range_i32(m: Ix, n: Ix) -> Array2<i32> {
     Array::from_iter(0..(m * n) as i32)
-        .into_shape((m, n))
+        .into_shape_with_order((m, n))
         .unwrap()
 }
 
@@ -119,8 +119,8 @@ where
     S2: Data<Elem = A>,
 {
     let ((m, _), k) = (lhs.dim(), rhs.dim());
-    reference_mat_mul(lhs, &rhs.as_standard_layout().into_shape((k, 1)).unwrap())
-        .into_shape(m)
+    reference_mat_mul(lhs, &rhs.as_standard_layout().into_shape_with_order((k, 1)).unwrap())
+        .into_shape_with_order(m)
         .unwrap()
 }
 
@@ -132,8 +132,8 @@ where
     S2: Data<Elem = A>,
 {
     let (m, (_, n)) = (lhs.dim(), rhs.dim());
-    reference_mat_mul(&lhs.as_standard_layout().into_shape((1, m)).unwrap(), rhs)
-        .into_shape(n)
+    reference_mat_mul(&lhs.as_standard_layout().into_shape_with_order((1, m)).unwrap(), rhs)
+        .into_shape_with_order(n)
         .unwrap()
 }
 
diff --git a/xtest-numeric/tests/accuracy.rs b/xtest-numeric/tests/accuracy.rs
index 1f8e9a82..67926709 100644
--- a/xtest-numeric/tests/accuracy.rs
+++ b/xtest-numeric/tests/accuracy.rs
@@ -65,7 +65,7 @@ fn reference_mat_mul<A, S, S2>(lhs: &ArrayBase<S, Ix2>, rhs: &ArrayBase<S2, Ix2>
         }
     }
 
-    res_elems.into_shape((m, n)).unwrap()
+    res_elems.into_shape_with_order((m, n)).unwrap()
 }
 
 fn gen<A, D>(d: D, rng: &mut SmallRng) -> Array<A, D>
diff --git a/xtest-serialization/tests/serialize.rs b/xtest-serialization/tests/serialize.rs
index efb3bacd..cea84dd7 100644
--- a/xtest-serialization/tests/serialize.rs
+++ b/xtest-serialization/tests/serialize.rs
@@ -45,7 +45,7 @@ fn serial_many_dim_serde() {
 
     {
         // Test a sliced array.
-        let mut a = ArcArray::linspace(0., 31., 32).reshape((2, 2, 2, 4));
+        let mut a = ArcArray::linspace(0., 31., 32).into_shape_with_order((2, 2, 2, 4)).unwrap();
         a.slice_collapse(s![..;-1, .., .., ..2]);
         let serial = serde_json::to_string(&a).unwrap();
         println!("Encode {:?} => {:?}", a, serial);
@@ -77,7 +77,7 @@ fn serial_ixdyn_serde() {
 
     {
         let a = arr2(&[[3., 1., 2.2], [3.1, 4., 7.]])
-            .into_shape(IxDyn(&[3, 1, 1, 1, 2, 1]))
+            .into_shape_with_order(IxDyn(&[3, 1, 1, 1, 2, 1]))
             .unwrap();
         let serial = serde_json::to_string(&a).unwrap();
         println!("Serde encode {:?} => {:?}", a, serial);
@@ -155,7 +155,7 @@ fn serial_many_dim_serde_msgpack() {
 
     {
         // Test a sliced array.
-        let mut a = ArcArray::linspace(0., 31., 32).reshape((2, 2, 2, 4));
+        let mut a = ArcArray::linspace(0., 31., 32).into_shape_with_order((2, 2, 2, 4)).unwrap();
         a.slice_collapse(s![..;-1, .., .., ..2]);
 
         let mut buf = Vec::new();
@@ -208,7 +208,7 @@ fn serial_many_dim_ron() {
 
     {
         // Test a sliced array.
-        let mut a = ArcArray::linspace(0., 31., 32).reshape((2, 2, 2, 4));
+        let mut a = ArcArray::linspace(0., 31., 32).into_shape_with_order((2, 2, 2, 4)).unwrap();
         a.slice_collapse(s![..;-1, .., .., ..2]);
 
         let a_s = ron_serialize(&a).unwrap();