overloading methods where only difference is optional vs. non-optional type - swift

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?) { ... }

Related

Optional extension for any types

I want to write Optional extension for any types.
My code for integer:
extension Optional where Wrapped == Int {
func ifNil<T>(default: T) -> T {
if self != nil {
return self as! T
}
return default
}
}
var tempInt: Int?
tempInt.ifNil(default: 2) // returns 2
tempInt = 5
tempInt.ifNil(default: 2) // returns 5
It works but it is Optional(Int) extension (Optional where Wrapped == Int), I want to use this extension for any types like Date, String, Double etc.
What are your suggestions?
The answer to your basic question is to just remove the where clause:
extension Optional {
// ... the rest is the same
func isNil<T>(value: T) -> T {
if self != nil {
return self as! T
}
return value
}
}
Now it applies to all Optionals.
But this code is quite broken. It crashes if T is not the same as Wrapped. So you would really mean a non-generic function that works on Wrapped:
extension Optional {
func isNil(value: Wrapped) -> Wrapped {
if self != nil {
return self! // `as!` is unnecessary
}
return value
}
}
But this is just an elaborate way of saying ?? (as matt points out)
extension Optional {
func isNil(value: Wrapped) -> Wrapped { self ?? value }
}
Except that ?? is much more powerful. It includes an autoclosure that avoids evaluating the default value unless it's actually used, and which can throw. It's also much more idiomatic Swift in most cases. You can find the source on github.
public func ?? <T>(optional: T?, defaultValue: #autoclosure () throws -> T)
rethrows -> T {
switch optional {
case .some(let value):
return value
case .none:
return try defaultValue()
}
}
But I can imagine cases where you might a method-based solution (they're weird, but maybe there are such cases). You can get that by just rewriting it as a method:
extension Optional {
public func value(or defaultValue: #autoclosure () throws -> Wrapped) rethrows -> Wrapped {
switch self {
case .some(let value):
return value
case .none:
return try defaultValue()
}
}
}
tempInt.value(or: 2)
Optional is already a generic. It already takes any type as its parameterized type. Its parameterized already has a name: Wrapped. Just say Wrapped instead of T. Your T is Wrapped.
extension Optional {
func isNil<Wrapped>(value: Wrapped) -> Wrapped {
if self != nil {
return self as! Wrapped
}
return value
}
}
If you really prefer T for some reason, use a type alias. It's only a name:
extension Optional {
typealias T = Wrapped
func isNil<T>(value: T) -> T {
if self != nil {
return self as! T
}
return value
}
}
But in any case your extension is completely unnecessary because this is what the nil-coalescing operator ?? already does.
var tempInt: Int?
tempInt ?? 2 /// returns 2
tempInt = 5
tempInt ?? 2 /// returns 5

Unable to return an optional as an optional

Why can't I get Swift to return a value as an optional.
I have a funtion that checks if an optional contains a value and return it as an optional if it isn't:
var someOptional: String?
func checkIfOptional<T>(value: T?) -> (String, T) {
if let _value = value {
return (("Your optional contains a value. It is: \(_value)"), (_value))
} else {
return (("Your optional did not contain a value"), (value?)) //ERROR: Value of optional type 'T?' not unwrapped; did you mean to use '!' or '?'?
}
}
When the optional is nil. Ist should return the same optional the was given to the function.
If there is a value. It should return the unwrapped value.
If you want to return an optional you have to declare the return type as optional
func checkIfOptional<T>(value: T?) -> (String, T?) {
if let _value = value {
return ("Your optional contains a value. It is: \(_value)", value)
} else {
return ("Your optional did not contain a value", value)
// or even return ("Your optional did not contain a value", nil)
}
I removed all unnecessary parentheses.
You may want to declare an enum like this:
enum Value<T> {
case full(String, T)
case empty(String, T?)
}
func checkIfOptional<T>(_ value: T?) -> Value<T> {
if let _value = value {
return .full("Your optional contains a value. It is: \(_value)", _value)
} else {
return .empty("Your optional did not contain a value.", value)
}
}
var toto: String?
print(checkIfOptional(toto)) // empty("Your optional did not contain a value", nil)
print(checkIfOptional("Blah")) // full("Your optional contains a value. It is: Blah", "Blah")
To treat a Value you should use switch this way:
var toto: String?
let empty = checkIfOptional(toto)
let full = checkIfOptional("Blah")
func treatValue<T>(_ value: Value<T>) {
switch(value) {
case .full(let msg, let val):
print(msg)
print(val)
case .empty(let msg, _):
print(msg)
}
}
treatValue(empty) // Your optional did not contain a value.
treatValue(full) // Your optional contains a value. It is: Blah\nBlah
But all of this seems to me to only add needless complexity to the straightforward type that is Optional. So you might want to expand on what you are trying to achieve here.

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

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) }

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) }

Check string for nil & empty

