Why can't I call protocol method from class method? - swift

The code below compiles just fine if I make the tester() method an instance method. How can I make it work while keeping it a class method?
protocol Numbers {
}
extension Numbers {
func amountFromText(text: String) -> Int {
return 0
}
}
class CommonDB: Numbers {
class func tester() {
let text = ""
let amount = amountFromText(text)
}
}

The way you have your function defined in your protocol means that it will be an instance function, that is, you need an instance of the class or structure in order to call that function. When you are in a class function, you don't have an instance of that class.
If you want to call amountFromText() from a class function, then declare it to be static. That way, it won't need an instance of the class or structure to be called:
extension Numbers {
static func amountFromText(text: String) -> Int {
return 0
}
}

Related

How to prevent subclasses from inheriting super class's static method in Swift?

In the case of the following code, it is possible to call both Base.f() and Sub.f() because the sub class inherits its parent class's static method.
But I want to use only Base.f(), and don't want to use Sub.f() in my code.
Base.f() and Sub.f() do the same thing in the following case.
If both Base.f() and Sub.f() are used in my code, it just makes my code complex and difficult to find the places where f() are used.
Is it possible to tell swift to generate a compile error if Sub.f() is used?
Or, is there an alternative way to do it other than to define f() as a global function?
class Base {
static func f() {
print("hello world")
}
}
class Sub: Base {
}
Base.f()
// hello world
Sub.f()
// hello world
EDIT
More meaningful example than printing "hello world".
In the following case, I don't want to call it with Sub1.findSubclassByType("sub2") because Sub1 finding a subclass sounds funny.
So, I want to always call it with Base.findSubclassByType("sub2").
Maybe, defining findSubclassByType(type) in Base is a wrong design of a class? (Although, it is convenient that Xcode suggests findSubclassByType(type) when I type Base..)
What should I do?
class Base {
static func findSubclassByType(_ type: String) -> Base {
// find and return a subclass
if type == "sub1" {
return Sub1()
} else if type == "sub2" {
return Sub2()
} else {
fatalError("no sub class")
}
}
}
class Sub1: Base {
}
class Sub2: Base {
}
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 of static (=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.
What you're precisely asking is impossible, because the only public/internal members that are not inherited by subclasses are initializers—and only when a subclass defines its own designated initializer, without implementations of all of its superclass's initializers.
So, to abuse that capability, you can use failable initializers when you don't need a return value…
class Base {
init() { }
#discardableResult init?(printingHelloWorld: Void) {
print("hello world")
return nil
}
}
class Sub: Base {
init(_: Any) {
super.init()
}
}
Base(printingHelloWorld: ())
…or throwing initializers, when you do.
class Base {
init() { }
struct Error: Swift.Error {
let payload: String
}
init(returningAPayload: #autoclosure () -> Never) throws {
throw Error(payload: "💰")
}
}
class Sub: Base {
init(_: Any) {
super.init()
}
}
extension Never {
init() { fatalError() }
}
do {
try Base(returningAPayload: .init())
} catch {
(error as! Base.Error).payload
}
I advise against any of this, and subclassing in general.

Type constraints on contained generic type parameter

I expected the following code to print "extension" in both cases. But the type constraint on the extension does not take effect on the contained generic type. I see the same behavior when constraining on protocols too.
class Generic1<T1> {
func doSomething() {
print("base")
}
}
extension Generic1 where T1 == String {
func doSomething() {
print("extension")
}
}
class Generic2<T2> {
private let generic1 = Generic1<T2>()
func doSomething() {
generic1.doSomething()
}
}
Generic1<String>().doSomething() // prints extension
Generic2<String>().doSomething() // prints base
The only workaround I currently have is to constrain the outer generic as well like so:
extension Generic2 where T2 == String {
func doSomething() {
generic1.doSomething()
}
}
Why does this happen? Are there better solutions?
Edit: Just for completeness, the workaround that suited my case was the following:
class Generic1<T1> {
func doSomething() {
print("base")
}
}
class StringGeneric1: Generic1<String> {
override func doSomething() {
print("extension")
}
}
class Generic2<T2> {
private let generic1: Generic1<T2>
init (_ generic1: Generic1<T2>) {
self.generic1 = generic1
}
func doSomething() {
generic1.doSomething()
}
}
Generic1<String>().doSomething() // prints "base"
Generic2<String>(StringGeneric1()).doSomething() // prints "extension"
The problem is that methods defined in extensions are statically dispatched. So when you have:
class Generic2<T2> {
private let generic1 = Generic1<T2>()
func doSomething() {
generic1.doSomething()
}
}
The compiler cannot know here whether T2 is going to be a String or not, so it generates a call to the method in the base class. When you explicitly specify that T2 is String, then with that information, the compiler can generate a call to the extension's method here. Otherwise, though, the type of T2 isn't known until runtime, so you can't reach the extension method via static dispatch.
This may be solved when conditional conformances are added with Swift 4.2

