Chaining type(of:) with an optional type in swift 3 [duplicate] - swift

does anyone have a (better) way to do this?
Lets say I have a optional Float
let f: Float? = 2
Now I want to cast it to a Double
let d = Double(f) //fail
This will obviously fail but is there a way to chain the optional through the function like you can with calculated variables? What I am doing now is this:
extension Float {
var double: Double { return Double(self) }
}
let d: Double? = f?.double
But I really do not like putting a cast as a calculated variable.
Another option I have considered using is this:
public func optionalize<A,B>(_ λ : #escaping (A) -> B) -> (A?) -> B? {
return { (a) in
guard let a = a else { return nil }
return λ(a)
}
}
let d: Double? = optionalize(Double.init)(f)
I realize I can guard the value of 'f' to unwrap it. However in many cases the optional value will be the parameter for a function that returns an optional. This leads to intermediate values in the guard. As seen in this example:
func foo(_ a: String?) throws -> Float {
guard
let a = a,
let intermediate = Float(a)
else { throw.something }
return intermediate
}
Here it is possible for the cast from String to Float to fail also.
At least with a calculated variable this foo function is a bit cleaner
extension String {
var float: Float? { return Float(self) }
}
func foo(_ a: String?) throws -> Float {
guard
let a = a?.float
else { throw.something }
return a
}
I do not want to rewrite optional versions of frequent inits.
Any ideas will be much appreciated. Thanks!

You can simply use Optional's map(_:) method, which will return the wrapped value with a given transform applied if it's non-nil, else it will return nil.
let f : Float? = 2
// If f is non-nil, return the result from the wrapped value passed to Double(_:),
// else return nil.
let d = f.map { Double($0) }
Which, as you point out in the comments below, can also be said as:
let d = f.map(Double.init)
This is because map(_:) expects a transformation function of type (Float) -> Double in this case, and Double's float initialiser is such a function.
If the transform also returns an optional (such as when converting an String to a Int), you can use flatMap(_:), which simply propagates a nil transform result back to the caller:
let s : String? = "3"
// If s is non-nil, return the result from the wrapped value being passed to the Int(_:)
// initialiser. If s is nil, or Int($0) returns nil, return nil.
let i = s.flatMap { Int($0) }

Related

Double Extension Swift

I am trying to create an iOS Swift extension in a playground to the Double type that implements a method titled add that receives a String and returns an optional Double (Double?).
Extend the Double type, using an extension, and add a method called add that takes a String as a parameter with no label and returns a Double?.
If the String parameter can be turned into a Double, return the String’s Double value plus the value of the Double on which add is being called. If the String cannot be turned into a Double, return nil.
For testing this code I need to use:
let value1: Double? = 3.5.add("1.2") //value should be 4.7
let value3: Double? = 1.5.add("words") //value should be nil
extension Double {
func add(_ value: String) -> Double? {
guard let someNum = Double?(self) else {
return nil
}
return (someNum + value)
}
}
https://i.stack.imgur.com/VLM2E.png
Looks like you got a little confused about what to unwrap in your guard statement and what needed to be turned from a String into a Double. In your current code, you try to turn self, which is already a Double into a Double? -- then, you try to add that Double? to a String.
Here's a fixed version:
extension Double {
func add(_ value: String) -> Double? {
guard let numValue = Double(value) else {
return nil
}
return self + numValue
}
}

Shorter Alternative to ternary to generate empty string if nil?

