Swift override static method compile error
In class B
, the method list
is a separate method from list
in class A
. They just share the same name, that's all.
The parameters of the two list
methods are actually different:
// A.list
static func list(completion: (_ result:[A]?) -> Void) {
// B.list
static func list(completion: (_ result:[B]?) -> Void) {
A.list
takes an argument of type (_ result: [A]?) -> Void
while B.list
takes a (_ result: [B]?) -> Void
. The array type in the closure type's parameter list is different!
So you're not overridding anything, you're just overloading.
Note:
static
methods can never be overridden! If you want to override a method, use class
instead of static
.
class A {
class func get(completion: (_ result:A?) -> Void) {
completion (nil)
}
}
class B: A {
override class func get(completion: (_ result:B?) -> Void) {
completion (nil)
}
}
How to prevent subclasses from inheriting super class's static method in Swift?
The comments of my question contains many good answers:
there is no dedicated swift feature to prevent subclasses from inheriting super class static methods.
move static functions to a new (final) class or struct
use
class
instead ofstatic (=final class)
and override the class method and add@available(*, unavailable)
to it.use Lint tools
I think the easiest way is to create a new (final) class for static methods which do not depend on subclasses, though, that sacrifices code completion feature a little.
I hope someday Swift will introduce @noInherit static func
attribute.
EDIT
I found another way to restrict the way to call a static method in runtime:
class Base {
static func f() {
if Self.self != Base.self {
fatalError("don't call from subclass: " + String(describing: Self.self))
}
print("hello world")
}
}
note: The disadvantage of the EDIT is that it is checked only in runtime. The benefit of it is that you need only 3 lines and you don't need to override the static method in all subclasses. But this way should be used only when you have confident that checking in runtime is enough and safe for your app.
Swift: Overriding Self-requirement is allowed, but causes runtime error. Why?
Yes, there seems to be a contradiction. The Self keyword, when used as a return type, apparently means 'self as an instance of Self'. For example, given this protocol
protocol ReturnsReceived {
/// Returns other.
func doReturn(other: Self) -> Self
}
we can't implement it as follows
class Return: ReturnsReceived {
func doReturn(other: Return) -> Self {
return other // Error
}
}
because we get a compiler error ("Cannot convert return expression of type 'Return' to return type 'Self'"), which disappears if we violate doReturn()'s contract and return self instead of other. And we can't write
class Return: ReturnsReceived {
func doReturn(other: Return) -> Return { // Error
return other
}
}
because this is only allowed in a final class, even if Swift supports covariant return types. (The following actually compiles.)
final class Return: ReturnsReceived {
func doReturn(other: Return) -> Return {
return other
}
}
On the other hand, as you pointed out, a subclass of Return can 'override' the Self requirement and merrily honor the contract of ReturnsReceived, as if Self were a simple placeholder for the conforming class' name.
class SubReturn: Return {
override func doReturn(other: Return) -> SubReturn {
// Of course this crashes if other is not a
// SubReturn instance, but let's ignore this
// problem for now.
return other as! SubReturn
}
}
I could be wrong, but I think that:
if Self as a return type really means 'self as an instance of
Self', the compiler should not accept this kind of Self requirement
overriding, because it makes it possible to return instances which
are not self; otherwise,if Self as a return type must be simply a placeholder with no further implications, then in our example the compiler should already allow overriding the Self requirement in the Return class.
That said, and here any choice about the precise semantics of Self is not bound to change things, your code illustrates one of those cases where the compiler can easily be fooled, and the best it can do is generate code to defer checks to run-time. In this case, the checks that should be delegated to the runtime have to do with casting, and in my opinion one interesting aspect revealed by your examples is that at a particular spot Swift seems not to delegate anything, hence the inevitable crash is more dramatic than it ought to be.
Swift is able to check casts at run-time. Let's consider the following code.
let sm = SuperMario()
let ffm = sm as! FireFlowerMario
ffm.throwFireballs()
Here we create a SuperMario and downcast it to FireFlowerMario. These two classes are not unrelated, and we are assuring the compiler (as!) that we know what we are doing, so the compiler leaves it as it is and compiles the second and third lines without a hitch. However, the program fails at run-time, complaining that it
Could not cast value of type
'SomeModule.SuperMario' (0x...) to
'SomeModule.FireFlowerMario' (0x...).
when trying the cast in the second line. This is not wrong or surprising behaviour. Java, for example, would do exactly the same: compile the code, and fail at run-time with a ClassCastException. The important thing is that the application reliably crashes at run-time.
Your code is a more elaborate way to fool the compiler, but it boils down to the same problem: there is a SuperMario instead of a FireFlowerMario. The difference is that in your case we don't get a gentle "could not cast" message but, in a real Xcode project, an abrupt and terrific error when calling throwFireballs().
In the same situation, Java fails (at run-time) with the same error we saw above (a ClassCastException), which means it attempts a cast (to FireFlowerMario) before calling throwFireballs() on the object returned by queryFriend(). The presence of an explicit checkcast instruction in the bytecode easily confirms this.
Swift on the contrary, as far as I can see at the moment, does not try any cast before the call (no casting routine is called in the compiled code), so a horrible, uncaught error is the only possible outcome. If, instead, your code produced a run-time "could not cast" error message, or something as gracious as that, I would be completely satisfied with the behaviour of the language.
Circular warnings about Swift static override being final
Thanks to Martin R above for the link to the issue in the Swift compiler. That issue also has a workaround, that does indeed fix the issue for me.
Fixing this is possible by actually using class instead of static in the override in class Y.
Overriding superclass initializer in Swift
You are not doing anything wrong ;) The override
modifier is required because your RailsData
superclass declares a designated initializer with the exact same signature:
class RailsData {
init() {...}
...
}
as such, the override
modified is made necessary in your subclass. The same thing applies to inherited methods as well. From the The Swift Programming Language book:
When you write a subclass initializer that matches a superclass designated initializer, you are effectively providing an override of that designated initializer. Therefore, you must write the
override
modifier before the subclass’s initializer definition. This is true even if you are overriding an automatically provided default initializer.As with an overridden property, method or subscript, the presence of the override modifier prompts Swift to check that the superclass has a matching designated initializer to be overridden, and validates that the parameters for your overriding initializer have been specified as intended.
Rest assured, you won't be bitten by this later on ;)
Motivating example. To see this initializer overriding in action, try this example:
class SuperClass {
init(x: Int) {
print("3. SuperClass.init(x: \(x))")
}
convenience init() {
print("1. SuperClass.init()")
self.init(x: 123) // Will be overridden by subclass.
}
}
class SubClass: SuperClass {
override init(x: Int) {
print("2. SubClass.init(x: \(x))")
super.init(x: x)
print("4. SubClass.init(x: \(x))")
}
}
// Calls inherited convenience initializer.
let sub = SubClass()
outputs:
- SuperClass.init()
- SubClass.init(x: 123)
- SuperClass.init(x: 123)
- SubClass.init(x: 123)
Abstract classes. By the way, there is no direct, linguistic support for abstract classes in Swift — nor in Objective-C — but at least Cupertino is thinking about it ;) Currently, such a concept is merely a soft convention used by frameworks authors, etc.
overriding static vars in subclasses swift 1.2
The documentation says:
“
static
” methods and properties are now allowed in classes (as an alias for “
class final
”).
So it is final
, which means you cannot override it.
Marking an open method final in subclass
You can do this by making the method public
like this:
open class A { // This class is from the SDK and cannot be modified in anyway.
open func aFunc() {}
}
open class B : A { // This has to be open for others to override.
override final public func aFunc() {}
}
open
keyword is for letting subclasses from different module to override, whereas the public
keyword only gives access to different module and do not allow the overriding. If you want to override this method in only your module and not in other modules you can just make it public without final
.
Related Topics
"Ambiguous Reference to Member Map" When Attempting to Append/Replace Array Element
iOS 16 Swiftui List Background
Tableview.Cellforrowatindexpath(Indexpath) Return Nil
Swift Protocol Extension Implementing Another Protocol with Shared Associated Type
How to Get Reliable Timing for My Audio App
Negative Arrayslice: Index Is Out of Range
Enum for Buttonstyle in Swiftui
How to Refresh The Google Map in My Application Using Swift
Xcode Debugger Displays Incorrect Values for Variables
How to Unwrap Optional<Optional<T>> in Swift 1.2
Can't Get Throws to Work with Function with Completion Handler
Swiftui Scrollview Only Scroll in One Direction
How to Get The Count of a Type Conforming to 'sequence'
Pfobject Unable to Be Cast to Custom Subclass
How Is Commoncrypto Used in Swift3
How to Use Passed Parameters in Swift Setmethodcallhandler - Self.Methodname(Result: Result)
Is There Any Reasonable Way to Access The Contents of a Characterset