Swift struct type recursion - swift

Why can't structs have recursive value types in Swift?
Is this a temporary limit of the language or is it as intended?
I feel that the ability to declare a binary tree node as a struct with recursive types in it to be the most natural implementation.
struct TreeNode<E>{
var leftNode:TreeNode<E>
var rightNode:TreeNode<E>
var element:E
}

The answer is in your question: structs are value types. If you include a substruct B into a struct A, it means, that one object of type A will have a size sizeof(all_other_fields_of_A) + sizeof(B). So, a value type can not be recursive: it would have infinite size.

Enums in Swift support recursive types using the indirect keyword so you can do something like:
indirect enum Tree<T> {
case Node(left: Tree?, right: Tree?, element: T)
}
Check out this great blog post A persistent tree using indirect enums in Swift

Related

Swift explicit variable declaration with optional

I'm new to Swift and trying to decode one of the Apple examples. Could someone please explain what this line is doing ?
#SceneStorage("selection") private var selectedProjectID: Project.ID?
Project is a struct conforming to Codable and Identifiable
Is selectedProjectID of the same type as Project.ID? ?
In general for some type, T, T? is syntactic sugar for Optional<T>.
Optional<T> is defined as an enum with special compiler support for comparisons and assignments to nil. It looks something like this.
enum Optional<Wrapped>
{
case none
case some(wrapped: Wrapped)
}
So when an optional is nil, it's actually .none
In comments you asked:
Does the Project.Id bit mean selectedProjectID will be of explicit type the same as the Project.ID member in the struct ?
The answer is no. selectedProjectID is an instance property (a variable) whose type is Optional<Project.ID>. Project.ID is a type. It does also have a type, a meta-type (the type of a type), but I don't think that's what you mean to ask. I think you're asking if selectedProjectID is same type as the id property that is defined in Project as part of its conformance to Identifiable. And the answer is no, not exactly.
If someProject is an instance of Project, then someProject.id is of type Project.ID, whereas selectedProjectID is of type Optional<Project.ID>.
There is a lot of compiler support extracting, comparing and assigning between optionals and their wrapped type, but strictly speaking they are different types, just as much as Int and Array<Int> are different types.
On the other hand, assuming someProjectID is not nil, then someProjectID! (ie, force-unwrapped) is the same type as someProject.id. Similarly in
if let pID = someProjectID {
...
}
within the if, pID is also the same type as someProject.id

Is there any way in Swift to define a collection which holds elements with different data types?

In my specific case, I want something like:
var collectionWithDifferentTypes: [ObservableObject] = []
var elementOfTypeAWhichConformsToObservableObject = TypeA()
var elementOfTypeBWhichConformsToObservableObject = TypeB()
collectionWithDifferentTypes.append(elementOfTypeAWhichConformsToObservableObject)
collectionWithDifferentTypes.append(elementOfTypeBWhichConformsToObservableObject)
But letting arrays conform to ObservableObject is not possible. As the docs state, arrays, sets, and dictionaries can only contain elements of the same type. Is there any way in swift to have a collection similar to the one I've described above?
The reason you are getting this error is that ObservableObject specifies an associated type ObjectWillChangePublisher that has to be defined in classes that conform to the protocol. There's an annoying trait of Swift that any protocol that specifies an associated type can't be used as a generic parameter since the runtime needs to know how the associated type is defined in order to effectively use it.
In order to use such a protocol as a generic type, you have to do what the error message specifies and use it as a generic constraint. That means that wherever you are defining the array has to be made into a generic context using ObservableObject as a constraint.
(class field)
class SomeClass<T: ObservableObject> {
var myArray: [T] = []
}
(function variable)
func doAThing<T: ObservableObject>() {
var myArray: [T] = []
}
(See this article for a more in-depth explanation on what this error means.)
Of course, there's always the nuclear option of just defining the array as [Any].
Two ways I can think of. If you subclass TypeB with TypeA then you could use var collectionWithDifferentTypes: [TypeA] = [] or if they both conformed the same protocol. No need for the subclassing. Just use var collectionWithDifferentTypes: [protocolName] = []

Enums and static typing

I have declared an enum in some gdscript code.
Then, I want to declare some variables to be of that type of enum.
Is this possible. I know GDScript allows to declare a static type of a var. MEvery language I have used allows you to treat an enum as a var.
The following code produces the following error for me...
enum XDir {
None,
Left,
Right
}
enum YDir {
None,
Up,
Down
}
var x_dir : XDir
var y_dir : YDir
Parser Error: Identifier 'XDir' is not a valid type (not a script or
class), or could not be found on base 'self'.
This is not possible yet. Enums in GDScript are syntactic sugar for constant dictionaries and are not actual types.
You'll have to use int as the type until enums are made into real types.
Do note that you can still give enums to export like
export(XDir) var x_dir: int
To enforce an enum value at runtime you can do:
assert(XDir.has(x_dir))

What does the Swift 'mutating' keyword mean?

