     }
 }
 
+public extension ChainComplex where chainType == Descending {
+    public var dual: CochainComplex<R, A> {
+        return CochainComplex(chain.reversed(), offset: offset)
+    }
+}
+
+public extension ChainComplex where chainType == Ascending {
+    public var dual: ChainComplex<R, A> {
+        return ChainComplex(chain.reversed(), offset: offset)
+    }
+}
+
 public func ⊗<chainType: ChainType, R: Ring, A: FreeModuleBase, B: FreeModuleBase>(C1: _ChainComplex<chainType, R, A>, C2: _ChainComplex<chainType, R, B>) -> _ChainComplex<chainType, R, Tensor<A, B>> {
     typealias NewChainBasis = [Tensor<A, B>]
     typealias NewBoundaryMap = FreeModuleHom<R, Tensor<A, B>, Tensor<A, B>>

        default:
            return BoundaryMap.zero
        }
    }
    
    @discardableResult

    public typealias ChainBasis = [A]
    public typealias BoundaryMap = FreeModuleHom<R, A, A>
    
    internal let chain: [BoundaryMap]
    public  let offset: Int
    
    // root initializer
