Recursive type definitions in Swift - swift

I have encountered what would seem like an extremely simple issue to solve, and I think I may be missing something.
The program crashes when attempting to create a recursive variable (?) with the typed to a class while being a member of the said class. For example:
class A {
var x: A
init() {
x = A()
}
}
Checking the crash log suggests a recursion of sorts, with init() being called infinitely.
Is there a proper method/syntax to solve this sort of problem, given that I need the variable x to be typed to class A, and the initializer must initialize variable x to class A?

It's obvious that at some step you should left property x uninitialized. So, thats better to declare it as Optional, and initialize it after instance was created:
class A {
var x: A?
}
let mainObject = A()
let nestedObject = A()
mainObject.x = nestedObject

Not sure but i think you are looking for this
class A {
var x: A?
init() {
}
anothermethod() {
x = A()
}
}
and you can call this method like
let a = A()
a.anothermethod()

Related

Why does Swift allow assigning a struct property to itself, but not a class property?

Swift has this awesome error that shows up when you try to do something of the form x = x:
class Foo {
var foo = 1
}
var a = Foo()
a.foo = a.foo // error
This helped me avoid typos where the class had two similarly named properties, and I want to assign one to the other, but mistakenly typed the same one twice.
However, in this particular case:
struct Foo {
var foo = 1 {
didSet {
print("Did set")
}
}
mutating func f() {
foo = foo
}
}
var a = Foo()
a.foo = a.foo
It successfully compiles! There isn't even an error on the foo = foo line! If I change Foo to a class, or if I remove the didSet, then the expected error appears. It's just this struct + didSet combination that makes the compiler think "yeah, a.foo = a.foo makes a lot of sense! Let me allow that!"
I found this related post, which is about how to stop getting this error, rather than how to get it.
I also looked on bugs.swift.org, but there were only 3 results, and none of them are related.
I'm using Swift 5.3.2 and Xcode 12.4.
Is there any reason why assigning a struct property to itself is more "OK" than assigning a class property to itself?

Why can't I assign this protocol conforming class to a variable of the protocol type?

