Overcoming Type alias '…' references itself - swift

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?

Related

Get Type from Metatype

I'm struggling to understand the different between Types and Metatypes in swift 4. In particular I am looking to create an array something like this:
class A { ... }
class B {
func doStuff() {
let otherType = A.self
let itemArr : [otherType] = // Objects of type A
}
}
This throws a compile time error of Use of undeclared type 'otherType' which I think is occurring because otherType is actually A.Type. I think this may have something to do with Generics, but the catch is the type might not be known at compile time...
Is there a solution to this problem?
Swift is powerful because you can pass types as parameters and create variable of types. This is attractive, but yet, there is better solution for your issue.
Define protocol CustomArrayPopulatable {} And add this to all subclasses/classes that could be added to the array. E.G. A1: CustomArrayPopulatable ; A2: CusstomArrayPopulatable.
With generic types, you could achieve great abstraction. However, have in mind, if you need to cast to specific subtype later on, you would need to cast it yourself such as: if type as? A1 {...}, so use generics carefully and think before you start, do you really need them.

Switch on Array type

Overview
I would like to use switch statement by matching array type. I have the following classes.
Class:
class A {}
class B : A {}
Switch on single value works:
let a : A = B()
switch a {
case let b as B:
print("b = \(b)")
default:
print("unknown type")
}
Switch on array (Compilation Error):
let aArray : [A] = [B(), B()]
switch aArray {
case let bArray as [B] :
print("bArray = \(bArray)")
default:
print("unknown type")
}
Error:
Downcast pattern value of type '[B]' cannot be used
Note: Tested on Swift 4
Question:
How can I achieve this ?
In Swift 4.1, you get a better error message (thanks to #11441):
Collection downcast in cast pattern is not implemented; use an explicit downcast to '[B]' instead
In short, you're hitting a bit of the compiler that isn't fully implemented yet, the progress of which is tracked by the bug SR-5671.
You can however workaround this limitation by coercing to Any before performing the cast:
class A {}
class B : A {}
let aArray : [A] = [B(), B()]
switch aArray /* or you could say 'as Any' here depending on the other cases */ {
case let (bArray as [B]) as Any:
print("bArray = \(bArray)")
default:
print("unknown type")
}
// bArray = [B, B]
Why does this work? Well first, a bit of background. Arrays, dictionaries and sets are treated specially by Swift's casting mechanism – despite being generic types (which are invariant by default), Swift allows you to cast between collections of different element types (see this Q&A for more info).
The functions that implement these conversions reside in the standard library (for example, Array's implementation is here). At compile time, Swift will try to identify collection downcasts (e.g [A] to [B] in your example) so it can directly call the aforementioned conversion functions, and avoid having to do a full dynamic cast through the Swift runtime.
However the problem is that this specialised logic isn't implemented for collection downcasting patterns (such as in your example), so the compiler emits an error. By first coercing to Any, we force Swift to perform a fully dynamic cast, which dispatches through the runtime, which will eventually wind up calling the aforementioned conversion functions.
Although why the compiler can't temporarily treat such casts as fully dynamic casts until the necessary specialised logic is in place, I'm not too sure.

Is it possible to get the containing type from an instance of a nested type?

I'm trying to achieve something similar to--but not quite the same as--the Codable/CodableKeys protocols that Swift4 uses.
Given the following code:
protocol Handler{}
protocol HandlerValues{}
class SomeClass : Handler{
enum MyEnum : String, HandlerValues{
case first
case second
}
}
class SomeOtherClass : Handler{
enum MyEnum : String, HandlerValues{
case third
case fourth
case fifth
}
}
The following statements are guaranteed to be true:
A class that implements Handler, must specify an enum that implements HandlerValues, or an error will be thrown.
That enum's name will always be MyEnum (in this example)
Any enum that implements HandlerValues will always be defined within a Handler class. (similar to CodableKeys being defined within a Codable. Technically this can't be enforced, but if it's defined anywhere else, it's simply ignored.)
What I'm trying to do is one of two things:
Inside a function that takes a HandlerValue as an argument, infer it's containing class, or...
Inside a function that takes a Handler as an argument, to be able to enumerate its HandlerValues (like how implementations that take a Codable know how to iterate over its CodableKeys enum.)
For the first, my thought is to use String(reflecting:), split on '.', lop off the last component, reassemble/join to a string, then get the type based on it. It's three-lefts-to-go-right, but it would get me there.
In the second case, I'm trying to define Handler in such a way to guarantee it will have a HandlerValues enum that can be enumerated (again, like Codable knows it will have a CodableKeys enum. I just don't know how Codable defines that.)
I tried this, but of course this doesn't work...
protocol HandlerValues{}
protocol Handler{
enum MyEnum : HandlerValues
}
Update
This seems to be getting me closer...
protocol HandlerValues : RawRepresentable{}
protocol Handler{
associatedtype MyEnum : HandlerValues
}
...but I still don't know how to achieve #2 above (i.e. given a Handler instance, how can you enumerate the values of its MyEnum or how do you even guarantee MyEnum is an enum in the first place?)
So how can that information be obtained?
I figured out how to achieve what I'm after. In short, I now have solution approach #2 working in a purely-Swift way.
Here's the link to the answer on my other question.

representation of enum member values in swift?

enum CompassPoint {
case north, east, south, west
}
var compassHeading = CompassPoint.west
I've read that "The case values of an enumeration are actual values, not just another way of writing their raw values." I'm confused about this statement. If cases are new types themselves, then shouldn't it be initialized as:
var compassHeading = CompassPoint.west()
According to apple, enums don't include implicit initializers.. which confuses me even more.
TLDR;
If typing out a case of an enum where the case has associated values, then the type of this case will be a higher order function with arguments matching the associated values and return type matching the enum itself. Since different cases are allowed to have different types (and number) of associated values, naturally the type of a typed out enum case can differ. The importance here is to differ between an enum instance (which always have a given case as value) and the explicit types of the cases themselves (when not values).
An enum instance is always associated with a case, and always have the type of the enum
I don't know the source of your quotations, but the Language Guide is quite straightforward on describing each case as value:
An enumeration defines a common type for a group of related values and
enables you to work with those values in a type-safe way within your
code.
The typed cases of enum:s with cases of different associated values will define different types of higher order function types, all returning the type of the enum
But in addition the value-view of the case instance of an enum, it might be noted that each case (typed out!) itself has a type (although not a "new" type in the sense that struct Foo {} would), which may differ between different cases of the same enum. If the cases have no associated value(s), this type simply equals the enum itself, but if the case use associated values, then the type of the case will be a higher order function type with arguments typed as the associated values and return type being the enum type itself. Since different cases can have different associated values, it naturally follows that different cases can correspond to different types.
Alternatively, enumeration cases can specify associated values of any
type to be stored along with each different case value, much as unions
or variants do in other languages. You can define a common set of
related cases as part of one enumeration, each of which has a
different set of values of appropriate types associated with it.
...
You can define Swift enumerations to store associated values of
any given type, and the value types can be different for each case of
the enumeration if needed.
enum Foo {
case bar
case baz(Int) // Int associated value
case bax() // Void associated value
}
print(type(of: Foo.bar)) // Foo
print(type(of: Foo.baz)) // (Int) -> Foo
print(type(of: Foo.bax)) // () -> Foo
func foo(_ closure: (Int) -> Foo) -> Foo {
return closure(42)
}
let foobaz = foo(Foo.baz) // 'foobar' is 'Foo.baz' (ass. value 42)
let foobar = foo(Foo.bar) // wont compile, type mismatch
let foobax = foo(Foo.bax) // wont compile, type mismatch
Now, since different cases have different types (when typed out, not when part of a Foo instance), "initialization" of given case to a given enum instance will look different depending on whether the case have any associated values or not.
enum Foo {
case bar
case baz(Int) // Int associated value
case bax() // Void associated value
}
var foo = Foo.bar // no associated values
foo = Foo.baz(42) // expects Int associated value: needs to be _invoked_(/called)
foo = Foo.bax() // expects empty tuple '()' associated value: needs to be _invoked_(/called)
As you can see, a case instance without an associated value is instantiated simply by typing out the enum type and the case (since the type of this case will be the enum itself: compare with Foo.bar), whereas cases with associated values (even ()) will need to be invoked when instantiated. This invokation, particularly for the bax() case above, might look a lot like some implicit initialization, but its simply the invokation of a closure type to receive an instance of the return type Foo.
let aVoidFooClosure = Foo.bax
let aFooInstance = aVoidFooClosure()
// invoke! This now have value 'Foo.bax' (empty tuple '()' associated value)
If cases are new types themselves, then shouldn't it be initialized as:
var compassHeading = CompassPoint.west()
It's just a matter of notation. But I think you can justify it to yourself like this.
It is possible to add an initializer of the kind you seem to expect, but then what you are initializing is CompassWest, not a particular case:
enum CompassPoint {
case west
init() {
self = .west
}
}
let cp = CompassPoint()
Moreover, if CompassPoint's west case had an associated value, what you ask for is just the sort of thing you would say:
enum CompassPoint {
case west(Int)
}
let cp = CompassPoint.west(25)
But since no case has an associated value, all CompassPoint.west objects are effectively the same object. No state is maintained — remember, an enum has no stored properties. So this is not like instantiating a struct or a class. CompassPoint.west is not an instantiation of this case of CompassPoint; it the one and only CompassPoint.west in the universe.
(In that sense, the case .west is more like a static property of a struct than like an instance of a class. And so the notation for referring to it is just like the notation for referring to a static property of a struct.)

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