3

I have an abstract class in my mind and I can't implement its several features in swift, so I use C++ to deliver my thoughts:

template <class T>
class Swapping {
public:
    void swap() { _foregroundIndex = backgroundIndex() }
    virtual void cleanup() = 0;
    T* foreground() { return _buffer[foregroundIndex()]; }
    T* background() { return _buffer[backgroundIndex()]; }
    void setForeground(T* foreground) { _buffer[foregroundIndex()] = foreground; }
    void setBackground(T* background) { _buffer[backgroundIndex()] = background; }
private: 
    short foregroundIndex() { return _foregroundIndex; } 
    short backgroundIndex() { return _foregroundIndex ^ 1; }
    short _foregroundIndex = 0;
    T* _buffer[2] = {NULL, NULL};
}

The main contradiction is that

  1. The pure virtual method cleanup() requires all subclasses to implement it explicitly (can achieve in swift with protocol)
  2. The instance variable _foregroundIndex has an initial value (cannot achieve using protocol)
  3. The instance variable _foregroundIndex is restricted to be private ( cannot achieve using protocol)

On the other hand, if I use a class instead of protocol, then I can't guarantee cleanup() method is overriden.

One may suggest that put the virtual method in a protocol and the instance variable in a class. That may work but is not a obsession-satisfying one.

P.S. Objective-C is not Swift. Any objc_runtime related workaround is not preferred.

Nandin Borjigin
  • 2,094
  • 1
  • 16
  • 37
  • Swift doesn't support abstract class and [plans for it has been defered](https://github.com/apple/swift-evolution/blob/master/proposals/0026-abstract-classes-and-methods.md). There's no perfect workaround in Swift, see the discussion in [this question](http://stackoverflow.com/questions/24111356/swift-class-method-which-must-be-overridden-by-subclass) – Code Different Dec 26 '16 at 07:04
  • Thinking about an answer, it seems to me as you are mixing implementation details with APIs. A protocol is just supposed to express the public API that can be used, to express a set of functionality. `_foregroundIndex`, however, is an implementation detail. Why would the protocol care about how a class implements the functionality described in the protocol? – idmean Dec 26 '16 at 08:18

1 Answers1

2

There’s an obvious solution, which I have seen often but will certainly not satisfy you is:

func cleanup() {
    fatalError("You must override cleanup()")
}

Then you could try using extensions to extend the protocol with default implementations, but extensions don’t allow stored properties and so you would most likely need some external objects or other magic you certainly also dislike.

As I noted above in the comments, you might need to rethink your design. I don’t know what you really intend to do, but maybe something like this would work out for you:

class Swapper<T> {
    private var foregroundIndex = 0
    private var backgroundIndex: Int {
        return foregroundIndex ^ 1
    }
    private var buffer: [T?] = [nil, nil]

    private let cleanupHandler: () -> ()

    init(cleanupHandler: @escaping () -> ()) {
        self.cleanupHandler = cleanupHandler
    }

    func cleanup() {
        cleanupHandler()
    }

    var foreground: T? {
        get {
            return buffer[foregroundIndex]
        }
        set {
            buffer[foregroundIndex] = newValue
        }
    }
    var background: T? {
        get {
            return buffer[backgroundIndex]
        }
        set {
            buffer[backgroundIndex] = newValue
        }
    }

    func swap() {
        foregroundIndex = backgroundIndex
    }
}

This makes more sense to me as this allows any types to be swapped with any clean up handler, without having to subclass the class every time.

idmean
  • 14,540
  • 9
  • 54
  • 83