1

Normally I have an array with MemoryComponent classes (so [MemoryComponent]). I'd like to refactor that to a custom array class, which has an element type of MemoryComponent and includes stored properties which the program can use.

I tried creating an extension, but it doesn't allow stored properties:

extension Array where Element: MemoryComponent {
    // ... no stored properties due to extension
}

I also tried creating another class for the array:

class StorageArray: Array<MemoryComponent> {
    // ... stored properties are possible
    // but there's an error because of this:
    // error: inheritance from non-protocol, non-class type 'Array<MemoryComponent>'
}

How do I effectively create an inheritance from [MemoryComponent] to include stored properties?

5
  • 1
    Use composition instead of inheritance, create a new class that has the array as a (private) property and then add your other properties and functions to access/modify the array. You could also let the array be public if you don’t need that kind of control of it. Commented Dec 1, 2021 at 11:32
  • @JoakimDanielson - That is a possibility, although built-in array methods aren't (directly) available in that context Commented Dec 1, 2021 at 11:33
  • I don’t think you have that many other options if you want to include your own stored properties Commented Dec 1, 2021 at 11:35
  • Is there an array-like protocol to create the class with? Commented Dec 1, 2021 at 11:36
  • Yes there is, check out the documentation for Array and see what it conforms to. Commented Dec 1, 2021 at 12:19

1 Answer 1

1

It's probably better to use composition for your case.

... but if a custom sort of Array is what you really want, there is actually a weird and not recommended option to hack that.

You can't inherit from Array since it's a struct. But you can implement the Collection protocol.

struct MemoryComponent {}

struct MemoryComponentsArray: Collection {
    
    // typealias all associatedTypes of `Collection` protocol
    typealias Element = MemoryComponent
    typealias Index = Array<Element>.Index
    typealias SubSequence = Array<Element>.SubSequence
    typealias Iterator = Array<Element>.Iterator
    typealias Indices = Array<Element>.Indices
    
    /// Your real data storage
    private let internalArray: Array<Element>
    
    /**
     Create any custom initializers you need
     */
    init(_ arrayLiteral: [Element]) {
        self.internalArray = arrayLiteral
    }
    
    // Implement `Collection` protocol core stuff
    // By referencing to internal array
    
    var startIndex: Index { internalArray.startIndex }
    var endIndex: Index { internalArray.endIndex }
    func makeIterator() -> Iterator { internalArray.makeIterator() }
    subscript(position: Index) -> Element { internalArray[position] }
    subscript(bounds: Range<Index>) -> SubSequence { internalArray[bounds] }
    var indices: Indices { internalArray.indices }
    var isEmpty: Bool { internalArray.isEmpty }
    var count: Int { internalArray.count }
    func index(_ i: Index, offsetBy distance: Int) -> Index {
        internalArray.index(i, offsetBy: distance)
    }
    func index(_ i: Index, offsetBy distance: Int, limitedBy limit: Index) -> Index? {
        internalArray.index(i, offsetBy: distance, limitedBy: limit)
    }
    func distance(from start: Index, to end: Index) -> Int {
        internalArray.distance(from: start, to: end)
    }
    func index(after i: Index) -> Index {
        internalArray.index(after: i)
    }
    func formIndex(after i: inout Index) {
        internalArray.formIndex(after: &i)
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

At this point, it's probably better to use a composition strategy rather than reimplementing most of the array methods
@Smally yes, that's right. Most of Array's functions are already implemented in the Collection protocol's extension. Depends on what methods of Array you need. The stuff I posted above is everything you're obligated to implement. Everything else is optional.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.