if let with try? gives optional value [duplicate] - swift

I am using an SQLite library in which queries return optional values as well as can throw errors. I would like to conditionally unwrap the value, or receive nil if it returns an error. I'm not totally sure how to word this, this code will explain, this is what it looks like:
func getSomething() throws -> Value? {
//example function from library, returns optional or throws errors
}
func myFunctionToGetSpecificDate() -> Date? {
if let specificValue = db!.getSomething() {
let returnedValue = specificValue!
// it says I need to force unwrap specificValue,
// shouldn't it be unwrapped already?
let specificDate = Date.init(timeIntervalSinceReferenceDate: TimeInterval(returnedValue))
return time
} else {
return nil
}
}
Is there a way to avoid having to force unwrap there? Prior to updating to Swift3, I wasn't forced to force unwrap here.
The following is the actual code. Just trying to get the latest timestamp from all entries:
func getLastDateWithData() -> Date? {
if let max = try? db!.scalar(eventTable.select(timestamp.max)){
let time = Date.init(timeIntervalSinceReferenceDate: TimeInterval(max!))
// will max ever be nil here? I don't want to force unwrap!
return time
} else {
return nil
}
}

Update: As of Swift 5, try? applied to an optional expression does not add another level of optionality, so that a “simple” optional binding is sufficient. It succeeds if the function did not throw an error and did not return nil. val is then bound to the unwrapped result:
if let val = try? getSomething() {
// ...
}
(Previous answer for Swift ≤ 4:) If a function throws and returns an optional
func getSomething() throws -> Value? { ... }
then try? getSomething() returns a "double optional" of the
type Value?? and you have to unwrap twice:
if let optval = try? getSomething(), let val = optval {
}
Here the first binding let optval = ... succeeds if the function did
not throw, and the second binding let val = optval succeeds
if the return value is not nil.
This can be shortened with case let pattern matching to
if case let val?? = try? getSomething() {
}
where val?? is a shortcut for .some(.some(val)).

I like Martin's answer but wanted to show another option:
if let value = (try? getSomething()) ?? nil {
}
This has the advantage of working outside of if, guard, or switch statements. The type specifier Any? isn't necessary but just included to show that it returns an optional:
let value: Any? = (try? getSomething()) ?? nil

Related

Forwarding function generic parameter to generic class type

