My son wanted to exercise math on the iPad. He likes math, which is good.
We tried several apps, but nothing suits his needs. I did end up
in the Xcode.
Started with implementation of MathOperation. OptionSetType looked like
a good choice. He can exercise one operation, any combination or all of them.
Here’s the OptionSetTypedocumentation.
Later on, I came to the point where I wanted to select random MathOperation from
provided options. But how? There’s no easy way and it seems that enum & Set
would be much better. But let it be and finish it with OptionSetType. Just to
learn more about Swift standard library. What do we need?
Conversion of OptionSetType to an array of single options. In other
words – we need to convert OptionSetType to Array<OptionSetType>.
Generic implementation – any integer type can be used as RawValue (OptionSetType).
All integer types (Int, …) are structs in Swift. All of them conform to slightly
different set of protocols. Here’s the quick overview:
Lot of protocols omitted to make it more readable. Common ancestor for all integer
types is IntegerType protocol. Great, I’m going to stick with it. Let’s
define OptionSetType extension in this way:
Next step is to iterate over all single bit values (power of two), check if they’re set
and add them to an array. I do like generators, so, let’s introduce BitValuesGenerator
and implement array property with it.
What do I want? In case of:
UInt8 – 1, 2, 4, 8, 16, 32, 64, 128
Int8 – 1, 2, 4, 8, 16, 32, 64
does use one bit for sign (minus, plus) and I’m going to ignore this bit.
One can think that I can use << operator.
No, I can’t. This code doesn’t compile. Operator << cannot be applied to
operands of type Element and Int. And it cannot be applied to two Element operands as well even when Element is IntegerType.
The problem lies in the Swift standard library.
Copy & paste for all integer types, but there’s no << operator for IntegerType.
Optional left shift
What now? Going introduce new <<? operator – left shift or nil if overflow happens.
And for IntegerType instead of copy & pasting it for all integer types.
Now I’m going to check Swift standard library to see what can I do with IntegerType.
toIntMax()? No way. Int64 maximum value is 2^63 - 1. UInt64 maximum value is 2^63. toIntMax() converts integer to IntMax (typealias for Int64). And Int64 can’t hold 2^63 =
overflow = crash in case where RawValue of OptionSetType is UInt64 and 2^63 is used
multiplyWithOverflow? Left shift is multiplication by 2. Result type of this function
is (Self, overflow: Bool). Where Self is multiplication result and overflow indicates
if overflow happened or not. Useful.
Safe left shift for IntegerType done and I can fix broken BitValuesGenerator.
Finally I can extend OptionSetType with randomGenerator() as well.
We have working generic random option generator for IntegerType.
Go back to the Swift standard library and check IntegerType documentation
Useful functions are hidden in protocols with prefix _. And these protocols
documentation says: This protocol is an implementation detail of …; do
not use it directly. Bummer.
Another approach can be &*.
Updated <<? implementation.
Probably safer way in terms of _ protocols & implementation details. On the other side,
all these functions are available (again copy & paste) on all integer types as well.
Maybe it’s okay to use _IntegerArithmeticType.multiplyWithOverflow. Don’t know, not
100% sure and don’t have good feeling about it when working with IntegerType.
Anyway, you can find both implementations in this gist.
Choose whatever feels safer to you.
What I would like to see in Swift 3? Better generics support for integer types
more operators in standard library. I would like to work with IntegerType as
with any other integer type like Int8, … Type safety is good, really
good, but it makes things harder to do sometimes.