Swift Calling Static Methods: Type(Of: Self) VS Explicit Class Name

Swift calling static methods: type(of: self) vs explicit class name

There are two main differences.

1. The value of self inside the static method

The metatype that you call the static method on is available to you in the method as self (it's simply passed as an implicit parameter). Therefore if you call doIt() on type(of: self), self will be the dynamic metatype of the instance. If you call it on Foo, self will be Foo.self.

class Foo {
static func doIt() {
print("hey I'm of type \(self)")
}

func callDoItOnDynamicType() {
type(of: self).doIt() // call on the dynamic metatype of the instance.
}

func classDoItOnFoo() {
Foo.doIt() // call on the metatype Foo.self.
}
}

class Bar : Foo {}

let f: Foo = Bar()

f.callDoItOnDynamicType() // hey I'm of type Bar
f.classDoItOnFoo() // hey I'm of type Foo

This difference can be really important for factory methods, as it determines the type of instance you create.

class Foo {
required init() {}

static func create() -> Self {
return self.init()
}

func createDynamic() -> Foo {
return type(of: self).create()
}

func createFoo() -> Foo {
return Foo.create()
}
}

class Bar : Foo {}

let f: Foo = Bar()

print(f.createDynamic()) // Bar
print(f.createFoo()) // Foo

2. The dispatching of the static method

(Martin has already covered this, but I thought I would add it for the sake of completion.)

For class methods that are overridden in subclasses, the value of the metatype that you call the method on determines which implementation to call.

If called on a metatype that is known at compile time (e.g Foo.doIt()), Swift is able to statically dispatch the call. However, if you call the method on a metatype that isn't known until runtime (e.g type(of: self)), the method call will be dynamically dispatched to the correct implementation for the metatype value.

class Foo {
class func doIt() {
print("Foo's doIt")
}

func callDoItOnDynamicType() {
type(of: self).doIt() // the call to doIt() will be dynamically dispatched.
}

func classDoItOnFoo() {
Foo.doIt() // will be statically dispatched.
}
}

class Bar : Foo {
override class func doIt() {
print("Bar's doIt")
}
}

let f: Foo = Bar()

f.callDoItOnDynamicType() // Bar's doIt
f.classDoItOnFoo() // Foo's doIt

Refer to 'self' in a static context

Lets look at a simpler (working) example keeping your core issue the same:

class ClassName {
static var bundle = Bundle(for: ClassName.self)

static func getBundle() -> Bundle {
return Bundle(for: self)
}
}

Firstly, lets note that Bundle(for: AnyClass) takes an object type.



1. Regarding Variables

Variables at top-level, access self as ClassName which is an instance type, whether it is declared as let/var/lazy/computed, static or not.

So:

static var bundle = Bundle(for: self)

is same as:

static var bundle = Bundle(for: ClassName())

Both are invalid and generate the following error:

Cannot convert value of type 'ClassName' to expected argument type 'AnyClass' (aka 'AnyObject.Type')

For sure, this is because we're passing an instance type instead of the expected Object type.

Solution:

static var bundle = Bundle(for: ClassName.self)


2. Regarding static functions

As for a static function, this is a bit different.

The metatype that you call the static method on is available to you in the method as self (it's simply passed as an implicit parameter).

Ref: https://stackoverflow.com/a/42260880/2857130

In my example, we have:

static func getBundle() -> Bundle {
return Bundle(for: self)
}

When you call ClassName.getBundle(), ClassName.Type is implicitly passed to the function.

Now within the static function, self is of type ClassName.Type which is an Object type and can be applied directly in Bundle(for:), or similar functions that accept an Object type as it's parameter.

So, static functions access self as ClassName.Type which is same as ClassName.self, just not apparent as it's passed implicitly.

You can confirm this behavior of self in a static function, and furthermore even observe how self behaves in a normal function in the following example:

class ClassName {
static func check() {
print("static function check")
print(type(of: self)) //ClassName.Type
//same as
print(type(of: ClassName.self)) //ClassName.Type

//test
print(type(of: self) == type(of: ClassName.self)) //true
}

func check() {
print("normal function check")
print(type(of: self)) //ClassName

//test
print(type(of: self) == type(of: ClassName.self)) //false
}
}

ClassName.check()
ClassName().check()

Also shows us that normal functions access self as ClassName which is an instance type, similar to variables.



Summary:

  • Bundle(for:) takes an object type
  • Variables at top-level, access self as ClassName which is an instance type
  • Normal functions access self as ClassName which is an instance type
  • Static functions access self as ClassName.Type which is an Object type, as it's passed implicitly to the function

How to get a method’s defining class’s name?

I don't believe what you're specifically asking for is possible. There's no way I know of to evaluate something in your caller's context implicitly, except the provided #-literals.

That said, if you will change your syntax slightly, you can get the effect you want.

public class Logger {
public let caller: String

public init(for caller: Any) {
self.caller = "\(type(of: caller))"
}

public func info(_ message: String, file: String = #file, line: Int = #line, function: String = #function) {
print("Function \(function) of \(caller) in file \(file) was called.")
}
}

Now, in objects that use the logger, they just need to create their own with a consistent name like log. Make sure your Logger is stateless, so it's ok that they get created on demand.

class MyLoggingThing {
var log: Logger { Logger(for: self) }

func doSomething() {
log.info("Let's do this")
}
}

// Function doSomething() of MyLoggingThing in file MyPlayground.playground was called.

You can make this a little nicer with an extension, and handle static methods:

protocol Logging {}
extension Logging {
static var log: Logger { Logger(for: self) }
var log: Logger { Logger(for: self) }
}

class MyLoggingThing: Logging {
static func doSomethingStatic() {
log.info("Even static")
}
func doSomething() {
log.info("Let's do this")
}
}

Note that static methods will show the type as MyLoggingThing.Type. That's good or bad, depending on what you want. If you don't like the extra .Type, you can add an extra Logger.init like this:

public init(for staticCaller: Any.Type) {
self.caller = "\(staticCaller)"
}

That will cause types to be evaluated as themselves rather than as their metatypes.

If your logger is stateful or has a central configuration, or other situation where lots of loggers might be a problem, you should split apart the stateful "engine" part from this front-end. You can also make log a lazy var or otherwise initialize it in init when self is available.

In my personal Logging module, I also have a global "root" Logger called Log (with a leading capital). That makes it easier for functions that might not want to name themselves (such as top level functions or closures).

Base class static method returns type of subclass in Swift

A possible solution is a protocol extension

protocol Animal {
init()
static func generateMocks() -> [Self]
}

extension Animal {
static func generateMocks() -> [Self] {
var mocks: [Self] = []
// some implementation goes here...
for _ in 0..<10 {
mocks.append( Self() )
}
//
return mocks
}
}

struct Dog: Animal {
// dog things
var isCute = true
}

let myMockDogs = Dog.generateMocks()
print(myMockDogs.first?.isCute) // true

Difference between struct static func vs class static func in swift?

This is kind of a stretch, but due to the reference vs value semantics of class and struct types, respectively, there is subtle difference in in the realization of a case where you want to make use of a type method (static) to mutate a private property of the type, given an instance of the type has been supplied. Again, kind of a stretch, as this focuses on differences in implementation details, and not on a concrete difference between the two.

In the class case, an immutable reference can be supplied to the static method, which in turn can be used to mutate a private instance member of the type. In the case of the struct, the instance of the type naturally needs to be supplied as an inout parameter, as changing the value of an instance member of a value type also means changing the value of the instance itself.

class A {
private(set) var i: Int = 0
static func foo(_ bar: A) {
bar.i = 42
}
}

struct B {
private(set) var i: Int = 0
static func foo(_ bar: inout B) {
bar.i = 42
}
}

let a = A()
var b = B()

A.foo(a)
print(a.i) // 42
B.foo(&b)
print(b.i) // 42

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

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

Implementing protocol static method that takes and returns Self (in swift)

Your * implementation has a few subtle problems. Here's the implementation you mean:

static func *(lhs: Float, rhs: ThingBox<T>) -> Self {
return self.init(thing: lhs * rhs.thing)
}

First, you can't use Self as a parameter type. You have to be explicit. Self means "the actual type" and if you could use that for a subclass, this would violate LSP. For example, say I have types Animal and Dog (with the obvious relationships). Say I wrote the function:

class Animal {
func f(_ a: Self) { ... }
}

with the meaning that Animal.f will take Animal, but Dog.f will only take Dog but will not take a Cat. So you would expect the following to be true:

dog.f(otherDog) // this works
dog.f(cat) // this fails

But that's breaks the rules of substitution. What if I write this:

let animal: Animal = Dog()
animal.f(cat)

That should be legal, because Animal.f can take any Animal, but the implementation of Dog.f cannot take a cat. Type mismatch. Boom. So it's not legal. (This restriction does not exist for return types. I'll leave that as an exercise for the reader. Try to create an example like the above for returning Self.)

The second error was just a syntax mistake. It's not Self(), it's self.init(). In a static method, self is the dynamic type (which is what you want), and Swift requires you to call init explicitly when used this way. That's just syntax, not a deep type issue like the other.


There's no way in Swift to inherit the thing you're talking about. If you want to overload, that's fine, but you have to be explicit about the types:

class OtherBox: ThingBox<Int> {
static func *(lhs: Float, rhs: OtherBox) -> Self {
return self.init(thing: lhs * rhs.thing)
}
}

This does exactly what you want, but it has to be added to each child; it won't inherit automatically with covariance. Swift doesn't have a strong covariance system to express it.

That said, when you start intermixing generics, protocols, and subclassing this way, you're going to run into many, many weird corner cases, both due to the math, and due to current Swift limitations. You should ask carefully if your actual code needs this much parameterization. Most cases I encounter of these kinds of questions are over-designed "in case we need it" and just simplifying your types and making things concrete is everything you need for solving the actual program you want to write. It's not that it wouldn't be nice to build incredibly generic algorithms built on higher-kinded types, but Swift just isn't the language for that today (and possibly never; there are a lot of costs to adding those features).

How to infer type in static generic method with the type of the caller in Swift

I want to tell to the compiler "T is the class who calls the static method"

Assuming you want to apply your get only when T is the class who calls the static method, how is this?

protocol Storable {
//...
}

extension Storable where Self: Decodable {
static func get(by identifier: String, completion: @escaping (Self?) -> Void) {
//...
}
}

struct User: Storable, Decodable {
//...
}

This will be compiled successfully:

    User.get(by: "userId", completion: { user in
print(user)
})

Swift: How to load a Bundle from a static method

You can use ClassName.self.

class SomeClass
static func foo() {
let bundle = Bundle(for: SomeClass.self)

}
}


Related Topics



Leave a reply



Submit