Swift enum error: Braced block of statements is an unused closure - swift

Enums in Swift look to be really powerful, but... I must be missing something about how I'm implementing this. I want to define some actions for a remote media player. Seems like a good use case for an enum. I've defined the allowed message types in the Enum, and I'd like to use it to get a modified parameter dictionary. The parameters will eventually get sent as JSON to the player. At the moment, I'm getting a Braced block of statements is an unused closure error. Here's the relevant code:
public enum PlayerCommand {
case Play
case Pause
case Load(String)
func params(cmd_id:NSInteger) -> [String : Any] {
var dict = [
CMD_ID : cmd_id,
TYPE : "LOAD",
AUTOPLAY : false,
MEDIA : NSNull()
]
switch self {
case .Load(let media): {
dict.updateValue(media, forKey: MEDIA)
}
case .Play: {
dict.updateValue("PLAY", forKey: TYPE)
dict[CURRENT_TIME] = NSNull()
}
case .Pause: {
dict.updateValue("PAUSE", forKey: TYPE)
}
default:
}
return dict
}
}
I am sure that there is also a more functional (swiftian?) way to express this, as well, but I'm not having a lot of luck with the syntax yet. map?

You have your switch syntax a bit off, is all. You don’t need { } around the expressions of each case (Swift is interpreting them as you trying to create a closure expression hence the error).
Just do case .Play: dict.updateValue(etc.).
Note also you must have a statement in the default clause – but you don’t actually need a default in this case, since your switch is exhausting all the possibilities.

Related

Can you define an enum to represent values explicitly known to your app, but still handle unknown values decoded from the backend?

