I've been trying to figure out what is going on to no avail. I've distilled the code as much as possible but I still get the "Result of operator && is unused warning (even though it is used) if I do it in a project but the same code copied to Playground is working fine with no warnings. This is just some dummy code, after me rewriting the basic code again while trying to find the problem.
enum WordError: Error {
case tooShort
case tooLong
}
func isTooShort(_ word: String) throws -> Bool {
if word.count < 3 { throw WordError.tooShort }
return true }
func isTooLong(_ word: String) throws -> Bool {
if word.count > 5 { throw WordError.tooLong }
return true }
func check(_ word: String) {
do {
try isTooShort(word) && isTooLong(word)
print(word)
} catch let error as WordError {
print("\(error)")
} catch {
}
}
Is this just a bug or am I doing something wrong here?
I figured I can silence the warning if I use:
try _ = isTooShort(word) && isTooLong(word)
But I'm not sure whether that's the right way of 'patching' it.
There is nothing wrong with doing it that way. The "right" way, when something like isTooShort belongs to you and you want to call it without capturing the result, is to mark it with #discardableResult. If you did that, then you could write
do {
try isTooShort(word)
try isTooLong(word)
print(word) // if we get here, it's neither too short nor too long
} catch ...
But what you're doing is also "right" in these circumstances.
The real question is why you would both return a Bool and throw an error. Your implementation of isTooShort is very odd. You seem to be misusing throw. It isn't clear what problem you are trying to solve by implementing it in this odd way. isTooShort can only fail one way: the word is too short. So why doesn't it just return a Bool? isTooShort asks a simple yes/no question, so just answer it: return a Bool and stop.
If your goal is to answer a three-way question - i.e., to tell the caller whether this word was too short, too long, or just right, then again, just return a custom enum that answers the question:
enum WordLength {
case tooShort
case tooLong
case justRight
}
func howIs(_ word: String) -> WordLength {
if word.count < 3 { return .tooShort }
if word.count > 5 { return .tooLong }
return .justRight
}
Related
I would like to figure out how to pattern match against an enum-with-associated-value property of an error type in a catch. Everything works as expected with an enum without associated values, but I can't seem to figure out the correct pattern for this situation.
struct MyError: Error {
enum Size {
case big, small
}
enum Solution {
case runAway
case other(String)
}
let size: Size
let solution: Solution
}
func action() {
do {
// ...
}
catch let error as MyError where error.size == .big {
// This works fine, as `size` has no associated values.
}
catch let error as MyError where error.solution == .other {
// I want to handle all cases of `Solution.other` here, regardless of the associated value.
}
catch {
// ...
}
}
The second catch pattern won't compile (as expected due to the enum with associated value). The usual way I'd accomplish this would be a if case .runAway = error.solution {...}, but integrating this in the catch pattern is the problem.
I tried many combinations of if case/let case/case let, but couldn't get this working in a single catch pattern matching statement. This feels like it should be possible given the power and flexibility of pattern matching, so I'm hoping I've just overlooked something.
Thanks for the assistance!
This feels possible, but isn't :/. What you are trying to use is an enum case pattern. According to here, an enum case pattern is only allowed in switch, if, while, guard, and for statements.
You can add an isOther property in Solution:
var isOther: Bool {
if case .other = self {
return true
} else {
return false
}
}
And then use it in the catch:
do {
// ...
}
catch let error as MyError where error.size == .big {
// ...
}
catch let error as MyError where error.solution.isOther {
// ...
}
catch {
// ...
}
There are 2 things which should be fixed in your sample:
To compare cases of an enum it should be equitable, isn't it? For such a simple enum just mark Solution as Equitable.
Default case for a catch isn't handled, so you need to add it, eg:
do {
...
}
catch let error as MyError where error.size == .big {
// This works fine, assizehas no associated values.
}
catch let error as MyError where error.solution == .runAway {
// I want to accomplish this comparison.
}
catch let error {
...
}
I have been attempting to optimize some Swift code and am seeing this trace:
308.00 ms 10.2% 25.00 ms swift_deallocClassInstance
I have no idea what is causing it and trying to figure out what would be dealloc-ing in the method. Has anyone seen this come up in profile or know what is causing it. It is showing up in this method. I've looked through for any sort class type vars but can't seem to pin it down. One of the methods is using some static struct OptionSet but those I wouldn't think would cause it. All other parameters passed are Ints
It is over 50% of the actual method and 10% of the overall trace:
final func generateTextures(options: TextureOptions, baseLevel: Int) -> [AreaData] {
otherMethodCall();
methodCall()
for i in 0..<size {
...
}
for i in 0..<width {
switch someVar {
...
default:
switch someVar {
...
}
}
}
for i in stride(from: width - 1, to: size, by: width) {
switch someVar {
....
default:
switch someVar{
...
}
}
}
// post processing
for i in 0..<size {
... method
}
for i in 0..<size {
..some more stuff
}
for i in 0..<size {
..some more stuff
}
anotherMethod()
return someMethod()
}
I removed all of the option set use in the method and went directly to raw Int's and this huge hit went away. I had hoped they compiled down option sets to int or the raw value operations directly, I guess not.
I am reading MirrorType at nshipster,and trying to adopt it's code to Swift 2.1. Everything works fine until when I tried to custom the _MirrorTypewith :
extension WWDCSession : _Reflectable {
func _getMirror() -> _MirrorType {
return WWDCSessionMirror(self)
}
}
An error occured :
error: Playground execution aborted: Execution was interrupted,
reason: EXC_BAD_ACCESS (code=2, address=0x7fff58273e87).
And I found out it's because the init method in WWDCSessionMirror was being called infinite times.
struct WWDCSessionMirror: _MirrorType {
private let _value: WWDCSession
init(_ value: WWDCSession) {
_value = value
}
var value: Any { return _value }
var valueType: Any.Type { return WWDCSession.self }
var objectIdentifier: ObjectIdentifier? { return nil }
var disposition: _MirrorDisposition { return .Struct }
var count: Int { return 4 }
subscript(index: Int) -> (String, _MirrorType) {
switch index {
case 0:
return ("number", _reflect(_value.number))
case 1:
return ("title", _reflect(_value.title))
case 2:
return ("track", _reflect(_value.track))
case 3:
return ("summary", _reflect(_value.summary))
default:
fatalError("Index out of range")
}
}
var summary: String {
return "WWDCSession \(_value.number) [\(_value.track.rawValue)]: \(_value.title)"
}
var quickLookObject: PlaygroundQuickLook? {
print(summary)
return .Text(summary)
}
}
I want to ask why it happened , and how to fix it?
_Reflectable and _MirrorType are not the droids you're looking for.
They are legacy types, which have been superseded by CustomReflectable (among others). The 2015 WWDC session about LLDB goes into some detail about this (disclaimer: I am the speaker of that part of that session, so conflict of interests all around :-)
But, anyway, the issue you're running into is because of this line:
_value = value
Since you're typing this line in your playground, that tells the playground logic to capture for display ("log" in playground parlance) the thing you're assigning. To do so, the playground uses the Mirror attached to that type. So, we go off and create one, which causes us to run
_value = value
again, which tells the playground logic to log value, which then means we create a Mirror, ...
You should first of all check if you can adopt Mirror and CustomReflectable instead of _MirrorType and if using those APIs fixes your problem. If it doesn't a possible workaround is to put the reflection support code in an auxiliary source file which will cause the playground logic to not log things inside of it.
I give it a try to understand new error handling thing in swift 2. Here is what I did: I first declared an error enum:
enum SandwichError: ErrorType {
case NotMe
case DoItYourself
}
And then I declared a method that throws an error (not an exception folks. It is an error.). Here is that method:
func makeMeSandwich(names: [String: String]) throws -> String {
guard let sandwich = names["sandwich"] else {
throw SandwichError.NotMe
}
return sandwich
}
The problem is from the calling side. Here is the code that calls this method:
let kitchen = ["sandwich": "ready", "breakfeast": "not ready"]
do {
let sandwich = try makeMeSandwich(kitchen)
print("i eat it \(sandwich)")
} catch SandwichError.NotMe {
print("Not me error")
} catch SandwichError.DoItYourself {
print("do it error")
}
After the do line compiler says Errors thrown from here are not handled because the enclosing catch is not exhaustive. But in my opinion it is exhaustive because there is only two case in SandwichError enum.
For regular switch statements swift can understands it is exhaustive when every case handled.
There are two important points to the Swift 2 error handling model: exhaustiveness and resiliency. Together, they boil down to your do/catch statement needing to catch every possible error, not just the ones you know you can throw.
Notice that you don't declare what types of errors a function can throw, only whether it throws at all. It's a zero-one-infinity sort of problem: as someone defining a function for others (including your future self) to use, you don't want to have to make every client of your function adapt to every change in the implementation of your function, including what errors it can throw. You want code that calls your function to be resilient to such change.
Because your function can't say what kind of errors it throws (or might throw in the future), the catch blocks that catch it errors don't know what types of errors it might throw. So, in addition to handling the error types you know about, you need to handle the ones you don't with a universal catch statement -- that way if your function changes the set of errors it throws in the future, callers will still catch its errors.
do {
let sandwich = try makeMeSandwich(kitchen)
print("i eat it \(sandwich)")
} catch SandwichError.NotMe {
print("Not me error")
} catch SandwichError.DoItYourself {
print("do it error")
} catch let error {
print(error.localizedDescription)
}
But let's not stop there. Think about this resilience idea some more. The way you've designed your sandwich, you have to describe errors in every place where you use them. That means that whenever you change the set of error cases, you have to change every place that uses them... not very fun.
The idea behind defining your own error types is to let you centralize things like that. You could define a description method for your errors:
extension SandwichError: CustomStringConvertible {
var description: String {
switch self {
case NotMe: return "Not me error"
case DoItYourself: return "Try sudo"
}
}
}
And then your error handling code can ask your error type to describe itself -- now every place where you handle errors can use the same code, and handle possible future error cases, too.
do {
let sandwich = try makeMeSandwich(kitchen)
print("i eat it \(sandwich)")
} catch let error as SandwichError {
print(error.description)
} catch {
print("i dunno")
}
This also paves the way for error types (or extensions on them) to support other ways of reporting errors -- for example, you could have an extension on your error type that knows how to present a UIAlertController for reporting the error to an iOS user.
I suspect this just hasn’t been implemented properly yet. The Swift Programming Guide definitely seems to imply that the compiler can infer exhaustive matches 'like a switch statement'. It doesn’t make any mention of needing a general catch in order to be exhaustive.
You'll also notice that the error is on the try line, not the end of the block, i.e. at some point the compiler will be able to pinpoint which try statement in the block has unhandled exception types.
The documentation is a bit ambiguous though. I’ve skimmed through the ‘What’s new in Swift’ video and couldn’t find any clues; I’ll keep trying.
Update:
We’re now up to Beta 3 with no hint of ErrorType inference. I now believe if this was ever planned (and I still think it was at some point), the dynamic dispatch on protocol extensions probably killed it off.
Beta 4 Update:
Xcode 7b4 added doc comment support for Throws:, which “should be used to document what errors can be thrown and why”. I guess this at least provides some mechanism to communicate errors to API consumers. Who needs a type system when you have documentation!
Another update:
After spending some time hoping for automatic ErrorType inference, and working out what the limitations would be of that model, I’ve changed my mind - this is what I hope Apple implements instead. Essentially:
// allow us to do this:
func myFunction() throws -> Int
// or this:
func myFunction() throws CustomError -> Int
// but not this:
func myFunction() throws CustomErrorOne, CustomErrorTwo -> Int
Yet Another Update
Apple’s error handling rationale is now available here. There have also been some interesting discussions on the swift-evolution mailing list. Essentially, John McCall is opposed to typed errors because he believes most libraries will end up including a generic error case anyway, and that typed errors are unlikely to add much to the code apart from boilerplate (he used the term 'aspirational bluff'). Chris Lattner said he’s open to typed errors in Swift 3 if it can work with the resilience model.
Swift is worry that your case statement is not covering all cases, to fix it you need to create a default case:
do {
let sandwich = try makeMeSandwich(kitchen)
print("i eat it \(sandwich)")
} catch SandwichError.NotMe {
print("Not me error")
} catch SandwichError.DoItYourself {
print("do it error")
} catch Default {
print("Another Error")
}
I was also disappointed by the lack of type a function can throw, but I get it now thanks to #rickster and I'll summarize it like this: let's say we could specify the type a function throws, we would have something like this:
enum MyError: ErrorType { case ErrorA, ErrorB }
func myFunctionThatThrows() throws MyError { ...throw .ErrorA...throw .ErrorB... }
do {
try myFunctionThatThrows()
}
case .ErrorA { ... }
case .ErrorB { ... }
The problem is that even if we don't change anything in myFunctionThatThrows, if we just add an error case to MyError:
enum MyError: ErrorType { case ErrorA, ErrorB, ErrorC }
we are screwed because our do/try/catch is no longer exhaustive, as well as any other place where we called functions that throw MyError
enum NumberError: Error {
case NegativeNumber(number: Int)
case ZeroNumber
case OddNumber(number: Int)
}
extension NumberError: CustomStringConvertible {
var description: String {
switch self {
case .NegativeNumber(let number):
return "Negative number \(number) is Passed."
case .OddNumber(let number):
return "Odd number \(number) is Passed."
case .ZeroNumber:
return "Zero is Passed."
}
}
}
func validateEvenNumber(_ number: Int) throws ->Int {
if number == 0 {
throw NumberError.ZeroNumber
} else if number < 0 {
throw NumberError.NegativeNumber(number: number)
} else if number % 2 == 1 {
throw NumberError.OddNumber(number: number)
}
return number
}
Now Validate Number :
do {
let number = try validateEvenNumber(0)
print("Valid Even Number: \(number)")
} catch let error as NumberError {
print(error.description)
}
Error can be handle using switch case in catch
func checkAge(age:Int) throws {
guard !(age>0 && age < 18) else{
throw Adult.child
}
guard !(age >= 60) else{
throw Adult.old
}
guard (age>0) else{
throw Adult.notExist
}
}
do{
try checkAge(age:0)
}
catch let error {
switch error{
case Adult.child : print("child")
case Adult.old : print("old")
case Adult.notExist : print("not Exist")
default:
print("default")
}
}
enum Adult:Error {
case child
case old
case notExist
}
Create enum like this:
//Error Handling in swift
enum spendingError : Error{
case minus
case limit
}
Create method like:
func calculateSpending(morningSpending:Double,eveningSpending:Double) throws ->Double{
if morningSpending < 0 || eveningSpending < 0{
throw spendingError.minus
}
if (morningSpending + eveningSpending) > 100{
throw spendingError.limit
}
return morningSpending + eveningSpending
}
Now check error is there or not and handle it:
do{
try calculateSpending(morningSpending: 60, eveningSpending: 50)
} catch spendingError.minus{
print("This is not possible...")
} catch spendingError.limit{
print("Limit reached...")
}
func head<T>(xs: [T]) -> T {
if (xs.count > 0) {
return xs.first!
} else {
NSException(name:"empty list", reason:"empty list", userInfo:nil).raise()
}
}
This code does not compile (compiler is expecting every branch to have a return statement and does not recognize NSException as control statement).
How can I change my code to make it compile?
P.S. I don't want to change return value to Optional
Could you reformat your NSException to something that does compile?
Try the answer for this question: Calling NSException.raise() in Swift
I needed fatalError("")
func head<T>(xs: [T]) -> T {
if (xs.count > 0) {
return xs.first!
} else {
fatalError("list is empty")
}
}
this code works just fine.