Returning a more specific type from a subclassed method?

83 views
Skip to first unread message

Ben Gollmer

unread,
Jul 19, 2014, 3:15:16 PM7/19/14
to swift-l...@googlegroups.com
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


Jeremy Pereira

unread,
Jul 22, 2014, 8:32:36 AM7/22/14
to swift-l...@googlegroups.com, Ben Gollmer

My guess is that that String? is not a subclass of Any?

Type? is shorthand for Optional<Type>. I don't see why the compiler would necessarily regard Optional<String> as being a subclass of Optional<Any> - after all, actually it isn't.
> --
> Ben
>
>
> --
> You received this message because you are subscribed to the Google Groups "Swift Language" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to swift-languag...@googlegroups.com.
> To post to this group, send email to swift-l...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/920F0832-8164-4ADD-9BFB-EBB9B2457AB1%40tcnetworks.com.
> For more options, visit https://groups.google.com/d/optout.

Ben Gollmer

unread,
Jul 22, 2014, 10:15:39 AM7/22/14
to Jeremy Pereira, swift-l...@googlegroups.com
That sounds plausible, but changing the return types to non-Optional results in the same behavior for all three implementations of StringOption.value().


Ben

Jeremy Pereira

unread,
Jul 22, 2014, 10:34:58 AM7/22/14
to swift-l...@googlegroups.com, Ben Gollmer
Also, String is a struct, so it doesn't have superclasses.

Ben Gollmer

unread,
Jul 22, 2014, 12:21:34 PM7/22/14
to Jeremy Pereira, swift-l...@googlegroups.com
I’m not sure why that is important — a String is still an Any.

I tried declaring Option.value() as returning AnyObject / AnyObject? and StringOption.value() as returning NSString / NSString?, but saw no change in behavior.



Ben

On Jul 22, 2014, at 9:34 AM, Jeremy Pereira <jeremy.j...@googlemail.com> wrote:

> Also, String is a struct, so it doesn't have superclasses.
>
>
> On 22 Jul 2014, at 15:15, Ben Gollmer <bgol...@tcnetworks.com> wrote:
>
>> That sounds plausible, but changing the return types to non-Optional results in the same behavior for all three implementations of StringOption.value().
>>
>> --
> To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/F760AD06-AAB1-4CD9-8ECC-3B0BB58DE85B%40googlemail.com.

Jeremy Pereira

unread,
Jul 23, 2014, 4:25:39 AM7/23/14
to Ben Gollmer, swift-l...@googlegroups.com
Actually, a String is not an Any in the sense of being a subclass.

I'm not saying the current behaviour is right, I'm just theorising about why it might be so.
Reply all
Reply to author
Forward
0 new messages