The Problem
Can you define an enum to represent known values for a property in your model while still allowing for unknown values to be returned from the backend?
Short answer: Yes you can! The answer is below.
More Context
As part of our app, we have defined a set of feature flags that the app uses to enable/disable certain features depending on a set of criteria. These flags are sent back from the backend as an array of strings.
However, in our app, rather than dealing with the messiness of string constants, we want to define those values as an enum which we mark as Codable so the compiler handles the encoding/decoding to the actual enum cases for us automatically.
Here's a typical enum for such scenarios...
enum FeatureFlag : String, CaseIterable, Codable {
case allowsTrading
case allowsFundScreener
case allowsFundsTransfer
}
The wrinkle with this design is it doesn't handle values that may be defined, and returned from the backend in the future.
There are several ways to handle this scenario:
Abandon the enum and go to string constants. This is error prone and breaks containment/scoping since any string can participate in this logic.
Stick with an enum as-is and force an update to the app when the backend gets updated passing the buck to deployment.
Update the backend to handle versioning to only return values known to that version of the app complicating the logic on the backend to know about the various front-ends, which they shouldn't.
The most common, defensively program for unknowns by writing your own encoder/decoder methods for each class/struct that uses this enumeration, ignoring any flags not known by the current list of cases.
One through three are maintenance nightmares in their own right. Yes, four is better, but writing all those custom serializers/deserializers can be pretty time-consuming and error-prone, plus it defeats leveraging the benefits of the compiler being able to automatically do it for you!
But what if there's a number five? What if you can make the enumeration itself gracefully handle unknown values at runtime, while remaining lossless in the process, and without having to resort to optionals?
Well that's the exact solution I present below! Enjoy!
TL:DR - The Solution
For those who just want to see the solution, here it is in its entirety. This allows you to define an enum with known cases, but which can handle any raw value thrown at it at runtime, and do so in a lossless way for re-encoding purposes.
enum FeatureFlag : RawRepresentable, CaseIterable, Codable {
typealias RawValue = String
case allowsTrading
case allowsFundScreener
case allowsFundsTransfer
case unknown(RawValue)
static let allCases: AllCases = [
.allowsTrading,
.allowsFundScreener,
.allowsFundsTransfer
]
init(rawValue: RawValue) {
self = Self.allCases.first{ $0.rawValue == rawValue }
?? .unknown(rawValue)
}
var rawValue: RawValue {
switch self {
case .allowsTrading : return "ALLOWS_TRADING"
case .allowsFundScreener : return "ALLOWS_FUND_SCREENER"
case .allowsFundsTransfer : return "ALLOWS_FUNDS_TRANSFER"
case let .unknown(value) : return value
}
}
}
The Explanation
As mentioned above, our app has a certain set of known feature flags. At first, one may define them like so.
enum FeatureFlag : String, CaseIterable, Codable {
case allowsTrading
case allowsFundScreener
case allowsFundsTransfer
}
Simple enough. But again, now any value defined with the type FeatureFlag can only handle one of those specific known types.
Now say thanks to a new feature in the backend, a new flag allowsSavings is defined and pushed down to your app. Unless you have manually written the decoding logic (or resorted to optionals), the decoder will fail.
But what if the enum can handle unknown cases automatically for you, and do so in a completely transparent way?
It can! The trick is to define one additional case, unknown with an associated value of type RawValue. This new case handles all the unknown types handed to it when being decoded or even re-encoded.
Let's start by updating our enum with the new unknown case.
enum FeatureFlag : String, CaseIterable, Codable {
case allowsTrading
case allowsFundScreener
case allowsFundsTransfer
case unknown(RawValue)
}
This of course throws a ton of compiler errors thanks to that new case. Because of it, both RawRepresentable and CaseIterable can no longer be automatically synthesized by the compiler, so we have to manually implement them ourselves. Let's start with...
Manually Implementing the CaseIterable protocol
This is the easiest of the two steps. Since this 'version' of our app only knows about the first three cases, we can safely ignore all others. As such, to satisfy the protocol, we define a static allCases property that only specifies those cases we do care about.
Of Note: The property type AllCases here is an alias for [FeatureFlag] or more succinctly [Self], which we get for free when conforming to CaseIterable.
static let allCases: AllCases = [
.allowsTrading,
.allowsFundScreener,
.allowsFundsTransfer
]
With the above, this satisfies the CaseIterable protocol. Let's move on to...
Manually Implementing the RawRepresentable protocol
This is a little more complex/verbose, but this is where the 'magic' happens.
Specifying the RawValue type
Normally, to indicate your enum can be represented by a raw value, you specify a data type after an enum's name. In actuality, this is shorthand for telling the compiler you are conforming your enum to the RawRepresentable protocol and setting a RawValue typealias for that data type. However, again, because of our unknown type having an associated value, the compiler can't do that implicitly, so we must do so explicitly.
To do so, replace your raw type with RawRepresentable in the definition, then manually set the RawValue typealias inside, like so...
enum FeatureFlag : RawRepresentable, CaseIterable, Codable {
typealias RawValue = String
case allowsTrading
case allowsFundScreener
case allowsFundsTransfer
case unknown(RawValue)
}
implementing the rawValue: property (rawValues matching the case names)
Next up, we have to implement the rawValue property. For known cases where the raw value matches the case name, the implementation is simple as we can just return String(describing: self) and for the unknown cases, we return the associated value. Here's that implementation
var rawValue: RawValue {
switch self {
case let .unknown(value) : return value
default : return String(describing: self)
}
}
implementing the rawValue: property (rawValues unrelated to the case names)
But what if we wanted to express different values from the case names, or even a different data type entirely? In that situation, we have to manually expand out the switch statement and return the appropriate values like so....
var rawValue: RawValue {
switch self {
case .allowsTrading : return "ALLOWS_TRADING"
case .allowsFundScreener : return "ALLOWS_FUND_SCREENER"
case .allowsFundsTransfer : return "ALLOWS_FUNDS_TRANSFER"
case let .unknown(value) : return value
}
}
*Note: You must specify the raw values here and not up with the case definitions using the equals (=) as that's really syntactic sugar for the compiler to create what we're doing manually here, which again we have to since the compiler can't do it for us.
implementing init(rawValue:)... the 'Magic Sauce'
As mentioned, the entire purpose of this exercise is to allow your code to work with known types as usual, but to also gracefully handle unknown cases that are thrown at it. But how do we achieve that?
The trick is in the initializer, you first search for a known type within allCases and if a match is found, you use it. If however a match isn't found, rather than return nil like in the default implementation, you instead use the newly-defined unknown case, placing the unknown raw value inside.
This has the additional benefit of guaranteeing to always return an enum value from the initializer, so we can define it as a non-optional initializer as well (which is different from the implicitly created one from the compiler) making the call-site code easier to use as well.
Here's the implementation of the initializer:
init(rawValue: String) {
self = Self.allCases.first{ $0.rawValue == rawValue }
?? .unknown(rawValue)
}
In some situations, you may want to log when an unknown value is being passed for debugging purposes. That can be done with a simple guard statement (or an if if you prefer) like so...
init(rawValue: String) {
guard let knownCase = Self.allCases.first(where: { $0.rawValue == rawValue }) else {
print("Unrecognized \(FeatureFlag.self): \(rawValue)")
self = .unknown(rawValue)
return
}
self = knownCase
}
Interesting Behaviors on Equality and Hashability
One of the interesting things is that enums based on a raw value actually use that value for equality comparisons. Thanks to that piece of information, all three of these values are equal...
let a = FeatureFlag.allowsTrading // Explicitly setting a known case
let b = FeatureFlag(rawValue: "allowsTrading") // Using the initializer with a raw value from a known case
let c = FeatureFlag.unknown("allowsTrading") // Explicitly setting the 'unknown' case but with a raw value from a known case
print(a == b) // prints 'true'
print(a == c) // prints 'true'
print(b == c) // prints 'true'
Additionally, if your raw value conforms to Hashable, you can make the entire enum conform to Hashable by simply specifying its conformance to that protocol.
extension FeatureFlag : Hashable {}
With that conformance, now you can use it in sets or as keys in a dictionary as well, which again, thanks to the rules of equality above, provides for some interesting, but logically expected, behaviors.
Again, using 'a', 'b' and 'c' as defined above, you can use them like so...
var items = [FeatureFlag: Int]()
items[a] = 42 // Set using a known case
print(items[a] ?? 0) // prints 42 // Read using a known case
print(items[b] ?? 0) // prints 42 // Read using the case created from the initializer with a raw value from the known case
print(items[c] ?? 0) // prints 42 // Read using the 'unknown' case but with a raw value from the known case
Side-Benefit: Lossless Encoding/Decoding
One often-overlooked/underappreciated side-benefit of this approach is that serilization/deserialization is lossless and transparent, even for unknown values. In other words, when your app decodes data containing values you don't know about, the unknown case is still capturing and holding them.
This means if you were to then re-encode/re-serialize that data back out again, those unknown values would be re-written identically to how they would be if your app did know about them.
This is incredibly powerful!
This means for instance if an older version of your app reads in data from a server containing newer, unknown values, even if it has to re-encode that data to push it back out again, the re-encoded data looks exactly the same as if your app did know about those values without having to worry about versioning, etc. They're just silently and happily passed back.
Summary
With the above in place, you can now encode or decode any string into this enumeration type, but still have access to the known cases you care about, all without having to write any custom decoding logic in your model types. And when you do 'know' about the new type, simply add the new case as appropriate and you're good to go!
Enjoy!
Love this proposed solution! One small suggestion, add some logging in case the system encounters unknown types.
init?(rawValue: String) {
if let item = Self.allCases.first(where: { $0.rawValue == rawValue }) {
self = item
} else {
self = Self.other(rawValue)
if #available(iOS 12.0, *) {
os_log(.error, "Unknown FeatureFlag: %s", rawValue)
} else {
print("Error: Unknown FeatureFlag: \(rawValue)")
}
}
}

