`diff Swift C++`: Strange case of `enum`
So far the biggest difference that I've encountered between modern C++ use (read: C++11 with its standard library for generic containers and reference counting, exception safety guarantees and so on) and Swift is enum
.
enum
in C++ is just an enumeration of values of different integral types. There is nothing fancy about it nor anything that you haven't seen in other languages like Java or C#.
enum
s in Swift are something completely different:
- They can take values of
string
,char
or any integer or floating-point type (fine) - They can take associated values of any type within the same
enum
instance (what?) or as Swift book puts it:
“much as unions or variants do in other languages”
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/cl/jEUH0.l
(aaaah...)
- They allow you to not provide a direct raw value but instead let compile generate the internal representations in which case
enum
values are not convertible to raw values (unlike C/C++ where you can always cast them) - They can have computed properties and instance methods ("curiouser and curiouser")
- They can provide initializers (I'll just stop now)
- They can be
extend
ed. - They can adopt
protocol
s. - They can be pattern matched in
switch
statemens (another seemingly-similar-yet-rather-different facility than the one calledswitch
in other mainstream languages) - They can be generic types (!!)
That's lot to digest. To make it easy I've simply stopped thinking of these as enum
s but rather as a specialized type of classes that exibit some minor enum
characteristics as well.
IpAddress example
During my experimentation I came up with the following IP address enum
example:
enum IpAddress : Printable {
Only the following lines are the actual enum
values:
// IPv4 address is 4 bytes long
case v4(Byte, Byte, Byte, Byte)
// IPv6 address is 8 words long
case v6(Word, Word, Word, Word, Word, Word, Word, Word)
Here we can see how protocol
s are implemented as in other language constructs. At the same time this is obviously a property.
// Implementation of Printable protocol
var description: String {
switch self {
switch
command can perform pattern matching which can extract the values associated to an enum
value:
case let .v4(b1, b2, b3, b4):
return "\(b1).\(b2).\(b3).\(b4)"
case let .v6(w1, w2, w3, w4, w5, w6, w7, w8):
// If I tried postfix formatting XCode would just continuously crash
// so at the end I left Words unformatted (that is... formatted in the
// decimal system)
return "\(w1):\(w2):\(w3):\(w4):\(w5):\(w6):\(w7):\(w8)"
}
}
enum
s can have methods.
// Return the array of constituent address values.
// If IpAddress is IPv4 then convert Byte values to Word.
func getArray() -> Word[] {
switch self {
case let .v4(b1, b2, b3, b4):
Unrelated to enum
s an example of mapping an array of Byte
values to an array of Word
values.
// Map the array of IPv4 values to a Word array.
return [b1, b2, b3, b4].map { Word($0) }
case let .v6(w1, w2, w3, w4, w5, w6, w7, w8):
return [w1, w2, w3, w4, w5, w6, w7, w8]
}
}
We can even setup constant values of the very same enum
.
// Constant to be used for IpV4 0.0.0.0
static let ZeroV4 = IpAddress.v4(0, 0, 0, 0)
// Constant to be used for IpV4 127.0.0.1
static let LoopbackV4 = IpAddress.v4(127, 0, 0, 1)
// Constant to be used for IpV6 0:0:0:0:0:0:0:0
static let ZeroV6 = IpAddress.v6(0, 0, 0, 0, 0, 0, 0, 0)
// Constant to be used for IpV6 ::1
static let LoopbackV6 = IpAddress.v6(0, 0, 0, 0, 0, 0, 0, 1)
}
This example doesn't illustrate the generics but the example in the Swift book (reemplimenting optional values with generic enum
) is great.
A couple of final notes:
- I failed to implement a default
init
- compiler simply wouldn't allow me to assign toself
which was fine by me but left me without options. I even tried doing initialization delegation and at some point I managed to make it compile but it didn't work. - As I noted in the comments, I couldn't make hexadecimal formatting work with string interpolation - XCode would constantly crash on restart until I edited the playground source. It wasn't relevant for the example so I left it as it was.