subclassing specialized generic class in swift

I have a generic class DataSource over AnyObject. with a subscript function to pull some items from the cache.

When I subclass of DataSource for example the subscript function stops getting considered an override and subsequently invoking it on an object of type SpecialDataSource will call the super class version.

class DataSource<T: AnyObject>: NSObject {
    var cache: [T]?

    subscript(idx: Int) -> T? {
        if let hasStash = cache {
            if idx < hasStash.count{
                return hasStash[idx]
            }
        }
        return nil
    }
}


class SpecialDataSource<T> : DataSource<NSNumber> {
//The following declaration will generate:
//subscript does not override any subscript from its superclass

    override subscript(idx: Int) -> T? {
        if let hasStash = cache {
            if idx < hasStash.count{
                return hasStash[idx] as? T
            }
        }
        return nil
    }

}

after experimenting with this in Playground i found that this would not have happened if the SpecialDataSource declaration was:

class SpecialDataSource<T> : DataSource<T>

I need the subclass to be based of a common object so i can stuff a few of them in a homogenous array.

so this declaration doesn't provide that option.

When i got this error it sounded like DataSource<NSNumber> is complete different superclass.

Any Idea whats going wrong here? Im trying to understand why my SpecialDataSource can't seem to override this function.

=============== Current Solution ===========

The only way i was able to work around this problem is by specializing the return type of the subscript to NSNumber, with that in place the override did actually do the job.

Not sure if there is a better solution. Please let me know. I will be happy to try it out.

class SpecialDataSource2<T: NSNumber> : DataSource2<NSNumber> {
    override subscript(idx: Int) -> NSNumber? {
        if let hasStash = cache {
            if idx < hasStash.count{
                return hasStash[idx] as? T
            }
        }
        return nil
    }

}

Answers


DataSource<NSNumber> is indeed a different superclass. Different code gets generated!

It's not really making sense that you're specializing the parent class to use NSNumber. What's the deeper intent / goal? What goes wrong if you follow the T pattern in both child and parent?

Suppose the parent class had another method xyz that used T. Well now that's been bound to NSNumber, so xyz expects an NSNumber. And any child class of course inherits the xyz method. But now suppose your child class is instantiated with NSString for T. What is the compiler supposed to do with method xyz for an instance of SpecialDataSource? Do you see the inherent conflict?

As "magically flexible" generics are, they actually come with quite a few very specific rules.


One option may be to define the subclass like this:

class SpecialDataSource<T, U> : DataSource<T> { ... }

That adds some complexity - SpecialDataSource now requires two generic types.

But it also adds flexibility. You could have superclasses of DataSource<NSNumber> or DataSource<NSWhateverYouWant>.

Also, I believe your subclass's subscript function would look something like this:

subscript(idx: Int) -> U? {
    if let hasStash = cache {
        if idx < hasStash.count{
            return hasStash[idx] as? U
        }
    }
    return nil
}

...and the override would not be necessary (I'm not in a spot where I could test this.)


Need Your Help

mule returning primary key on successful insert

mule mule-studio mule-component mule-el

Hi there I'm new to Mule and I needed pointer on how to process records. I'm trying to perform an operation where I insert a new record into one table and if the record is inserted successfully, ob...

How do I make part of layer to disappear when it moves to certain part of the screen in cocos2d-x

android c++ ios cocos2d-x

I'm currently using CCScrollLayer in cocos2d-x to scroll my list of items but I want the part of the list to disappear before it goes out of the screen.