I have a parameter of Type Double?.
When this parameter is nil, I want to have an empty string.
I can use if (variable == nil) ? "" : String(variable!) but is there a shorter alternative?
Using Optional.map and the nil-coalescing operator ?? you can do
var variable: Double? = 1.0
let string = variable.map { String($0) } ?? ""
The closure is called (and the string returned) if the variable is not nil, otherwise map returns nil and the expression evaluates to the empty string.
I don't see a simple way to simplify your code. An idea is to create a Double extension like this:
extension Optional where Wrapped == Double {
var asString: String {
self == nil ? "" : String(self!)
}
}
And then instead of that if condition you just use:
variable.asString
If you want to use the resulting string in another string, like this:
let string = "The value is: \(variable)"
and possibly specify what to print when variable is nil :
let string = "The value is: \(variable, nil: "value is nil")"
you can write a handy generic extension for String.StringInterpolation which takes any type of value and prints this and if it's an optional and also nil it prints the specified "default" string:
extension String.StringInterpolation {
mutating func appendInterpolation<T>(_ value: T?, `nil` defaultValue: #autoclosure () -> String) {
if let value = value {
appendLiteral("\(value)")
} else {
appendLiteral(defaultValue())
}
}
}
Example:
var d: Double? = nil
print("Double: \(d, nil: "value is nil")")
d = 1
print("Double: \(d, nil: "value is nil")")
let i = 1
print("Integer: \(i, nil: "value is nil")")
Output on the console:
Double: value is nil
Double: 1.0
Integer: 1
Just for fun a generic approach to cover all types that conforms to LosslessStringConvertible:
extension LosslessStringConvertible {
var string: String { .init(self) }
}
extension Optional where Wrapped: LosslessStringConvertible {
var string: String { self?.string ?? "" }
}
var double = Double("2.7")
print(double.string) // "2.7\n"
Property wrappers should help you give the desired result - property wrappers have a special variables wrappedValue and projectedValue that can add a layer of separation and allow you to wrap your custom logic.
wrappedValue - manipulate this variable with getters and setters. It has very less use in our case as it is of Double? type
projectedValue - this is going to be our focus as we can use this variable to project the Double as a String in our case.
The implementation is as below
#propertyWrapper
struct DoubleToString {
private var number: Double = 0.0
var projectedValue: String = ""
var wrappedValue: Double?{
get {
return number // Not really required
}
set {
if let value = newValue { // Check for nil
projectedValue = value.description // Convert to string
number = value
}
}
}
}
Now we create a struct which uses this wrapper.
struct NumbersTest {
#DoubleToString var number1: Double?
#DoubleToString var number2: Double?
}
On running the below code, we get the desired result. $number1 gives us the projectedValue and if we ignore the $ symbol we get the wrappedvalue
var numbersTest = NumbersTest()
numbersTest.number1 = 25.0
numbersTest.number2 = nil
print(numbersTest.$number1) //"25.0"
print(numbersTest.$number2) //""
By using property wrappers you can keep the variable interoperable to get both Double and String values easily.

Swift - unwrapping a Double value with a Guard let statement

to unwrap a Double from my default values, I seem to have to do it with two guard let statements to unwrap the value safely such as in what follows:
guard let distanceAwayPreference = self.defaults.string(forKey: "distancePreference") else {
return
}
guard let doubleDAP = Double(distanceAwayPreference) else {
return
}
– because if I do it like this:
guard let DistanceAwayPreference = self.defaults.double(forKey: "distancePreference") else {
return
}
– I get the error:
Initializer for conditional binding must have Optional type, not 'Double'
Is there a better way so i can do it once, or have less code throughout my app?
The method double(forKey:) is not returning an optional at all. According to the documentation it returns:
The double value associated with the specified key. If the key doesn‘t exist, this method returns 0.
So you can't optional bind it to a variable. This is why you've got that error:
Initializer for conditional binding must have Optional type, not 'Double'
For less and cleaner code (when using it), you can use a simple property wrapper like:
#propertyWrapper
struct UserDefault<T> {
let key: String
let defaultValue: T
init(_ key: String, defaultValue: T) {
self.key = key
self.defaultValue = defaultValue
}
var wrappedValue: T {
get { UserDefaults.standard.object(forKey: key) as? T ?? defaultValue }
set { UserDefaults.standard.set(newValue, forKey: key) }
}
}
Then you can have a custom helper struct like this:
struct UserDefaultsConfig {
#UserDefault("distancePreference", defaultValue: 0)
static var distancePreference: Double
}
And use it late like:
UserDefaultsConfig.distancePreference = 12
I think it's better to return Any from defaults instead of String. So, this way you can use optional casting.
guard let doubleDAP = self.defaults.object(forKey: "distancePreference") as? Double else {
return
}

Propagate an optional through a function (or Init) in Swift