Swift enum evaluation

Using Alamofire we're trying to determine if an error is a certain kind of error (response code 499) as represented by a "nested" AFError enum:
if response.result.isFailure {
if let aferror = error as? AFError {
//THIS LINE FAILS
if (aferror == AFError.responseValidationFailed(reason: AFError.ResponseValidationFailureReason.unacceptableStatusCode(code: 499))) {
....
}
}
}
But this results in the compiler error:
Binary operator '==' cannot be applied to two 'AFError' operands
How can you do this?
Well, you could trying extending AFEError to conform to Equatable in order to use ==, but you are probably better off using switch and pattern matching:
switch aferror {
case .responseValidationFailed(let reason) :
switch reason {
case AFError.ResponseValidationFailureReason.unacceptableStatusCode(let code):
if code == 499 { print("do something here") }
default:
print("You should handle all inner cases")
{
default:
print("Handle other AFError cases")
}
This is the best syntax to ensure (and get the compiler to help you ensure) that all possible error cases and reasons are handled. If you only want to address a single case, like in your example, you can use the newer if case syntax, like this:
if case .responseValidationFailed(let reason) = aferror, case AFError.ResponseValidationFailureReason.unacceptableStatusCode(let code) = reason, code == 499 {
print("Your code for this case here")
}
As I point out here, you cannot, by default, apply the equality (==) operator between cases of an enum that as an associated value (on any of its cases); but there are many other ways to find out whether this is the desired case (and, if there is an associated value, to learn what the associated value may be).

Why is type inference not working in this switch statement in Swift 3?

UPDATE This is fixed in Swift 3.1
In migrating an if-else to a switch statement, I noticed that type inference wasn't working. Why do I need to specify HKQuantityTypeIdentifier in each case when quantityTypeIdentifier is already of that type?
func process(samples: [HKSample]?, quantityTypeIdentifier: HKQuantityTypeIdentifier) {
DispatchQueue.main.async { [weak self] in
if let quantitySamples = samples as? [HKQuantitySample] {
for sample in quantitySamples {
switch quantityTypeIdentifier {
case HKQuantityTypeIdentifier.distanceWalkingRunning:
// code
case HKQuantityTypeIdentifier.activeEnergyBurned:
// code
case HKQuantityTypeIdentifier.heartRate:
// code
default:
fatalError("Quantity Type Identifier not implemented \(quantityTypeIdentifier)")
}
}
}
}
}
I am able to call the function like:
process(samples: samples, quantityTypeIdentifier: .distanceWalkingRunning)
I think you've found a bug, or at least you have a reasonable case to claim one. The inconsistency is nicely shown by a much shorter example:
let c : UIColor = .red
switch c {
case .red : print ("red") // error
default : break
}
That won't compile. You can say .red on the first line but not on the third line. That seems a clear inconsistency.
Now, having said that, I can certainly explain why the rules are different in the two different places. A case expression is resolved according to the ~= operator and the rules of forming a pattern. Those rules are different from anything else in Swift (hence, for example, there are situations where you say as in a case pattern but would say as? everywhere else). So evidently those are the rules that would need tweaking in order for this to work. They have been tweaked so far as to allow bare enum cases but not bare enum-like struct "cases" (that is, static members of structs that are RawRepresentable where those static members evaluate to an instance of the struct itself).
Finally, here's a skanky workaround that I like to use when case patterns become too onerous:
let c : UIColor = .red
switch true {
case c == .red : print ("red") // heh heh
default : break
}
By switching on true and writing out the entire boolean condition we break the bounds of pattern-matching and reenter the world of normal expressions.

Can a condition be used to determine the type of a generic?

I will first explain what I'm trying to do and how I got to where I got stuck before getting to the question.
As a learning exercise for myself, I took some problems that I had already solved in Objective-C to see how I can solve them differently with Swift. The specific case that I got stuck on is a small piece that captures a value before and after it changes and interpolates between the two to create keyframes for an animation.
For this I had an object Capture with properties for the object, the key path and two id properties for the values before and after. Later, when interpolating the captured values I made sure that they could be interpolated by wrapping each of them in a Value class that used a class cluster to return an appropriate class depending on the type of value it wrapped, or nil for types that wasn't supported.
This works, and I am able to make it work in Swift as well following the same pattern, but it doesn't feel Swift like.
What worked
Instead of wrapping the captured values as a way of enabling interpolation, I created a Mixable protocol that the types could conform to and used a protocol extension for when the type supported the necessary basic arithmetic:
protocol SimpleArithmeticType {
func +(lhs: Self, right: Self) -> Self
func *(lhs: Self, amount: Double) -> Self
}
protocol Mixable {
func mix(with other: Self, by amount: Double) -> Self
}
extension Mixable where Self: SimpleArithmeticType {
func mix(with other: Self, by amount: Double) -> Self {
return self * (1.0 - amount) + other * amount
}
}
This part worked really well and enforced homogeneous mixing (that a type could only be mixed with its own type), which wasn't enforced in the Objective-C implementation.
Where I got stuck
The next logical step, and this is where I got stuck, seemed to be to make each Capture instance (now a struct) hold two variables of the same mixable type instead of two AnyObject. I also changed the initializer argument from being an object and a key path to being a closure that returns an object ()->T
struct Capture<T: Mixable> {
typealias Evaluation = () -> T
let eval: Evaluation
let before: T
var after: T {
return eval()
}
init(eval: Evaluation) {
self.eval = eval
self.before = eval()
}
}
This works when the type can be inferred, for example:
let captureInt = Capture {
return 3.0
}
// > Capture<Double>
but not with key value coding, which return AnyObject:\
let captureAnyObject = Capture {
return myObject.valueForKeyPath("opacity")!
}
error: cannot invoke initializer for type 'Capture' with an argument list of type '(() -> _)'
AnyObject does not conform to the Mixable protocol, so I can understand why this doesn't work. But I can check what type the object really is, and since I'm only covering a handful of mixable types, I though I could cover all the cases and return the correct type of Capture. Too see if this could even work I made an even simpler example
A simpler example
struct Foo<T> {
let x: T
init(eval: ()->T) {
x = eval()
}
}
which works when type inference is guaranteed:
let fooInt = Foo {
return 3
}
// > Foo<Int>
let fooDouble = Foo {
return 3.0
}
// > Foo<Double>
But not when the closure can return different types
let condition = true
let foo = Foo {
if condition {
return 3
} else {
return 3.0
}
}
error: cannot invoke initializer for type 'Foo' with an argument list of type '(() -> _)'
I'm not even able to define such a closure on its own.
let condition = true // as simple as it could be
let evaluation = {
if condition {
return 3
} else {
return 3.0
}
}
error: unable to infer closure type in the current context
My Question
Is this something that can be done at all? Can a condition be used to determine the type of a generic? Or is there another way to hold two variables of the same type, where the type was decided based on a condition?
Edit
What I really want is to:
capture the values before and after a change and save the pair (old + new) for later (a heterogeneous collection of homogeneous pairs).
go through all the collected values and get rid of the ones that can't be interpolated (unless this step could be integrated with the collection step)
interpolate each homogeneous pair individually (mixing old + new).
But it seems like this direction is a dead end when it comes to solving that problem. I'll have to take a couple of steps back and try a different approach (and probably ask a different question if I get stuck again).
As discussed on Twitter, the type must be known at compile time. Nevertheless, for the simple example at the end of the question you could just explicitly type
let evaluation: Foo<Double> = { ... }
and it would work.
So in the case of Capture and valueForKeyPath: IMHO you should cast (either safely or with a forced cast) the value to the Mixable type you expect the value to be and it should work fine. Afterall, I'm not sure valueForKeyPath: is supposed to return different types depending on a condition.
What is the exact case where you would like to return 2 totally different types (that can't be implicitly casted as in the simple case of Int and Double above) in the same evaluation closure?
in my full example I also have cases for CGPoint, CGSize, CGRect, CATransform3D
The limitations are just as you have stated, because of Swift's strict typing. All types must be definitely known at compile time, and each thing can be of only one type - even a generic (it is resolved by the way it is called at compile time). Thus, the only thing you can do is turn your type into into an umbrella type that is much more like Objective-C itself:
let condition = true
let evaluation = {
() -> NSObject in // *
if condition {
return 3
} else {
return NSValue(CGPoint:CGPointMake(0,1))
}
}

Pass Keyword in Swift

I know that the keyword "pass" in Python will allow one to leave a line of code empty where it should have contained an executable statement. Is there a similar keyword in Swift?
I am using a switch statement and Swift requires there to be a default case. The code should reach the default statement most of the time and I want nothing to be done in this case.
You can break out of the default case. Swift just wants you to be explicit about that to avoid bugs.
Here's a simple example:
enum Food {
case Banana
case Apple
case ChocolateBar
}
func warnIfUnhealthy(food : Food) {
switch food {
case .ChocolateBar:
println("Don't eat it!")
default:
break
}
}
let candy = Food.ChocolateBar
warnIfUnhealthy(candy)
The proper way to add a catch-all without an action to a switch statement is to add
default: break
at the end.