Swift var type for class

I have the next example where I have a problem to initialize the variable tmpClass, I tried Any, AnyObject, AnyClass ... but without success. I need to change and call the class dynamically from one variable
class One{
func doSomething()->Int{ return 100 }
}
class Two{
func doSomething()->Int{ return 200 }
}
class begin{
var tmpClass = ???
var type = "One"
switch (type){
case "One":
tmpClass = One()
case "Two":
tmpClass = Two()
}
println(tmpClass.doSomething())
}
the question is what type need to be tmpClass or some method to do that ?
You can do it in two different ways, see which fits you better:
Protocols
Create a protocol for doSomething
protocol DoSomethingProtocol {
func doSomething()->Int
}
Make your classes conform to it
class One : DoSomethingProtocol {
func doSomething()->Int{ return 100 }
}
class Two : DoSomethingProtocol{
func doSomething()->Int{ return 200 }
}
Set your tempClass variable to be of a protocol compliant class
var tmpClass: DoSomethingProtocol?
Inheritance
Create a base class with the doSomething method
class DoSomethingBaseClass {
func doSomething()->Int{ return 0 }
}
Override doSomething in your classes
class One : DoSomethingBaseClass {
override func doSomething()->Int{ return 100 }
}
class Two : DoSomethingBaseClass{
override func doSomething()->Int{ return 200 }
}
Set your tempClass variable to be of the super class (polymorphism!)
var tmpClass: DoSomethingBaseClass?
General tips
In Swift switches must be exhaustive (all possible options must have a case), to fix this in your example you can simply add
default:
tmpClass = nil
Do not forget to unwrap your optional. For safety you can use the if let syntax for optional binding:
if let tmpUnwrappedClass = tmpClass {
println(tmpUnwrappedClass.doSomething())
}
You could just use the ! unwrap operator as in println(tmpClass!.doSomething()) but this will fail when tmpClass is nil.
Your begin class has two properties and no initializers. Classes with properties must have a designated initializer to set them, that's why I removed the whole class.
Both versions are tested and working in the latest Swift using Playground.

Swift cannot assign to self in a class init method

I have a class called Letter
class Letter
{
init() {}
}
And I have an extension for this class:
extension Letter
{
convenience init(file_path:String) {
self = Letter.loadFromFile(file_path)
}
class func loadFromFile(file_path:String)->Letter {...}
}
I need to create and init with path to file and when i call Letter(file_path) I need a new object that returned by a func loadFromFile. How to assign in an init method or to return a new object?
It gives the error:
Cannot assign to value: 'self' is immutable
Class functions that return instances of that class seems to be an anti-pattern in Swift. You'll notice that the "with" Objective-C class methods like [NSString stringWithString:#"some other string"] made the transition as "with"-less convenience initializers: NSString(string: "some other string").
Furthermore, you'll need to delegate to a designated initializer from within a convenience initializer.
Also, since you're 1) defining the original class and 2) don't need the convenience initializer scoped differently than the designated initializer, I don't see any reason to place it in an extension.
Putting those together:
class Letter {
init() { … }
convenience init(filePath: String) {
self.init()
loadFromFile(filePath)
}
func loadFromFile(filePath: String) { … }
}
let letter1 = Letter()
letter1.loadFromFile("path1")
let letter2 = Letter(filePath: "path2")
In summary, the analogy for assigning to self in Swift is calling an initializer.
Let me know if this works for you!
Convenience initializer must delegate up to designated initializer
It says that convenience init(file_path:String) should call other initialiser
convenience init(file_path:String) {
self.init()
//here can set other properties
}
Convenience initialiser usually provide some default parameters
Convenience initialiser are designed to make creation of class instance less complicated. It means that you don't need to pass all arguments to constructor. In your example the class should look like this
Designated initializer takess all possible arguments.
Convenience provide default value
Code example
// Create instance of a Letter
Letter()
Letter(file_path: "path.txt")
Letter(file_path: "path.txt", option: 0, other: 0)
//Class Implementation
class Letter
{
init(file_path: String , option: Int, other: Int) {
// Instansiate class
}
}
extension Letter {
convenience init() {
self.init(file_path:"a")
}
convenience init(file_path:String) {
self.init(file_path: file_path , option: 0, other: 0)
}
class func loadFromFile(file_path:String) -> Letter {
return Letter()
}
}
Now you can create instance of Letter this way -
You can't assign to self. What about something like this:
class Letter {
}
extension Letter {
convenience init(filePath: String) {
self.init()
// code to load a Letter from a file goes here.
}
class func loadFromFile(filePath: String) -> Letter {
return Letter(filePath: filePath)
}
}

What is the difference between static func and class func in Swift?