I have created enum with associated value and I want to be able to dynamically update associated value. As far as I know Swift doesn't support that at the moment.
Because of that I used following approach:
enum PersonInfo {
class EnumValue<T> {
var value: T
init(_ value: T) {
self.value = value
}
}
// Instead of using String or Bool or any other type directly, use EnumValue wrapper
case firstName(EnumValue<String>)
case lastName(EnumValue<String>)
case isAdult(EnumValue<Bool>)
}
I want to add function that would update EnumValue.value property in following way:
func updateAssociatedValue<V>(_ updateValue: V) {
let mirror = Mirror(reflecting: self)
for associatedValue in mirror.children {
guard let value = associatedValue.value as? EnumValue<V> else {
continue
}
value.value = updateValue
}
}
Problem is that this guard statement always fails (guard let value = associatedValue.value as? EnumValue<V>) and I can't figure it out why.
On the other hand, when I write updateAssociatedValue with typed type then things work properly:
// This works
func updateAssociatedValue(_ updateValue: String) {
let mirror = Mirror(reflecting: self)
for associatedValue in mirror.children {
guard let value = associatedValue.value as? EnumValue<String> else {
continue
}
value.value = updateValue
}
}
Things compile normally but during the runtime guard statement always fails. Am I using generic value in some incorrect way? Should I use somehow updateValue.Type or updateValue.self (I tried but it didn't work).
Example of usage:
var array: [PersonInfo] = [
.firstName(PersonInfo.EnumValue("John")),
.lastName(PersonInfo.EnumValue("Doe")),
.isAdult(PersonInfo.EnumValue(false))
]
print(array)
// John, Doe, false
array.first?.updateAssociatedValue("Mike")
print(array)
// Mike, Doe, false
I can always reassign enum value in array but if possible I want to avoid that. That's the reason for asking this question.

Is If let Evaluated Differently from If Statement?

Is if let kind of if statement, or is if let different?
Does the compiler treat if let and if statement differently?
if let is for unwrapping optional values.
if is for evaluating a condition
var example: String? = "rick"
if let name = example{
print(name) //name is the unwrapped version of example
}
If example is nil (no value), then the if let statement will fall through and the code inside of it will not run.
var example: Bool = true
if example{
print("Example is true")
} else{
print("Example is false")
}

Can I use "guard let" if you want to pass over an optional string to "rawValue:" in enum in Swift?

I want to initialize a enum from a variable of type String?, like:
guard let rawId = request.queryParameters["id"] else {
return
}
guard let id = MyIdentifier(rawValue: rawId) else {
return
}
In this case, request.queryParameters["id"] returns String?. Then after I ensure that it is String in rawId, I convert it into an enum instance id.
However, the code is dirty and I want to write it in one-line if at all possible.
However, I don't like to make it unwrapped via forced optional unwrapping, because if it can not be transformed to String, the app would end up with an error, since rawValue: only takes String. I meant something like the following, which I don't like:
guard let id = MyIdentifier(rawValue: request.queryParameters["id"]!) else {
return
}
So is it still possible to define the guard let in one-line, maybe using where and/or case in guard?
You have two conditions there, trying to combine them into one condition is not always possible.
In your exact case I believe an empty id will behave the same as a nil id, therefore nil coalescing can be used:
guard let id = MyIdentifier(rawValue: request.queryParameters["id"] ?? "") else {
return
}
However, there is nothing dirty about splitting two checks into two statements. Code is not written to be short, it's written to be clear:
guard let rawId = request.queryParameters["id"],
let id = MyIdentifier(rawValue: rawId) else
return
}
Also, there is nothing wrong with creating a custom initializer for your enum:
init?(id: String?) {
guard let id = id else {
return nil
}
self.init(rawValue: id)
}
and then
guard let id = MyIdentifier(id: request.queryParameters["id"]) else {
return
}
Try this:
You can simply combine both the statements into a single statement ,i.e,
guard let id = request.queryParameters["id"], let id2 = MyIdentifier(rawValue: id) else {
return
}

Function throws AND returns optional.. possible to conditionally unwrap in one line?

I am using an SQLite library in which queries return optional values as well as can throw errors. I would like to conditionally unwrap the value, or receive nil if it returns an error. I'm not totally sure how to word this, this code will explain, this is what it looks like:
func getSomething() throws -> Value? {
//example function from library, returns optional or throws errors
}
func myFunctionToGetSpecificDate() -> Date? {
if let specificValue = db!.getSomething() {
let returnedValue = specificValue!
// it says I need to force unwrap specificValue,
// shouldn't it be unwrapped already?
let specificDate = Date.init(timeIntervalSinceReferenceDate: TimeInterval(returnedValue))
return time
} else {
return nil
}
}
Is there a way to avoid having to force unwrap there? Prior to updating to Swift3, I wasn't forced to force unwrap here.
The following is the actual code. Just trying to get the latest timestamp from all entries:
func getLastDateWithData() -> Date? {
if let max = try? db!.scalar(eventTable.select(timestamp.max)){
let time = Date.init(timeIntervalSinceReferenceDate: TimeInterval(max!))
// will max ever be nil here? I don't want to force unwrap!
return time
} else {
return nil
}
}
Update: As of Swift 5, try? applied to an optional expression does not add another level of optionality, so that a “simple” optional binding is sufficient. It succeeds if the function did not throw an error and did not return nil. val is then bound to the unwrapped result:
if let val = try? getSomething() {
// ...
}
(Previous answer for Swift ≤ 4:) If a function throws and returns an optional
func getSomething() throws -> Value? { ... }
then try? getSomething() returns a "double optional" of the
type Value?? and you have to unwrap twice:
if let optval = try? getSomething(), let val = optval {
}
Here the first binding let optval = ... succeeds if the function did
not throw, and the second binding let val = optval succeeds
if the return value is not nil.
This can be shortened with case let pattern matching to
if case let val?? = try? getSomething() {
}
where val?? is a shortcut for .some(.some(val)).
I like Martin's answer but wanted to show another option:
if let value = (try? getSomething()) ?? nil {
}
This has the advantage of working outside of if, guard, or switch statements. The type specifier Any? isn't necessary but just included to show that it returns an optional:
let value: Any? = (try? getSomething()) ?? nil

