ddddxxx
December 5, 2019, 6:29am
#1
The following code is perfectly valid. Before you run it, take a guess, WHAT IS IT?
class A: NSObject {
let x = withExtendedLifetime(self) { whatIsIt in
return whatIsIt
}
}
print(A().x)
Hint: A must inherit NSObject
, or you get build time error (as expected).
What the hell is it
The self
above is not really "self". It refers to instance method NSObjectProtocol.self .
Sorry I trolled you. This thread is not about "partially initialized self" at all.
Should we ban it? It's reasonable in a sense, but extremely misleading. Someone could accidentally write something like this:
class MyViewController: UIViewController {
let button: UIButton = {
let button = UIButton()
button.addTarget(self, action: #selector(...), for: .touchUpInside)
return button
}()
}
Xcode also render it as a keyword.
beccadax
(Becca Royal-Gordon)
December 5, 2019, 9:08am
#2
Fascinating. -dump-ast shows it clear as day:
(dot_syntax_base_ignored type='(A) -> () -> A' location=./example.swift:3:34 range=[./example.swift:3:34 - line:3:34]
(type_expr implicit type='A.Type' location=./example.swift:3:34 range=[./example.swift:3:34 - line:3:34] typerepr='A')
(declref_expr type='(A) -> () -> A' location=./example.swift:3:34 range=[./example.swift:3:34 - line:3:34] decl=Foundation.(file).NSObject.self() function_ref=unapplied))
I would expect self
here to refer to the metatype instance (the object representing type A
); I’m not sure why it doesn’t.
ddddxxx
December 5, 2019, 10:06am
#3
If only x is static:
class A {
static var x: A.Type {
return self
}
}
I'd expect self
to refer to self instance, like this:
class A: NSObject {
lazy var x = withExtendedLifetime(self) { whatIsIt in
// We get fully initialized self here because x is lazy.
return whatIsIt
}
}
let a = A()
a === a.x // true
Curious indeed. We don’t even need any trickery with closures to surface the behavior; it’s just tied to the meaning of self
in that context:
class A: NSObject {
let x = self
}
A().x // (__lldb_expr_3.A) -> () -> __lldb_expr_3.A
1 Like
dannliu
(Danny Liu)
December 5, 2019, 2:12pm
#5
ddddxxx:
Should we ban it? It's reasonable in a sense, but extremely misleading. Someone could accidentally write something like this:
class MyViewController: UIViewController {
let button: UIButton = {
let button = UIButton()
button.addTarget(self, action: #selector(...), for: .touchUpInside)
return button
}()
}
Reference from Swift Programming guide:
If you use a closure to initialize a property, remember that the rest of the instance has not yet been initialized at the point that the closure is executed. This means that you cannot access any other property values from within your closure, even if those properties have default values. You also cannot use the implicit self property, or call any of the instance’s methods.
You can not use self in the initialization.
shaneqi
(Shane Qi)
December 5, 2019, 3:23pm
#7
But the fact is that we can, and it compiles. That's the point of this post.
1 Like
Is that maybe this?
public protocol NSObjectProtocol {
func `self`() -> Self
}
self
is basically an unapplied reference to () -> Self
in our case.
1 Like