Why must I insert mutating before implementing a method on a struct when adopting protocols?
Why don't I need mutating when I do the same thing in a class?
The mutating keyword is only required if you are changing any state contained within the struct. Since Swift structs are immutable objects, calling a mutating function actually returns a new struct in-place (much like passing an inout parameter to a function). The mutating keyword lets callers know that the method is going to make the value change. The best way to conceptualize this is to think of your struct the same as you would a number: if you perform the operation 4 + 1, 4 doesn’t become 5, you’ve just gotten a new value after performing the operation. Mutating functions operate on the same principle. You cannot call mutating functions on constants (e.g. let someStruct = SomeStruct()), because that would be the same thing as trying to assign the constant to a new value. Because of this behavior mutating functions can only be performed on variables (e.g var someStruct = SomeStruct()).
Being the value type structs are immutable. Meaning other variables can not change the values for instance of structure at any given point.
The mutating word is required for changing the values of self variables inside structure's function ONLY.
For. e.g
struct MyStruct {
var abc: String = "initila value"
func changeValue() {
abc = "some other value". //Compile time error: Cannot assign to property: 'self' is immutable. Mark method 'mutating' to make 'self' mutable.
}
}
Here as we are trying to change value of variable abc inside function declared in struct itself, we get the compile time error.
So here we need to make function mutating to make change value inside structure. Hence the correct code will be:
struct MyStruct {
var abc: String = "initila value"
mutating func changeValue() {
abc = "some other value"
}
}
EDIT:
When declaring protocol, it can be declared commonly for reference and value types, so these kind of protocols itself declares the functions as mutating so that it can be adopted by both classes and structures.
Since being reference type the mutating keyword is removed (or we can say not required) in the classes, but for structures being value types the mutating keyword is required.
From the docs:
If you define a protocol instance method requirement that is intended to mutate instances of any type that adopts the protocol, mark the method with the mutating keyword as part of the protocol’s definition. This enables structures and enumerations to adopt the protocol and satisfy that method requirement.
If you mark a protocol instance method requirement as mutating, you don’t need to write the mutating keyword when writing an implementation of that method for a class. The mutating keyword is only used by structures and enumerations.
Reference
I hope this will clear your doubt.
Classes are reference types. What that means is that a variable typed to a class:
let someObject = SomeClass()
just contains a pointer to that class's memory, under the hood. The class's contents and data can change without changing the original pointer, because it's just a reference.
Structs, on the other hand, are value types. If you have a variable containing something that is a struct type:
var someStruct = SomeStruct()
the variable itself is actually containing all the struct's data. Changing the struct's internal state actually involves reassigning the variable—so in the example above, something like someStruct.foo = "bar" would actually cause the someStruct variable to be reassigned, as if you'd typed:
someStruct = SomeStruct(foo: "bar", otherStuff: someStruct.otherStuff) // or something of this nature
This is also why you have to declare structs using var if you plan to change anything in them, whereas this isn't so with classes.
As for protocols, they can represent either struct or class types, so if you are dealing with a protocol existential, you can't do operations on it that assume it's a class (unless the protocol is constrained as such).
The Mutating Keyword : In order to modify the properties of a value type, you have to use the mutating keyword in the instance method. With this keyword, your method can then have the ability to mutate the values of the properties and write it back to the original structure when the method implementation ends.
Class is not support In swift, classes are reference type whereas structures and enumerations are value types. The properties of value types cannot be modified within its instance methods by default. In order to modify the properties of a value type, you have to use the mutating keyword in the instance method.

Swift: Recursive use of generic struct

I'm playing around with linked lists in Swift and I'm using:
struct Node<Element> {
var next: Node<Element>?
}
it yields this error:
Recursive value type "Node<Element>" is not allowed.
I tried using indirect on both the struct declaration and the property but neither worked. How do you implement this type of structure?
When you write var next: Node<Element>?, Swift tries to put this storage inline, but since it's recursive, that results in an infinite-size struct.
indirect only applies to enums, so you could do something like this:
enum Node<Element> {
indirect case Node(Element, next: Node?)
}
Node.Node(42, next: nil)
Or you can use a regular reference type, a.k.a. class:
class Node<Element> {
var next: Node<Element>?
}
It seems that is not possible to create a recursive use of struct, but you can do by using enum, associated values and the indirect attribute.
A recursive enumeration is an enumeration that has another instance of
the enumeration as the associated value for one or more of the
enumeration cases. You indicate that an enumeration case is recursive
by writing indirect before it, which tells the compiler to insert the
necessary layer of indirection.
indirect enum Tree<Element: Comparable> {
case Empty
case Node(Tree<Element>,Element,Tree<Element>)
}
Code taken from AirspeedVelocity.
It's not possible with Structs. It's also doesn't seem wise to do linked list with value types. Unless you feel like doing
head.next.next.next.next.next = head.next.next.next.next.next.next
to delete the seventh node, you're going to want to be able to set
let next = head.next