Redeclaring members in an extension hides the original member *sometimes*. Why?
This works because you are declaring this extension in a separate module from the original variable declaration.
Across modules a variable name can be overloaded but in my mind this has been a shortcoming of Swift as there is currently no way to explicitly state which module declaration it is that you want.
Swift override function in extension
From the documentation:
Extensions can add new functionality to a type, but they cannot override existing functionality.
The documentation lists carefully and precisely what an extension is allowed to do.
As to your question:
Is there anyway to override a function of a particular class
Yes, it's called subclassing.
Dynamic dispatching protocol extension doesn't work multiple targets
Your Project
module declares MyClass
's conformance to ProtocolA
.
Swift implements that conformance using a data structure called a “protocol witness table”. For each method declared by the protocol, the witness table contains a function that calls the actual implementation of the method for the conforming type.
To be concrete, there is a witness table for the conformance of MyClass
to ProtocolA
. That witness table contains a function for the dontCrash
method declared by ProtocolA
. That function in the witness table calls the MyClass
dontCrash
method.
You can see the function from the protocol witness table in the stack trace when your test case hits fatalError
:
#8 0x00000001003ab9d9 in _assertionFailure(_:_:file:line:flags:) ()
#9 0x00000001000016fc in ProtocolA.dontCrash() at /Users/rmayoff/TestProjects/Project/Project/AppDelegate.swift:11
#10 0x0000000100001868 in protocol witness for ProtocolA.dontCrash() in conformance MyClass ()
#11 0x000000010000171e in ProtocolA.tryCrash() at /Users/rmayoff/TestProjects/Project/Project/AppDelegate.swift:15
#12 0x00000001030f1987 in ProjectTests.testExample() at /Users/rmayoff/TestProjects/Project/ProjectTests/ProjectTests.swift:12
#13 0x00000001030f19c4 in @objc ProjectTests.testExample() ()
Frame #10 is the call from tryCrash
to the function in the protocol witness table. Frame #9 is the call from the protocol witness table function to the actual implementation of dontCrash
.
Swift emits the protocol witness table in the module that declares the conformance. So, in your case, the witness table is part of the Project
module.
Your override of dontCrash
in your test bundle cannot change the contents of the witness table. It's too late for that. The witness table was fully defined when Swift generated the Project
module.
Here's why it has to be this way:
Suppose I'm the author of the Project
module and you're just a user of it. When I wrote the Project
module, I knew calling MyClass().dontCrash()
would call fatalError
, and I relied on this behavior. In many places inside Project
, I called MyClass().dontCrash()
specifically because I knew it would call fatalError
. You, as a user of Project
, don't know how much Project
depends on that behavior.
Now you use the Project
module in your app, but you retroactively change MyClass().dontCrash()
to not call fatalError
. Now all those places where Project
calls MyClass().dontCrash()
don't behave in the way that I expected when I wrote the Project
module. You have broken the Project
module, even though you didn't change the source code of the Project
module or any of the modules that Project
imports.
It's critical to the correct operation of the Project
module that this not happen. So the only way to change what MyClass().dontCrash()
means (when called from inside the Project
module) is to change the source code of the Project
module itself (or change the source code of something that Project
imports).
why multiple optionals(wrap nil) compare with operator == return false?
There are four kinds of values that a Int???
can have:
.none
(nil
).some(.none)
(a non nilInt???
wrapping a nilInt??
).some(.some(.none))
(a non nilInt???
wrapping a non nilInt??
wrapping a nilInt?
).some(.some(.some(n)))
wheren
is anInt
(anInt
wrapped by 3 layers ofOptional
s)
Similarly, there are three kinds of values that an Int??
can have
.none
.some(.none)
.some(.some(n))
wheren
is anInt
When you write nil
, it always means .none
of whatever type that context needs, so both opt1
and opt2
are .none
here.
What happens when you pass them to the ==
operator? Well, After some overload resolution/type inference, the compiler finds that ==
takes a two Int???
parameters, but you have passed an Int??
as the second argument. Luckily, there exists a conversion from any value t
of type T
to type T?
- .some(t)
.
So after being passed into the ==
, opt2
changes from .none
to .some(.none)
, as you can see from this code snippet:
func test(lhs: Int???, rhs: Int???) {
if case .none = lhs, case .some(.none) = rhs {
print("lhs is .none and rhs is .some(.none)")
}
}
test(lhs: opt1, rhs: opt2) // prints
Hence they are "not equal".
The debugger seems to be showing both .none
and .some(.none)
as "nil", possibly because both of their debugDescription
/description
is "nil".
If you don't care about the multiple layers of optionals, you can just unwrap them to a single layer by doing as? Int
, then compare:
print((opt1 as? Int) == (opt2 as? Int)) // true
Related Topics
Skaction Completion Handlers; Usage in Swift
Realitykit - How to Set a Modelentity's Transparency
How to Speed Up Updating Relationship Among Tables, After One or Both Tables Are Already Saved
Swift: When Should I Use "Var" Instead of "Let"
Swift Mutable Set: Duplicate Element Found
How to Loop Through an Array from the Second Element in Elegant Way Using Swift
Get Lat and Long from Tapped Overlay in Google Maps
Default Optional Parameter in Swift Function
How to Display Image from a Url in Swiftui
How to Compare Just the Time of a Date in Swift
Mutating Function Inside Class
How to Draw a Cosine or Sine Curve in Swift
Session.Datataskwithurl Completionhandler Never Called
Gcd with Static Functions of a Struct
Swift Extension on Generic Struct Based on Properties of Type T
Having Tab Bar and Navigationbar in the Same View in Swiftui