According to
http://nomothetis.svbtle.com/type-variance-in-swift, function return types are covariant (e.g. it’s fine to return a more specific type than required), but that doesn’t seem to extend to methods.
For example, given this code:
> class Option {
> func value() -> Any? {
> return nil
> }
> }
>
> class StringOption: Option {
> // Various options for implementing value() listed below
> }
>
> let o1 = Option()
> let o2 = StringOption()
>
> for opt in [o1, o2] {
> println(opt.value())
> }
>
> if o2.value()!.hasPrefix("T") {
> println("That worked")
> }
This causes the compiler to complain "Method does not override any method from its superclass":
> override func value() -> String? {
> return "TEST"
> }
This compiles and runs, but unexpectedly prints "nil, nil" from the for loop:
> func value() -> String? {
> return "TEST"
> }
And this loses type information, causing a compiler error on the hasPrefix() call; "'Any' does not have a member named 'hasPrefix'":
> override func value() -> Any? {
> return "TEST"
> }
Is this expected behavior, or a bug? The equivalent Obj-C code does behave as I’d expect.
> #import <Foundation/Foundation.h>
>
> @interface Option: NSObject
> - (id)value;
> @end
>
> @implementation Option
> - (id)value {
> return nil;
> }
> @end
>
> @interface StringOption: Option
> @end
>
> @implementation StringOption
> - (NSString *)value {
> return @"TEST";
> }
> @end
>
> int main(int argc, char *argv[]) {
> Option *o1 = [[Option alloc] init];
> StringOption *o2 = [[StringOption alloc] init];
>
> for(Option *opt in @[o1, o2]) {
> NSLog(@"%@", [opt value]);
> }
>
> if([[o2 value] hasPrefix:@"T"]) {
> NSLog(@"That worked");
> }
> }
—
Ben