Use guard-let to modify possibly nil expression before assigning variable

I wish to use guard-let to assign a variable to an expression, but I want to modify the expression before assigning. If the expression is nil, then the else block should be entered, otherwise the variable should be assigned to f(expression). Here is an example of what I would like to do:
let arr: [Int] = []
// Do stuff, maybe add elements to arr
guard let x = abs(arr.first) else { return } // Syntax error
// If arr was nonempty, then we want x = abs(arr.first!)
But Swift does not allow this syntax because abs requires a non-optional argument, and arr.first is optional. So is there any way to evaluate arr.first, and then if it is not nil to assign abs(arr.first!) to x? I know that I could do this with if-let or by using two variables (one from the guard-let and then one that gets assigned to the absolute value of that variable). But guard-let seems like the tool for the job, if only there were some way to accomplish this.
let arr:[Int] = [-1,1,3,-9]
guard let x = arr.first.flatMap({ $0 < 0 ? -$0: $0 }) else { return }
// ...
or (UPDATE based on dfri's notes)
// ....
let arr:[Int] = [-1,1,3,-9]
guard let x = arr.first.map(abs) else { return }
Optional(Some<Int>) -> Int -> Optional<abs(Some<Int)> -> Int ... meh
You could do a dirty guard let ..., let ... else fix as follows (forcing the binded certainly-not-nil value of x to become an optional which you subsequently immediately unwrap and bind to xAbs)
func foo() {
let arr: [Int] = [-1, 2, -3, 4]
guard let x = arr.first,
let xAbs = Optional(abs(xAbs)) else { return }
print(xAbs, xAbs.dynamicType)
}
foo() // 1 Int
This doesn't look very pretty however, and I would, personally, prefer adding an Int extension and make use of optional chaining, as I will cover next.
Instead: use extensions and optional chaining
Unless you explicitly need to store x as well as xAbs, an alternative and more Swifty approach is to use optional chaining in combination with a simple extension to Int:
extension Int {
var absValue: Int { return abs(self) }
}
func foo() {
let arr: [Int] = [-1, 2, -3, 4]
guard let xAbs = arr.first?.absValue else { return }
print(xAbs, xAbs.dynamicType)
}
foo() // 1 Int
Since arr.first is an optional Int variable, you can implement whatever method/computed property you wish onto self as an extension to Int, and access that method/property using optional chaining arr.first?.someMethod()/arr.first?.someProperty (as .absValue above).
Or, simply modify your arr.first (unwrapped) value after the guard let ... else block
I see no reason, however (other than the technical discussion) not to introduce an additional immutable holding the absolute value of x. This will also increase code readability, at least w.r.t. to the dirty guard let ..., let ... else fix above.
// ...
guard let x = arr.first else { return }
let xAbs = abs(x)
Or, if you find it acceptable for your xAbs property to be mutable, out of a theoretical perspective your could remove the middle-man immutable by using a guard var ... block rather than guard let ...
guard var xAbs = arr.first else { return }
xAbs = abs(xAbs)
This should probably only be used, however, if xAbs is to be mutated again (i.e., use immutables whenever you really don't need mutables, and never the other way around).
I think the cleanest and simplest solution would be like this:
guard let first = arr.first else { return }
let x = abs(first)
Now the calculation abs(first) is only reached if arr.first != nil.
What you want can be achieved using case let.
let arr: [Int] = [1,2,3,4]
guard let first = arr.first, case let absolute = abs(first) else { return }
// use `absolute`