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
asClassName
which is an instance type - Normal functions access
self
asClassName
which is an instance type - Static functions access
self
asClassName.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
Using Environmentobject in Watchos
Why Are Iboutlets Optionals After Swift 5 Migration
How to Select a Contact with Abpeoplepickernavigationcontroller in Swift
Resetting Zone Allocator with Allocations Still Alive
Converting String to Data in Swift 3.0
Adding Nscoding as an Extension
How to Rearrange Views in Swiftui Zstack by Dragging
How Are the Arkit People Occlusion Samples Being Done
Why Is the ! in Swift Called an 'Implicitly' Rather Than 'Explicitly' Unwrapped Optional
Can You Use String/Character Literals Within Swift String Interpolation
How to Quit Swift Repl Without Using Ctrl-D
How to Apply Shadow to Interior Views in Swiftui
Function Taking a Variable Number of Arguments
Realitykit - Set Text Programmatically of an Entity of Reality Composer
Swift: How Can String.Join() Work Custom Types
How to Convert Copaquepointer in Swift to Some Type (Cgcontext? in Particular)