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
}
}
Related
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.
I am trying to make a dispatch function which can take Payload as an argument. The Payload can be Int, String or any other type. I tried the following approaches but inside the dispatch function the payload.value is always T and not Int or String. Casting is an option but I thought that was the whole point of generics.
struct Payload<T> {
let value: T
}
func dispatch<T>(payload: Payload<T>) {
print(payload.value) // get the value as Int, String or some other type
}
let payload = Payload<Int>(value: 100)
let payload2 = Payload<String>(value: "FOO")
dispatch(payload: payload)
dispatch(payload: payload2)
As you already know T is unconstrained so it can be any type. Your only option is to cast the value to the types you are expecting. You can simply switch the value:
switch payload.value {
case let value as Int:
print("Int:", value)
case let value as String:
print("String:", value)
default:
print("some other type", payload.value)
}
Depends on what you want to get inside your dispatch, you can create a protocol and requires T to be conformed to that protocol.
protocol Printable {
func printValue() -> String
}
struct Payload<T> {
let value: T
}
func dispatch<T: Printable>(payload: Payload<T>) {
print(payload.value.printValue()) // get the value as Int, String or some other type
}
extension String: Printable {
func printValue() -> String {
return self
}
}
extension Int: Printable {
func printValue() -> String {
return "\(self)"
}
}
I was under the impression that swift can have overloaded methods that differ only in the type of object that the methods return. I would think that I could have two funcs with the same signature yet they differ in return type.
import Foundation
// ambiguous use of 'IsTextEmpty(text:)'
func IsTextEmpty(text : String?) -> Bool? {
return text?.isEmpty
}
func IsTextEmpty(text : String?) -> Bool {
guard let text = text else {
return true
}
return text.isEmpty
}
let text: String? = nil
if let empty = IsTextEmpty(text:"text") {
print("Not Empty")
}
if IsTextEmpty(text: text) {
print("Empty")
}
Here, both functions have the same input parameters but one func returns an optional Bool? and the other returns a Bool. In this case I get an error:
ambiguous use of 'IsTextEmpty(text:)'
If I change the name of one of the input parameters I no longer get the ambiguous error:
// Works
func IsTextEmpty(foo : String?) -> Bool? {
return foo?.isEmpty
}
func IsTextEmpty(text : String?) -> Bool {
guard let text = text else {
return true
}
return text.isEmpty
}
let text: String? = nil
if let empty = IsTextEmpty(foo:"text") {
print("Not Empty")
}
if IsTextEmpty(text: text) {
print("Empty")
}
Shouldn't the compiler detect that they are two distinct methods even though their return types are different, since an optional Bool? is a different type from a non-optional Bool?
The compiler needs some context to decide which method to call, e.g.
let e1 = IsTextEmpty(text: text) as Bool
let e2: Bool = IsTextEmpty(text: text)
to call the non-optional variant, or
let e3 = IsTextEmpty(text: text) as Bool?
let e4: Bool? = IsTextEmpty(text: text)
to call the optional variant. Now
if IsTextEmpty(text: text) {
print("Empty")
}
compiles without problems: the if-statement requires a boolean
expression, so there is no ambiguity here.
But apparently the compiler is not smart enough to figure out that
in the context of an optional binding the expression on the right-hand side must be some optional
and to infer the unwrapped type automatically.
You need to annotate the type of empty explicitly:
if let empty: Bool = IsTextEmpty(text: text) { ... }
or to make the return type explicit:
if let empty = (IsTextEmpty(text: text) as Bool?) { ... }
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) }
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) }