Swift: Overriding Self-requirement is allowed, but causes runtime error. Why? -


i started learn swift (v. 2.x) because i'm curious how new features play out, protocols self-requirements.

the following example going compile fine, causes arbitrary runtime effects happen:

// protocol self requirement protocol narcissistic {     func getfriend() -> self }   // base class adopts protocol class mario : narcissistic  {     func getfriend() -> self {         print("mario.getfriend()")         return self;     } }   // intermediate class eliminates // self requirement specifying explicit type // (why compiler allow this?) class supermario : mario {     override func getfriend() -> supermario {         print("supermario.getfriend()")         return supermario();     } }  // specific class defines field // (polymorphic) access cause world explode class fireflowermario : supermario {     let fireballcount = 42      func throwfireballs() {         print("throwing " + string(fireballcount) + " fireballs!")     } }   // global generic function restricted protocol func queryfriend<t : narcissistic>(narcissistic: t) -> t {     return narcissistic.getfriend() }   // sample client code  // instantiate specific class let m = fireflowermario()  // call generic function verified return // same type went in -- 'fireflowermario' in case. // in reality, method returns 'supermario' , // call 'throwfireballs' cause arbitrary // things happen @ runtime. queryfriend(m).throwfireballs() 

you can see example in action on ibm swift sandbox here. in browser, output follows:

 supermario.getfriend() throwing 32 fireballs! 

(instead of 42! or rather, 'instead of runtime exception', method not defined on object called on.)

is proof swift not type-safe?

edit #1:

unpredictable behavior has unacceptable. true question is, exact meaning keyword self (capital first letter) has. couldn't find online, there @ least these 2 possibilities:

  • self syntactic shortcut full class name appears in, , substituted latter without change in meaning. then, cannot have same meaning when appears inside protocol definition.

  • self sort of generic/associated type (in both protocols , classes) gets re-instantiated in deriving/adopting classes. if case, compiler should have refused override of getfriend in supermario.

maybe true definition neither of those. great if more experience language shed light on topic.

yes, there seems contradiction. self keyword, when used return type, apparently means 'self instance of self'. example, given protocol

protocol returnsreceived {      /// returns other.     func doreturn(other: self) -> self } 

we can't implement follows

class return: returnsreceived {      func doreturn(other: return) -> self {         return other    // error     } } 

because compiler error ("cannot convert return expression of type 'return' return type 'self'"), disappears if violate doreturn()'s contract , return self instead of other. , can't write

class return: returnsreceived {      func doreturn(other: return) -> return {    // error         return other     } } 

because allowed in final class, if swift supports covariant return types. (the following compiles.)

final class return: returnsreceived {      func doreturn(other: return) -> return {         return other     } } 

on other hand, pointed out, subclass of return can 'override' self requirement , merrily honor contract of returnsreceived, if self simple placeholder conforming class' name.

class subreturn: return {      override func doreturn(other: return) -> subreturn {         // of course crashes if other not         // subreturn instance, let's ignore         // problem now.         return other as! subreturn     } } 

i wrong, think that:

  • if self return type means 'self instance of self', compiler should not accept kind of self requirement overriding, because makes possible return instances not self; otherwise,

  • if self return type must placeholder no further implications, in our example compiler should allow overriding self requirement in return class.

that said, , here choice precise semantics of self not bound change things, code illustrates 1 of cases compiler can fooled, , best can generate code defer checks run-time. in case, checks should delegated runtime have casting, , in opinion 1 interesting aspect revealed examples @ particular spot swift seems not delegate anything, hence inevitable crash more dramatic ought be.

swift able check casts @ run-time. let's consider following code.

let sm = supermario() let ffm = sm as! fireflowermario ffm.throwfireballs() 

here create supermario , downcast fireflowermario. these 2 classes not unrelated, , assuring compiler (as!) know doing, compiler leaves , compiles second , third lines without hitch. however, program fails @ run-time, complaining it

could not cast value of type 'somemodule.supermario' (0x...) 'somemodule.fireflowermario' (0x...). 

when trying cast in second line. not wrong or surprising behaviour. java, example, same: compile code, , fail @ run-time classcastexception. important thing application reliably crashes @ run-time.

your code more elaborate way fool compiler, boils down same problem: there supermario instead of fireflowermario. difference in case don't gentle "could not cast" message but, in real xcode project, abrupt , terrific error when calling throwfireballs().

in same situation, java fails (at run-time) same error saw above (a classcastexception), means attempts cast (to fireflowermario) before calling throwfireballs() on object returned queryfriend(). presence of explicit checkcast instruction in bytecode confirms this.

swift on contrary, far can see @ moment, not try cast before call (no casting routine called in compiled code), horrible, uncaught error possible outcome. if, instead, code produced run-time "could not cast" error message, or gracious that, satisfied behaviour of language.


Comments

Popular posts from this blog

javascript - jQuery: Add class depending on URL in the best way -

caching - How to check if a url path exists in the service worker cache -

Redirect to a HTTPS version using .htaccess -