I've got a toy example here that I can't find any solutions for online.
protocol Tree {
associatedtype Element
// some nice tree functions
}
class BinaryTree<T> : Tree {
typealias Element = T
}
class RedBlackTree<T> : Tree {
typealias Element = T
}
enum TreeType {
case binaryTree
case redBlackTree
}
// Use a generic `F` because Tree has an associated type and it can no
// longer be referenced directly as a type. This is probably the source
// of the confusion.
class TreeManager<E, F:Tree> where F.Element == E {
let tree: F
init(use type: TreeType){
// Error, cannot assign value of type 'BinaryTree<E>' to type 'F'
switch(type){
case .binaryTree:
tree = BinaryTree<E>()
case .redBlackTree:
tree = RedBlackTree<E>()
}
}
}
I'm not sure what the problem here is or what I should be searching for in order to figure it out. I'm still thinking of protocols as I would interfaces in another language, and I view a BinaryTree as a valid implementation of a Tree, and the only constraint on F is that it must be a Tree. To confuse things even more, I'm not sure why the following snippet compiles given that the one above does not.
func weird<F:Tree>(_ f: F){ }
func test(){
// No error, BinaryTree can be assigned to an F:Tree
weird(BinaryTree<String>())
}
Any pointers or explanations would be greatly appreciated.
I don't understand the context of the situation this would be in. However, I have provided two solutions though:
1:
class Bar<F:Foo> {
let foo: FooClass.F
init(){
foo = FooClass.F()
}
}
2:
class Bar<F:Foo> {
let foo: FooClass
init(){
foo = FooClass()
}
}
What you are currently doing doesn't make logical sense, to whatever you are trying to achieve
I don't know what are you trying for, but of course it's not possible to do that. from your example, you attempt to create Bar class with generic. and that not the appropriate way to create a generic object, because the creation of generic object is to make the object to accept with any type.
Here's some brief explanation of the generic taken from Wikipedia.
On the first paragraph that says, "Generic programming is a style of computer programming in which algorithms are written in terms of types to-be-specified-later that are then instantiated when needed for specific types provided as parameters."
it's very clear about what are the meaning of to-be-specified-later, right :)
Back to your example :
class Bar<F: Foo> {
let foo: F
init() {
// Error, cannot assign value of type 'FooClass' to type 'F'
foo = FooClass()
}
}
From the above code, it is type parameter F which has a constraint to a type Foo. and, you try to create an instance for foo variable with a concrete implementation, that is FooClass. and that's not possible since the foo variable is a F type(which is abstract). of course we can downcast it, like this foo = FooClass() as! F, but then the foo is only limited to FooClass, so why even bother with generic then ?
Hope it help :)
Your approach to this is wrong. In your original example, you would have to specify the type of both the element (E) and the container (BinaryTree or RedBlackTree), in addition to the enum value. That make no sense.
Instead, you should construct the manager to take a tree as the constructor argument, allowing Swift to infer the generic arguments, i.e.
class TreeManager<E, F: Tree> where F.Element == E {
var tree: F
init(with tree: F) {
self.tree = tree
}
}
let manager = TreeManager(with: BinaryTree<String>())
Alternatively, you should look into using opaque return types in Swift 5.1 depending on what the final goal is (the example here is obviously not a real world scenario)
Something like this seems reasonable. The point was to try and have some piece of logic that would determine when the TreeManager uses one type of Tree vs another.
protocol TreePicker {
associatedtype TreeType : Tree
func createTree() -> TreeType
}
struct SomeUseCaseA<T>: TreePicker {
typealias TreeType = RedBlackTree<T>
func createTree() -> TreeType {
return RedBlackTree<T>()
}
}
struct SomeUseCaseB<T>: TreePicker {
typealias TreeType = BinaryTree<T>
func createTree() -> TreeType {
return BinaryTree<T>()
}
}
class TreeManager<T, Picker: TreePicker> where Picker.TreeType == T {
let tree: T
init(use picker: Picker){
tree = picker.createTree()
}
This introduces another protocol that cares about picking the tree implementation and the where clause specifies that the Picker will return a tree of type T.
I think all of this was just the result of not being able to declare the tree of type Tree<T>. Its a bit more verbose but its basically what it would have had to look like with a generic interface instead. I think I also asked the question poorly. I should have just posted the version that didn't compile and asked for a solution instead of going one step further and confusing everyone.
protocol Foo {
associatedtype F
}
class FooClass : Foo {
typealias F = String
}
class Bar<M:Foo> {
let foo: M
init(){
foo = FooClass() as! M
}
}

Accessing subclass members using KeyPath

I was trying to access subclass members using KeyPath when I encountered something strange. Look at these 2 simple classes:
class A {
var a:String {
get {
return "str"
}
}
}
class B: A {
override var a:String {
get {
return "str1"
}
}
var c = 10
}
Now if I have the following code:
var m: A = B()
var k = \B.a
print(m[keyPath: k])
I will get a runtime error. It seems that you cannot access to subclass members using a WriteableKeyPath. But the following code works:
var m: A = B()
var k: AnyKeyPath = \B.a
print(m[keyPath: k]!)
I can use this code to access both \B.a and \B.c. Any idea why it is like this?
Since returned object by using AnyKeyPath is immutable, I will not be able to use it for updating object. I wonder if there is any workaround for updating subclass members using a KeyPath on parent class or not.
Update:
In order to elaborate more, here is another example:
var v: UIView = UILabel()
var k = \UILabel.text
v[keyPath: k] = "test" // Error cannot do this
I think this can be very useful.

Is it safe to pass variable created into function to closure?

Everyone knows standard situation with retain cycle.
class TestClass {
var aBlock: (() -> ())? = nil
let aConstant = 5
init() {
print("init")
aBlock = {
print(self.aConstant)
}
}
deinit {
print("deinit")
}
}
var testClass: TestClass? = TestClass()
testClass = nil
but what about situation like this:
class A {
let b: B
let c: C
init() {
b = B()
c = C()
}
func foo() {
let localC = c
b.bar {
localC.execute()
}
}
}
B, C are classes.
I copied c and passed into b.bar closure as localC. In my opinion this situation does not create retain cycle and there will be no problems with deallocation of A.
But I am not 100% sure and I want to ask some with more experience about this. Someone could explain me what happens with references? Tnx.
The way you set it up should not create any retain cycles.
localC is unnecessary. All that does is create another reference to the underlying instance of c. They are identical. Modifying localC would also modify c. They point to the same object. You would have to explicitly copy() in order for them to point to different objects.
With that in mind, this is a diagram of the references:
As you can see, there is no retain cycle being created.

Swift- variable not initialized before use (but it's not used)

Currently I've got some swift code like this:
class C {
let type: Type;
var num = 0;
init() {
self.type = Type({ (num: Int) -> Void in
self.num = num;
});
}
}
The Swift compiler refuses to permit it, saying that I've referenced self.type before it's initialized, even though that's clearly completely untrue. Furthermore, I can't employ the workaround found in other questions/answers, because the type is not optional, and it's immutable, so it can't be initialized with nil pointlessly first.
How can I make the Swift compiler accept this perfectly valid code?
This has nothing to do with returning from the initializer early. The callback is executed asynchronously- it is stored and then used later.
I also have a few further lets that are initialized after this one. I would have to turn them all into mutable optionals, even though they're not optional and can't be mutated.
This works:
class C {
var type: Type?;
var num = 0;
init() {
self.type = Type({ (num: Int) -> Void in
self.num = num;
});
}
}
I assume you knew that. But you want to know why your version isn't working.
Now for the tricky part: for the line
self.num = num;
to work, the compiler has to pass self to inside the closure. The closure could be and probably is executed inside of the constructor of Type.
This is as if you had written
self.type = Type({ (self: C, num: Int) -> Void in
self.num = num
});
which is syntactically wrong but explains what the compiler has to do to compile your code.
To pass this necessary instance of self to the constructor of Type, self has to be initialized. But self isn't initialized, because you are still in the constructor.
The compiler tells you which part of self is not initialized, when you try to pass self to the constructor of Type.
P.S.
obviously Type knows num in your code.
If you want to use let in C instead of var you could do...
class Type {
let num: Int
init () {
num = 3
}
}
class C {
let type: Type;
var num = 0;
init() {
self.type = Type();
num = type.num
}
}
or even
class C {
let type: Type;
var num: Int {
return type.num
}
init() {
self.type = Type();
}
}
depending on whether you want num to change or not. Both examples compile without error.
First, it's important to explain why this is not perfectly valid code, and that it isn't clear at all that self.type is not used before it is initialized. Consider the following extension of your code:
struct A {
init(_ f: (Int) -> Void) { f(1) }
}
class C {
let type: A
var num = 0 {
didSet { print(type) }
}
init() {
self.type = A({ (num: Int) -> Void in
self.num = num
})
}
}
If you walk through the logic, you'll note that self.type is accessed via print before it has been initialized. Swift can't currently prove that this won't happen, and so doesn't allow it. (A theoretical Swift compiler might prove that it wouldn't happen for some particular cases, but for most non-trivial code it would likely bump into the halting problem. In any case, the current Swift compiler isn't powerful enough to make this proof, and it's a non-trivial proof to make.)
One solution, though somewhat unsatisfying, is to use implicitly unwrapped optionals:
private(set) var type: A! = nil
Except for the declaration, every other part of the code is the same. You don't have to treat it as optional. In practice, this just turns off the "used before initialization" checks for this variable. It also unfortunately makes it settable inside of the current file, but does make it immutable to everyone else.
This is the technique I've most often used, though often I try to rework the system so that it doesn't require this kind of closure (not always possible, but I often rack my brain to try). It's not beautiful, but it is consistent and bounds the ugly.
Another technique that can work in some cases is laziness:
class C {
lazy var type: A = {
A({ (num: Int) -> Void in self.num = num })}()
var num = 0
init() {}
}
Sometimes that works, sometimes it doesn't. In your case it might. When it does work, it's pretty nice because it makes the property truly immutable, rather than just publicly immutable, and of course because it doesn't require !.
Interesting.
It looks like the error goes away if you avoid referencing self inside the closure.
If the callback is synchronous you can change your code as follow:
class C {
let type: Type
var num = 0
init() {
var numTemp = 0 // create a temporary local var
let initialType = Type({ (num: Int) -> () in
numTemp = num // avoid self in the closure
});
self.type = initialType
self.num = numTemp
}
}
Important: this will NOT work if the closure is async.
Tested with Xcode (Playground) 6.4 + Swift 1.2
Hope this helps.
As appzYourLife said, a temporary variable for num will suffice:
class Type{
var y: (Int)->Void
init(y2:((Int)->Void)){
self.y = y2
}
}
class C {
let type: Type
var num: Int = 0
init() {
var num2 = 0
self.type = Type(y2: { (num3: Int) -> () in
num2 = num3
});
self.num = num2
}
}
However, you do not need a temporary variable for type, this error message is misleading.