I can see these definitions in the Swift library:
extension Bool : BooleanLiteralConvertible {
static func convertFromBooleanLiteral(value: Bool) -> Bool
}
protocol BooleanLiteralConvertible {
typealias BooleanLiteralType
class func convertFromBooleanLiteral(value: BooleanLiteralType) -> Self
}
What's the difference between a member function defined as static func and another one defined as class func? Is it simply that static is for static functions of structs and enums, and class for classes and protocols? Are there any other differences that one should know about? What is the rationale for having this distinction in the syntax itself?
To be clearer, I make an example here,
class ClassA {
class func func1() -> String {
return "func1"
}
static func func2() -> String {
return "func2"
}
}
/* same as above
final class func func2() -> String {
return "func2"
}
*/
static func is same as final class func
Because it is final, we can not override it in subclass as below:
class ClassB : ClassA {
override class func func1() -> String {
return "func1 in ClassB"
}
// ERROR: Class method overrides a 'final` class method
override static func func2() -> String {
return "func2 in ClassB"
}
}
Is it simply that static is for static functions of structs and enums, and class for classes and protocols?
That's the main difference. Some other differences are that class functions are dynamically dispatched and can be overridden by subclasses.
Protocols use the class keyword, but it doesn't exclude structs from implementing the protocol, they just use static instead. Class was chosen for protocols so there wouldn't have to be a third keyword to represent static or class.
From Chris Lattner on this topic:
We considered unifying the syntax (e.g. using "type" as the keyword), but that doesn't actually simply things. The keywords "class" and "static" are good for familiarity and are quite descriptive (once you understand how + methods work), and open the door for potentially adding truly static methods to classes. The primary weirdness of this model is that protocols have to pick a keyword (and we chose "class"), but on balance it is the right tradeoff.
And here's a snippet that shows some of the override behavior of class functions:
class MyClass {
class func myFunc() {
println("myClass")
}
}
class MyOtherClass: MyClass {
override class func myFunc() {
println("myOtherClass")
}
}
var x: MyClass = MyOtherClass()
x.dynamicType.myFunc() //myOtherClass
x = MyClass()
x.dynamicType.myFunc() //myClass
I did some experiments in playground and got some conclusions.
TL;DR
As you can see, in the case of class, the use of class func or static func is just a question of habit.
Playground example with explanation:
class Dog {
final func identity() -> String {
return "Once a woofer, forever a woofer!"
}
class func talk() -> String {
return "Woof woof!"
}
static func eat() -> String {
return "Miam miam"
}
func sleep() -> String {
return "Zzz"
}
}
class Bulldog: Dog {
// Can not override a final function
// override final func identity() -> String {
// return "I'm once a dog but now I'm a cat"
// }
// Can not override a "class func", but redeclare is ok
func talk() -> String {
return "I'm a bulldog, and I don't woof."
}
// Same as "class func"
func eat() -> String {
return "I'm a bulldog, and I don't eat."
}
// Normal function can be overridden
override func sleep() -> String {
return "I'm a bulldog, and I don't sleep."
}
}
let dog = Dog()
let bullDog = Bulldog()
// FINAL FUNC
//print(Dog.identity()) // compile error
print(dog.identity()) // print "Once a woofer, forever a woofer!"
//print(Bulldog.identity()) // compile error
print(bullDog.identity()) // print "Once a woofer, forever a woofer!"
// => "final func" is just a "normal" one but prevented to be overridden nor redeclared by subclasses.
// CLASS FUNC
print(Dog.talk()) // print "Woof woof!", called directly from class
//print(dog.talk()) // compile error cause "class func" is meant to be called directly from class, not an instance.
print(Bulldog.talk()) // print "Woof woof!" cause it's called from Bulldog class, not bullDog instance.
print(bullDog.talk()) // print "I'm a bulldog, and I don't woof." cause talk() is redeclared and it's called from bullDig instance
// => "class func" is like a "static" one, must be called directly from class or subclassed, can be redeclared but NOT meant to be overridden.
// STATIC FUNC
print(Dog.eat()) // print "Miam miam"
//print(dog.eat()) // compile error cause "static func" is type method
print(Bulldog.eat()) // print "Miam miam"
print(bullDog.eat()) // print "I'm a bulldog, and I don't eat."
// NORMAL FUNC
//print(Dog.sleep()) // compile error
print(dog.sleep()) // print "Zzz"
//print(Bulldog.sleep()) // compile error
print(bullDog.sleep()) // print "I'm a bulldog, and I don't sleep."
To declare a type variable property, mark the declaration with the static declaration modifier. Classes may mark type computed properties with the class declaration modifier instead to allow subclasses to override the superclass’s implementation. Type properties are discussed in Type Properties.
NOTE
In a class declaration, the keyword static has the same effect as marking the declaration with both the class and final declaration modifiers.
Source: The Swift Programming Language - Type Variable Properties
Both the static and class keywords allow us to attach methods to a class rather than to instances of a class. For example, you might create a Student class with properties such as name and age, then create a static method numberOfStudents that is owned by the Student class itself rather than individual instances.
Where static and class differ is how they support inheritance. When you make a static method it becomes owned by the class and can't be changed by subclasses, whereas when you use class it may be overridden if needed.
Here is an Example code:
class Vehicle {
static func getCurrentSpeed() -> Int {
return 0
}
class func getCurrentNumberOfPassengers() -> Int {
return 0
}
}
class Bicycle: Vehicle {
//This is not allowed
//Compiler error: "Cannot override static method"
//static override func getCurrentSpeed() -> Int {
//return 15
//}
class override func getCurrentNumberOfPassengers() -> Int {
return 1
}
}
This example will clear every aspect!
import UIKit
class Parent {
final func finalFunc() -> String { // Final Function, cannot be redeclared.
return "Parent Final Function."
}
static func staticFunc() -> String { // Static Function, can be redeclared.
return "Parent Static Function."
}
func staticFunc() -> String { // Above function redeclared as Normal function.
return "Parent Static Function, redeclared with same name but as non-static(normal) function."
}
class func classFunc() -> String { // Class Function, can be redeclared.
return "Parent Class Function."
}
func classFunc() -> String { // Above function redeclared as Normal function.
return "Parent Class Function, redeclared with same name but as non-class(normal) function."
}
func normalFunc() -> String { // Normal function, obviously cannot be redeclared.
return "Parent Normal Function."
}
}
class Child:Parent {
// Final functions cannot be overridden.
override func staticFunc() -> String { // This override form is of the redeclared version i.e: "func staticFunc()" so just like any other function of normal type, it can be overridden.
return "Child Static Function redeclared and overridden, can simply be called Child Normal Function."
}
override class func classFunc() -> String { // Class function, can be overidden.
return "Child Class Function."
}
override func classFunc() -> String { // This override form is of the redeclared version i.e: "func classFunc()" so just like any other function of normal type, it can be overridden.
return "Child Class Function, redeclared and overridden, can simply be called Child Normal Function."
}
override func normalFunc() -> String { // Normal function, can be overridden.
return "Child Normal Function."
}
}
let parent = Parent()
let child = Child()
// Final
print("1. " + parent.finalFunc()) // 1. Can be called by object.
print("2. " + child.finalFunc()) // 2. Can be called by object, parent(final) function will be called.
// Parent.finalFunc() // Cannot be called by class name directly.
// Child.finalFunc() // Cannot be called by class name directly.
// Static
print("3. " + parent.staticFunc()) // 3. Cannot be called by object, this is redeclared version (i.e: a normal function).
print("4. " + child.staticFunc()) // 4. Cannot be called by object, this is override form redeclared version (normal function).
print("5. " + Parent.staticFunc()) // 5. Can be called by class name directly.
print("6. " + Child.staticFunc()) // 6. Can be called by class name direcly, parent(static) function will be called.
// Class
print("7. " + parent.classFunc()) // 7. Cannot be called by object, this is redeclared version (i.e: a normal function).
print("8. " + child.classFunc()) // 8. Cannot be called by object, this is override form redeclared version (normal function).
print("9. " + Parent.classFunc()) // 9. Can be called by class name directly.
print("10. " + Child.classFunc()) // 10. Can be called by class name direcly, child(class) function will be called.
// Normal
print("11. " + parent.normalFunc()) // 11. Can be called by object.
print("12. " + child.normalFunc()) // 12. Can be called by object, child(normal) function will be called.
// Parent.normalFunc() // Cannot be called by class name directly.
// Child.normalFunc() // Cannot be called by class name directly.
/*
Notes:
___________________________________________________________________________
|Types------Redeclare------Override------Call by object------Call by Class|
|Final----------0--------------0---------------1------------------0-------|
|Static---------1--------------0---------------0------------------1-------|
|Class----------1--------------1---------------0------------------1-------|
|Normal---------0--------------1---------------1------------------0-------|
---------------------------------------------------------------------------
Final vs Normal function: Both are same but normal methods can be overridden.
Static vs Class function: Both are same but class methods can be overridden.
*/
Output:
According to the Swift 2.2 Book published by apple:
“You indicate type methods by writing the static keyword before the method’s func keyword. Classes may also use the class keyword to allow subclasses to override the superclass’s implementation of that method.”
From Swift2.0, Apple says:
"Always prefix type property requirements with the static keyword when you define them in a protocol. This rule pertains even though type property requirements can be prefixed with the class or static keyword when implemented by a class:"
This is called type methods, and are called with dot syntax, like instance methods. However, you call type methods on the type, not on an instance of that type. Here’s how you call a type method on a class called SomeClass: