Swift enum cannot assign default raw value - swift

Sample code:
enum BestLetters {
case A
case B
case C
case Default = B
}
The error in the Default case: Raw value for enum case must be a literal
My understanding is that enum raw values are limited to certain types (Ints, Strings, Booleans, etc). Obviously BestLetters isn't one of those types and the compiler is complaining.
How can I set the Default type's raw value to one of the other "letters"? If gives any context, the reason for this odd syntax is that I am trying to imitate something I saw in obj-c.
Thank you for your help.

In (Objective-)C an enumeration defines a set of named integer constants, and those need not be distinct:
enum {
A = 1,
B = 2,
C = 99,
Default = B
};
The cases of a Swift enum represent mutually distinct values, and their raw values – if assigned – must be unique:
enum BestLetters: Int {
case a = 1
case b
case c
case `default` = 2 // Error: Raw value for enum case is not unique
}
On the other hand, enumerations in Swift are first-class types, so that you can define a static property for that purpose:
enum BestLetters {
case a
case b
case c
static let `default` = BestLetters.b
}
(This is also how Swift imports C enumerations with duplicate values, compare touchIDLockout deprecated in iOS 11.0.)

Related

Swift enum size when associated value is a reference type

I read documentation about size of enums in Swift and here is my understanding:
This simple one only hold a 'tag' to differentiate cases, which is by default an UInt8 value, i.e. small = 0, medium = 1 and so on. So, Size's size is 1 byte, which can be verified with MemoryLayout<Size>.size. I also noted that if an enum has more than 255 cases, obviously the tag size is upgraded to 2 bytes.
enum Size {
case small
case medium
case large
}
Second case, if an enum has associated values it behaves like a union. In this case the enum size is the size of the tag plus the size of the largest associated value. In the following example the size is 1 byte + 16 bytes (String) so 17 bytes, which can also be verified with MemoryLayout.
enum Value {
case int(Int)
case double(Double)
case string(String)
case bool(Bool)
}
Last case, as Swift is a safe language references are always valid using standard non-unsafe Swift code, i.e always pointing to a value in memory. This allows the compiler to optimise such enum when T is a reference type:
enum Opt<T> {
case none
case some(T)
}
Here an instance of type T cannot by nil (NULL) so the compiler uses this special value for the none case, hence Opt is of size 8 bytes instead of 9 bytes when T is a reference type. This optimisation is raised in this SO question about Rust which I believe has the same behaviour has Swift concerning enums.
For instance with this simple reference type, MemoryLayout returns a size of 8 bytes:
class Person {
var name: String
init(name: String) {
self.name = name
}
}
let p = Opt.some(Person(name: "Bob")) // 8 bytes
Question
What I cannot figure out is the size of this enum (still when T is a reference type):
enum Opt<T> {
case none
case secondNone
case some(T)
}
Why this one is also 8 bytes, according to MemoryLayout?
In my understanding it should be 9 bytes. The NULL optimisation is only possible because none can be represented by NULL but there is no 'second' NULL value for secondNone in my example, so a tag should be required here to differentiate the cases.
Does the compiler automatically turns this enum into a reference type (similar to an indirect enum) because of this? This would explain the 8 bytes size. How can I verify this last hypothese?
From Type Layout: Single-Payload Enums:
If the data type's binary representation has extra inhabitants, that is, bit patterns with the size and alignment of the type but which do not form valid values of that type, they are used to represent the no-data cases, with extra inhabitants in order of ascending numeric value matching no-data cases in declaration order.
Your example with more cases:
enum Opt<T> {
case a, b, c, d, e, f, g, h, i, j, k
case l, m, n, o, p, q, r, s, t, u, v
case some(T)
}
class Person {
var name: String
init(name: String) { self.name = name }
}
print(unsafeBitCast(Opt<Person>.a, to: UnsafeRawPointer.self))
// 0x0000000000000000
print(unsafeBitCast(Opt<Person>.b, to: UnsafeRawPointer.self))
// 0x0000000000000002
print(unsafeBitCast(Opt<Person>.v, to: UnsafeRawPointer.self))
// 0x000000000000002a
let p = Person(name: "Bob")
print(unsafeBitCast(Opt.some(p), to: UnsafeRawPointer.self))
// 0x00006030000435d0
Apparently, 0x0, 0x2, ..., 0x2a are invalid bit patterns for a pointer, and therefore used for the additional cases.
The precise algorithm seems to be undocumented, one probably would have to inspect the Swift compiler source code.

How does this code to generate enum work in Swift? [duplicate]

In Swift, there is Raw Value in Enumeration and Default Value in class and structure. What's the different? Can someone explain that for me?
Ex. of Raw Values of Enumeration (From the Office Swift Document)
enum ASCIIControlCaracter: Character {
case Tab = "\t"
case LineFeed = "\n"
case CarriageReturn = "\r"
}
From Apple docs:
Raw Values
The barcode example in Associated Values shows how cases of an
enumeration can declare that they store associated values of different
types. As an alternative to associated values, enumeration cases can
come prepopulated with default values (called raw values), which are
all of the same type.
So I guess it is the same.
On the other hand, with "default value", you may be referring to the default value of an enum case where no values have been set, for example:
enum TestEnum: Int {
case A
case B
}
Here, TestEnum.A has a default value of 0, and TestEnum.B has a default value of 1.
Raw value refers to the actual value of an enum case (in the enum's type, in this example it would be Int):
enum TestEnum: Int {
case A
case B = 3
}
Here, TestEnum.A has the default value (which is also the raw value) of 0, and TestEnum.B has a raw value of 3 (which is no longer the default value).

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

Cannot subscript a value of type 'inout Array<Array<Any>>

I have a 2D array : var matrixOfMutableObjects: Array<Array<Any>>
But when i try to check if the value on a certain position of the Array is a enum that i created the compiler complains: Cannot subscript a value of type 'inout Array<Array<Any>>
if(x < 0 || x > ROWS || y < 0 || y > COLS){
return false;
} else if (matrixOfMutableObjects[x][y] != enumObject.NOTHING){
return false;
}
Why cant i verify if the element in the position x,y of my Array is of the type enumObject.NOTHING that i created??
public enum enumObject {
case NOTHING
case Wall
}
Pattern matching (used for matching cases in enum instances) and equality testing are two different things.
Also, an object wrapped in Any is only known to the compiler as Any, so you need to perform an attempted conversion to a given type prior to applying e.g. pattern matching vs cases of that type (say, if the type converted to is an enum).
E.g.:
public enum enumObject {
case NOTHING
case Wall
}
var matrixOfMutableObjects: Array<Array<Any>> = [
[1, "two"],
[enumObject.NOTHING, 4.2]
]
let x = 1
let y = 0
// no bounds checking in this simple example!
if case .some(.NOTHING) = matrixOfMutableObjects[x][y] as? enumObject {
print("Is nothing!")
}
Or, using the ? syntactic sugar:
// ...
if case .NOTHING? = matrixOfMutableObjects[x][y] as? enumObject {
print("Is nothing!")
}
Note that the outer .some(...) pattern matching (or ? sugar) checks that the attempted conversion of the element to enumObject is successful. If that is the case, an additional pattern matching of is performed for the wrapped object (which is then known to be of type enumObject) to a given case of enumObject (.NOTHING, specifically).
Curiosities of Swift: avoiding the explicit type conversion
As pointed out by #Hamish in a comment below, it seems that enum case pattern matching can actually perform the conditional type casting for you, meaning you needn't resort to the explicit casting and nested pattern matching above (as? and .some(...)/?, respectively), but can simply use pattern matching against the NOTHING case directly, given that you also supply the enum type:
if case enumObject.NOTHING = matrixOfMutableObjects[x][y] {
print("Is nothing!")
}
Finally, note that the Swift API Guidelines prescribes lowercase enum cases, so you might want to use the cases nothing and wall, rather than NOTHING and Wall, and additionally CamelCase name convention for types (so prefer EnumObject over enumObject).

Raw Value of Enumeration, Default value of a class/structure, What's the different?

In Swift, there is Raw Value in Enumeration and Default Value in class and structure. What's the different? Can someone explain that for me?
Ex. of Raw Values of Enumeration (From the Office Swift Document)
enum ASCIIControlCaracter: Character {
case Tab = "\t"
case LineFeed = "\n"
case CarriageReturn = "\r"
}
From Apple docs:
Raw Values
The barcode example in Associated Values shows how cases of an
enumeration can declare that they store associated values of different
types. As an alternative to associated values, enumeration cases can
come prepopulated with default values (called raw values), which are
all of the same type.
So I guess it is the same.
On the other hand, with "default value", you may be referring to the default value of an enum case where no values have been set, for example:
enum TestEnum: Int {
case A
case B
}
Here, TestEnum.A has a default value of 0, and TestEnum.B has a default value of 1.
Raw value refers to the actual value of an enum case (in the enum's type, in this example it would be Int):
enum TestEnum: Int {
case A
case B = 3
}
Here, TestEnum.A has the default value (which is also the raw value) of 0, and TestEnum.B has a raw value of 3 (which is no longer the default value).