         return elementShape == nil
     }
 
-    /// The number of items (atoms) per element (sub-tensor).
+    /// The number of units (atoms) per element (sub-tensor).
     /// - Note: This holds the same value as the computed property
     /// `shape.contiguousSize`, which is extremely frequently used.
     /// We cache it in this variable whenever a new shape is set
-    public private(set) var itemCountPerElement: Int
+    public private(set) var unitCountPerElement: Int
 
     /// Contiguous storage
-    public fileprivate(set) var items: ContiguousArray<ItemType>
+    public fileprivate(set) var units: ContiguousArray<UnitType>
 
     /// Capacity reserved for sub-tensors
     public var capacity: Int {
-        return items.capacity / itemCountPerElement
-    }
-
-    fileprivate init(elementShape: TensorShape?, items: ContiguousArray<ItemType>) {
+        return units.capacity / unitCountPerElement
+    }
+
+    fileprivate init(elementShape: TensorShape?, units: ContiguousArray<UnitType>) {
         let elementContiguousSize = elementShape?.contiguousSize ?? 1
-        precondition(items.count % elementContiguousSize == 0,
-                     "Item count does not match element shape")
-        self.itemCountPerElement = elementShape == nil ? 0 : elementContiguousSize
+        precondition(units.count % elementContiguousSize == 0,
+                     "Unit count does not match element shape")
+        self.unitCountPerElement = elementShape == nil ? 0 : elementContiguousSize
         self.elementShape = elementShape
-        self.items = ContiguousArray(items)
+        self.units = ContiguousArray(units)
     }
 
     /// Initialize a tensor using an existing slice of elements in row-major order
     /// - parameter shape: tensor shape
     /// - parameter elements: slice of existing elements in row-major order
-    fileprivate init(shape: TensorShape, items: ContiguousArray<ItemType>) {
-        precondition(items.count >= shape.contiguousSize,
+    fileprivate init(shape: TensorShape, units: ContiguousArray<UnitType>) {
+        precondition(units.count >= shape.contiguousSize,
                      "The slice has fewer elements than required by the shape")
         self.init(elementShape: shape.isScalar ? nil : shape.dropFirst(),
-                  items: ContiguousArray(items.prefix(shape.contiguousSize)))
+                  units: ContiguousArray(units.prefix(shape.contiguousSize)))
     }
 
     /// Initialize an empty tensor of scalar elements

    }
}

// MARK: - RangeReplaceableCollection
extension Tensor : RangeReplaceableCollection {

    public typealias SubSequence = RangeReplaceableRandomAccessSlice<Tensor<ItemType>>

    public mutating func append(_ newElement: Tensor<ItemType>) {
        precondition(newElement.shape == elementShape, "Element shape mismatch")
        reserveCapacity(count + 1)
        items.append(contentsOf: newElement.items)
    }

    public mutating func reserveCapacity(_ minimumCapacity: Int) {
        let cap = Swift.max(items.capacity, itemCountPerElement * minimumCapacity)
        items.reserveCapacity(cap)
    }

    @discardableResult
    public mutating func remove(at index: Int) -> Tensor<ItemType> {
        precondition(indices.contains(index), "Index out of range")
        let range = itemSubrange(from: index..<index+1)
        defer { items.removeSubrange(range) }
        return Tensor(self[range])
    }

    public mutating func append<S : Sequence>(contentsOf newElements: S)
        where S.Iterator.Element == Tensor<ItemType> {
        for element in newElements {
            append(element)
        }
    }

    public mutating func append<C : Collection>(contentsOf newElements: C)
        where C.Iterator.Element == Tensor<ItemType>, C.IndexDistance == Int {
        reserveCapacity(count + newElements.count)
        for element in newElements {
            append(element)
        }
    }

    public mutating func append(contentsOf newElements: Tensor<ItemType>) {
        precondition(newElements.elementShape == elementShape, "Element shape mismatch")
        reserveCapacity(count + newElements.count)
        items.append(contentsOf: newElements.items)
    }

    public mutating func replaceSubrange<C : Collection>
        (_ subrange: Range<Int>, with newElements: C) where C.Iterator.Element == Tensor<ItemType> {
        let range = itemSubrange(from: subrange)
        let elemShape = elementShape
        items.replaceSubrange(range, with: newElements.lazy.flatMap { elem -> ContiguousArray<ItemType> in
            precondition(elemShape == elem.shape, "Element shape mismatch")
            return elem.items
        })
    }

    public subscript(bounds: Range<Int>) -> RangeReplaceableRandomAccessSlice<Tensor<ItemType>> {
        get {
            precondition(isScalar,
                         "I am a scalar and I have no dimensions!")

//

public protocol TensorProtocol : RangeReplaceableCollection, RandomAccessCollection {
    associatedtype UnitType
    var units: ContiguousArray<UnitType> { get }
    var unitCountPerElement: IndexDistance { get }
    var elementShape: TensorShape? { get }
    subscript(index: Index) -> Self { get }
    subscript(index: TensorIndex) -> Self { get }
