The switch statement in Swift is so much more expressive. I\'m wondering if this might be possible:
Lets look at UIViewAutoresizing for example. It\'s defined in Objecti
Another solution that I came up with is this:
let foo = /* .. your value to test .. */
let allCases = [UIViewAutoresizing.FlexibleHeight, UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleTopMargin]
for oneCase in allCases {
switch oneCase & foo {
case UIViewAutoresizing.FlexibleHeight:
println("height")
case UIViewAutoresizing.FlexibleWidth:
println("width")
case UIViewAutoresizing.FlexibleTopMargin:
println("top")
default:
break
}
}
I tried several hours yesterday and today to make this work with switch — no success.
The reason is that in this particular case we need to test against several cases. In Swift we need to use the fallthrough
key word. But we are not allowed to fall through to the next case if that next case uses a variable, there for we cannot use the case let where
statement, as shown here:
switch foo {
case let x where x & .FlexibleHeight != nil:
println("height")
case let x where x & .FlexibleWidth != nil:
println("width")
case let x where x & .FlexibleTopMargin != nil:
println("top margin")
default:
println("no")
}
This will break out once a case triggered. But
switch foo {
case let x where x & .FlexibleHeight != nil:
println("height")
fallthrough
case let x where x & .FlexibleWidth != nil:
println("width")
fallthrough
case let x where x & .FlexibleTopMargin != nil:
println("top margin")
default:
println("no")
}
does not work for the reason described above.
I'd go with a clear if statement, like
let foo = UIViewAutoresizing.FlexibleLeftMargin | UIViewAutoresizing.FlexibleHeight
let width = foo & UIViewAutoresizing.FlexibleWidth;
let height = foo & UIViewAutoresizing.FlexibleHeight;
if width == .FlexibleWidth {
println("width")
}
if height == .FlexibleHeight {
println("height")
}
or
let foo = UIViewAutoresizing.FlexibleLeftMargin | UIViewAutoresizing.FlexibleHeight
let usesFlexibleWidth = (foo & UIViewAutoresizing.FlexibleWidth) != nil;
let usesFlexibleHeight = (foo & UIViewAutoresizing.FlexibleHeight) != nil;
if usesFlexibleWidth {
println("width")
}
if usesFlexibleHeight {
println("height")
}
You definitely can, although it's a little more convoluted now that RawOptionSetType
doesn't implement the BooleanType
protocol.
switch foo {
case let x where x & .FlexibleHeight != nil:
println("height")
case let x where x & .FlexibleWidth != nil:
println("width")
case let x where x & .FlexibleTopMargin != nil:
println("top margin")
default:
println("no")
}
Note that this stops on the first condition that matches! So it really is another form of this:
if foo & .FlexibleHeight != nil {
println("height")
} else if foo & .FlexibleWidth != nil {
println("width")
} else if foo & .FlexibleTopMargin != nil {
println("top margin")
}
I was frustrated enough about this problem that I wrote a Bitmask<T>
class that can handle these use cases. The code is up on Github: brynbellomy/SwiftBitmask
It allows you to do stuff like this with any kind of object as your underlying type (here I'm using an enum
):
enum MonsterAttributes : IBitmaskRepresentable, IAutoBitmaskable {
case Big, Ugly, Scary
static var autoBitmaskValues : [MonsterAttributes] = [.Big, .Ugly, .Scary,]
var bitmaskValue: UInt16 { return AutoBitmask..autoBitmaskValueFor(self) }
init(bitmaskValue: UInt16) { self = AutoBitmask.autoValueFromBitmask(bitmaskValue) }
}
// various ways to initialize
let option : MonsterAttributes = .Ugly
let bitmaskOfOption = Bitmask(option)
let anotherBitmaskOfOption = |MonsterAttributes.Ugly // same as bitmaskOfOption
let orWithVar = option | .Big // == Bitmask<MonsterAttributes> with a bitmaskValue of 1 | 2
let simpleOr = MonsterAttributes.Big | .Ugly // == Bitmask<MonsterAttributes> with a bitmaskValue of 1 | 2
// getting the raw integral bitmask value
let simpleOrValue = simpleOr.bitmaskValue // == UInt16(1 | 2)
let orValue = (MonsterAttributes.Big | .Ugly).bitmaskValue // == UInt16(1 | 2)
// implements BooleanType
if simpleOr & .Ugly { /* this code will execute */ }
// supports pattern matching operator
if simpleOr ~= .Ugly { /* this code will execute */ }
if simpleOr ~= (.Ugly | .Scary) { /* this code will execute */ }
... and all you have to do is implement a one-property protocol.
I'm really curious if anyone has any feedback on or ideas for the code, so please leave an issue in the queue if you think of anything!