Is there a way to check strings for nil and "" in Swift? In Rails, I can use blank() to check.
I currently have this, but it seems overkill:
if stringA? != nil {
if !stringA!.isEmpty {
...blah blah
}
}
If you're dealing with optional Strings, this works:
(string ?? "").isEmpty
The ?? nil coalescing operator returns the left side if it's non-nil, otherwise it returns the right side.
You can also use it like this to return a default value:
(string ?? "").isEmpty ? "Default" : string!
You could perhaps use the if-let-where clause:
Swift 3:
if let string = string, !string.isEmpty {
/* string is not blank */
}
Swift 2:
if let string = string where !string.isEmpty {
/* string is not blank */
}
With Swift 5, you can implement an Optional extension for String type with a boolean property that returns if an optional string is empty or has no value:
extension Optional where Wrapped == String {
var isEmptyOrNil: Bool {
return self?.isEmpty ?? true
}
}
However, String implements isEmpty property by conforming to protocol Collection. Therefore we can replace the previous code's generic constraint (Wrapped == String) with a broader one (Wrapped: Collection) so that Array, Dictionary and Set also benefit our new isEmptyOrNil property:
extension Optional where Wrapped: Collection {
var isEmptyOrNil: Bool {
return self?.isEmpty ?? true
}
}
Usage with Strings:
let optionalString: String? = nil
print(optionalString.isEmptyOrNil) // prints: true
let optionalString: String? = ""
print(optionalString.isEmptyOrNil) // prints: true
let optionalString: String? = "Hello"
print(optionalString.isEmptyOrNil) // prints: false
Usage with Arrays:
let optionalArray: Array<Int>? = nil
print(optionalArray.isEmptyOrNil) // prints: true
let optionalArray: Array<Int>? = []
print(optionalArray.isEmptyOrNil) // prints: true
let optionalArray: Array<Int>? = [10, 22, 3]
print(optionalArray.isEmptyOrNil) // prints: false
Sources:
swiftbysundell.com - Extending optionals in Swift
objc.io - Swift Tip: Non-Empty Collections
Using the guard statement
I was using Swift for a while before I learned about the guard statement. Now I am a big fan. It is used similarly to the if statement, but it allows for early return and just makes for much cleaner code in general.
To use guard when checking to make sure that a string is neither nil nor empty, you can do the following:
let myOptionalString: String? = nil
guard let myString = myOptionalString, !myString.isEmpty else {
print("String is nil or empty.")
return // or break, continue, throw
}
/// myString is neither nil nor empty (if this point is reached)
print(myString)
This unwraps the optional string and checks that it isn't empty all at once. If it is nil (or empty), then you return from your function (or loop) immediately and everything after it is ignored. But if the guard statement passes, then you can safely use your unwrapped string.
See Also
Statements documentation
The Guard Statement in Swift 2
If you are using Swift 2, here is an example my colleague came up with, which adds isNilOrEmpty property on optional Strings:
protocol OptionalString {}
extension String: OptionalString {}
extension Optional where Wrapped: OptionalString {
var isNilOrEmpty: Bool {
return ((self as? String) ?? "").isEmpty
}
}
You can then use isNilOrEmpty on the optional string itself
func testNilOrEmpty() {
let nilString:String? = nil
XCTAssertTrue(nilString.isNilOrEmpty)
let emptyString:String? = ""
XCTAssertTrue(emptyString.isNilOrEmpty)
let someText:String? = "lorem"
XCTAssertFalse(someText.isNilOrEmpty)
}
var str: String? = nil
if str?.isEmpty ?? true {
print("str is nil or empty")
}
str = ""
if str?.isEmpty ?? true {
print("str is nil or empty")
}
I know there are a lot of answers to this question, but none of them seems to be as convenient as this (in my opinion) to validate UITextField data, which is one of the most common cases for using it:
extension Optional where Wrapped == String {
var isNilOrEmpty: Bool {
return self?.trimmingCharacters(in: .whitespaces).isEmpty ?? true
}
}
You can just use
textField.text.isNilOrEmpty
You can also skip the .trimmingCharacters(in:.whitespaces) if you don't consider whitespaces as an empty string or use it for more complex input tests like
var isValidInput: Bool {
return !isNilOrEmpty && self!.trimmingCharacters(in: .whitespaces).characters.count >= MIN_CHARS
}
If you want to access the string as a non-optional, you should use Ryan's Answer, but if you only care about the non-emptiness of the string, my preferred shorthand for this is
if stringA?.isEmpty == false {
...blah blah
}
Since == works fine with optional booleans, I think this leaves the code readable without obscuring the original intention.
If you want to check the opposite: if the string is nil or "", I prefer to check both cases explicitly to show the correct intention:
if stringA == nil || stringA?.isEmpty == true {
...blah blah
}
I would recommend.
if stringA.map(isEmpty) == false {
println("blah blah")
}
map applies the function argument if the optional is .Some.
The playground capture also shows another possibility with the new Swift 1.2 if let optional binding.
SWIFT 3
extension Optional where Wrapped == String {
/// Checks to see whether the optional string is nil or empty ("")
public var isNilOrEmpty: Bool {
if let text = self, !text.isEmpty { return false }
return true
}
}
Use like this on optional string:
if myString.isNilOrEmpty { print("Crap, how'd this happen?") }
Swift 3
For check Empty String best way
if !string.isEmpty{
// do stuff
}
Swift 3 solution
Use the optional unwrapped value and check against the boolean.
if (string?.isempty == true) {
// Perform action
}
You should do something like this:
if !(string?.isEmpty ?? true) { //Not nil nor empty }
Nil coalescing operator checks if the optional is not nil, in case it is not nil it then checks its property, in this case isEmpty. Because this optional can be nil you provide a default value which will be used when your optional is nil.
Based on this Medium post, with a little tweak for Swift 5, I got to this code that worked.
if let stringA, !stringA.isEmpty {
...blah blah
}
Although I understand the benefits of creating an extension, I thought it might help someone needing just for a small component / package.
You can create your own custom function, if that is something you expect to do a lot.
func isBlank (optionalString :String?) -> Bool {
if let string = optionalString {
return string.isEmpty
} else {
return true
}
}
var optionalString :String? = nil
if isBlank(optionalString) {
println("here")
}
else {
println("there")
}
Create a String class extension:
extension String
{ // returns false if passed string is nil or empty
static func isNilOrEmpty(_ string:String?) -> Bool
{ if string == nil { return true }
return string!.isEmpty
}
}// extension: String
Notice this will return TRUE if the string contains one or more blanks. To treat blank string as "empty", use...
return string!.trimmingCharacters(in: CharacterSet.whitespaces).isEmpty
... instead. This requires Foundation.
Use it thus...
if String.isNilOrEmpty("hello world") == true
{ print("it's a string!")
}
Swift 3
This works well to check if the string is really empty. Because isEmpty returns true when there's a whitespace.
extension String {
func isEmptyAndContainsNoWhitespace() -> Bool {
guard self.isEmpty, self.trimmingCharacters(in: .whitespaces).isEmpty
else {
return false
}
return true
}
}
Examples:
let myString = "My String"
myString.isEmptyAndContainsNoWhitespace() // returns false
let myString = ""
myString.isEmptyAndContainsNoWhitespace() // returns true
let myString = " "
myString.isEmptyAndContainsNoWhitespace() // returns false
Using isEmpty
"Hello".isEmpty // false
"".isEmpty // true
Using allSatisfy
extension String {
var isBlank: Bool {
return allSatisfy({ $0.isWhitespace })
}
}
"Hello".isBlank // false
"".isBlank // true
Using optional String
extension Optional where Wrapped == String {
var isBlank: Bool {
return self?.isBlank ?? true
}
}
var title: String? = nil
title.isBlank // true
title = ""
title.isBlank // true
Reference : https://useyourloaf.com/blog/empty-strings-in-swift/
This is a general solution for all types that conform to the Collection protocol, which includes String:
extension Optional where Wrapped: Collection {
var isNilOrEmpty: Bool {
self?.isEmpty ?? true
}
}
When dealing with passing values from local db to server and vice versa, I was having too much trouble with ?'s and !'s and what not.
So I made a Swift3.0 utility to handle null cases and i can almost totally avoid ?'s and !'s in the code.
func str(_ string: String?) -> String {
return (string != nil ? string! : "")
}
Ex:-
Before :
let myDictionary: [String: String] =
["title": (dbObject?.title != nil ? dbObject?.title! : "")]
After :
let myDictionary: [String: String] =
["title": str(dbObject.title)]
and when its required to check for a valid string,
if !str(dbObject.title).isEmpty {
//do stuff
}
This saved me having to go through the trouble of adding and removing numerous ?'s and !'s after writing code that reasonably make sense.
Use the ternary operator (also known as the conditional operator, C++ forever!):
if stringA != nil ? stringA!.isEmpty == false : false { /* ... */ }
The stringA! force-unwrapping happens only when stringA != nil, so it is safe. The == false verbosity is somewhat more readable than yet another exclamation mark in !(stringA!.isEmpty).
I personally prefer a slightly different form:
if stringA == nil ? false : stringA!.isEmpty == false { /* ... */ }
In the statement above, it is immediately very clear that the entire if block does not execute when a variable is nil.
helpful when getting value from UITextField and checking for nil & empty string
#IBOutlet weak var myTextField: UITextField!
Heres your function (when you tap on a button) that gets string from UITextField and does some other stuff
#IBAction func getStringFrom_myTextField(_ sender: Any) {
guard let string = myTextField.text, !(myTextField.text?.isEmpty)! else { return }
//use "string" to do your stuff.
}
This will take care of nil value as well as empty string.
It worked perfectly well for me.
Swift 5.6 - Xcode 13
extension Optional where Wrapped: Collection {
var isEmptyOrNil: Bool {
guard let self = self else { return true }
return self.isEmpty
}
}
Usage:
var name: String?
if name.isEmptyOrNil {
///true
}
name = "John Peter"
guard !name.isEmptyOrNil else { return }
/// Name is not empty
you can use this func
class func stringIsNilOrEmpty(aString: String) -> Bool { return (aString).isEmpty }