Swift: Recursive use of generic struct - swift

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

Related

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] = []

Overcoming Type alias '…' references itself

Background
I have an enum which, simplified, goes like this:
enum Container<T> {
case a(T)
case b(T)
case c
}
I want to be able to instantiate this with a few different types for the generic and use typealias for that:
typealias IntContainer = Container<Int>
typealias FloatContainer = Container<Float>
Problem
So far, this is all fine. However, I also want to create a recursive instance of this:
typealias CyclicContainer = Container<CyclicContainer>
Swift reports this with a compile error:
Type alias 'CyclicContainer' references itself
… This error is still reported when I change the Container declaration to:
indirect enum Container<T>
This is a bit annoying, because this would be wholesome and compiling Swift:
indirect enum CyclicContainer {
case a(CyclicContainer)
case b(CyclicContainer)
case c
}
Workaround 1
There is a work around for this. I can declare, for example:
indirect enum CyclicContainer {
case container(Container<CyclicContainer>)
}
… However, this becomes awkward for concise descriptions of a CyclicContainer instance:
let cyclicContainer: CyclicContainer = .container(.a(.container(.b(.container(.c)))))
Instead of just:
let cyclicContainer: CyclicContainer = .a(.b(.c))
Workaround 2
I could also simply create a separate enum for the recursive case, as shown earlier:
indirect enum CyclicContainer {
case a(CyclicContainer)
case b(CyclicContainer)
case c
}
However, I'll need to: create functions to convert between CyclicContainer and Container; re-implement various member functions that exist on Container<T>; and keep the two types in sync in future if I add a new case or change a case name.
This isn't terribly arduous and it's the approach I'm leaning towards. But it seems a shame to have to do this when Swift can handle an indirect enum completely happily, but not when its induced by instantiation of a generic argument on the enum.
Question
Is there a better way?

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))

Swift struct type recursion

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

Store type in variable to use like a type later

I'm trying to store a type in a variable so that I can use it like a 1st class type later on.
class SomeModel {}
let someType = SomeModel.self
let array = Array<someType>()
In this case sure I could have done Array<SomeModel>() instead but I want to generalize it and let subclasses provide the value of someType.
However I get errors like someType isn't a type or use of undeclared type 'someType' on the last line.
If you need to store several type values in array, this works pretty well:
let array: [Any.Type] = [String.self, Int.self]
func someFunc<T>(model: T) -> Array<T> {
let array = Array<T>()
return array
}
let someType = SomeModel.self
let array = someFunc(someType())
Looks like this does what I want. The only drawback is that I have to create an instance of the desired type to pass. In this case its minimal overhead, but it just seems like a waste.
Another thing with using generics like this is it appears that the generic's possible types are computed at compile time, so at run time model.dynamicType doesn't necessarily match T. In most cases it will, but if you are doing any reflection driven stuff make sure to really check your use case well.
These days, this can be more easily and adaptably achieved by using .Type on a class or protocol. Note that only functions available to that root class or protocol will be accessible however, so you should ensure that a required initialiser of some kind is defined. For example:
protocol MyClass {
init(someValue: Int)
}
class MyWrapper {
let myClassType: MyClass.Type
init(classType: MyClass.Type) {
self.myClassType = classType
}
func new(with value: Int) -> MyClassType {
return MyClassType.init(someValue: value)
}
}
You can now initialise this rather silly factory class with a specific class implementing the MyClass protocol and when you call the new() function with an integer value it will generate a new instance of that class and return it.