does anyone have a (better) way to do this?
Lets say I have a optional Float
let f: Float? = 2
Now I want to cast it to a Double
let d = Double(f) //fail
This will obviously fail but is there a way to chain the optional through the function like you can with calculated variables? What I am doing now is this:
extension Float {
var double: Double { return Double(self) }
}
let d: Double? = f?.double
But I really do not like putting a cast as a calculated variable.
Another option I have considered using is this:
public func optionalize<A,B>(_ λ : #escaping (A) -> B) -> (A?) -> B? {
return { (a) in
guard let a = a else { return nil }
return λ(a)
}
}
let d: Double? = optionalize(Double.init)(f)
I realize I can guard the value of 'f' to unwrap it. However in many cases the optional value will be the parameter for a function that returns an optional. This leads to intermediate values in the guard. As seen in this example:
func foo(_ a: String?) throws -> Float {
guard
let a = a,
let intermediate = Float(a)
else { throw.something }
return intermediate
}
Here it is possible for the cast from String to Float to fail also.
At least with a calculated variable this foo function is a bit cleaner
extension String {
var float: Float? { return Float(self) }
}
func foo(_ a: String?) throws -> Float {
guard
let a = a?.float
else { throw.something }
return a
}
I do not want to rewrite optional versions of frequent inits.
Any ideas will be much appreciated. Thanks!
You can simply use Optional's map(_:) method, which will return the wrapped value with a given transform applied if it's non-nil, else it will return nil.
let f : Float? = 2
// If f is non-nil, return the result from the wrapped value passed to Double(_:),
// else return nil.
let d = f.map { Double($0) }
Which, as you point out in the comments below, can also be said as:
let d = f.map(Double.init)
This is because map(_:) expects a transformation function of type (Float) -> Double in this case, and Double's float initialiser is such a function.
If the transform also returns an optional (such as when converting an String to a Int), you can use flatMap(_:), which simply propagates a nil transform result back to the caller:
let s : String? = "3"
// If s is non-nil, return the result from the wrapped value being passed to the Int(_:)
// initialiser. If s is nil, or Int($0) returns nil, return nil.
let i = s.flatMap { Int($0) }

Compare value and return a bool in Swift

I am converting my code from Objective-C to Swift. I declared a function to compare values of two properties and return a Bool.
And I am confused about why this code not work in Swift.
private var currentLineRange: NSRange?
var location: UInt?
func atBeginningOfLine() -> Bool {
return self.location! == self.currentLineRange?.location ? true : false
}
Compiler gave me an error:
Could not find an overload for == that accepts the supplied arguments
Thanks.
You have two optional values and you want to check if they’re equal. There is a version of == for comparing two optionals – but they need to be of the same type.
The main problem here is that you are comparing NSRange.location, which is a Int, with location, which is a UInt. If you tried to do this even without the complication of the optionals, you’d get an error:
let ui: UInt = 1
let i: Int = 1
// error: binary operator '==' cannot be applied to operands of
// type 'Int' and ‘UInt'
i == ui
There’s two ways you can go. Either change location to be an Int, and you’ll be able to use the optional ==:
private var currentLineRange: NSRange?
var location: Int?
func atBeginningOfLine() -> Bool {
// both optionals contain Int, so you can use == on them:
return location == currentLineRange?.location
}
Or, if location really does need to be a UInt for some other reason, map one of the optionals to the type of the other to compare them:
private var currentLineRange: NSRange?
var location: UInt?
func atBeginningOfLine() -> Bool {
return location.map { Int($0) } == currentLineRange?.location
}
One thing to be careful of – nil is equal to nil. So if you don’t want this (depends on the logic you’re going for), you need to code for it explicitly:
func atBeginningOfLine() -> Bool {
if let location = location, currentLineRange = currentLineRange {
// assuming you want to stick with the UInt
return Int(location) == currentLineRange.location
}
return false // if either or both are nil
}
Swift has operator overloading, so == is a function. You have to define a function that takes your two types.
If you remove the UInt it works:
class Document {
private var currentLineRange: NSRange?
var location: Int?
func atBeginningOfLine() -> Bool {
if let currentLocation = self.location, lineRange = self.currentLineRange {
return currentLocation=lineRange?.location
} else {
return false
}
}
}
Modified to be null safe.