Difference between nil and () in Swift - swift

I noticed that the empty tuple () is used to represent an absence of value in Swift. For example, the signature of a function that returns nothing, is:
func zz(){
println("zz")
}
The compiler will also accept this body for the function above:
func zz(){
println("zap")
return () // returning () and returning nothing is the same thing!
}
An equivalent way of defining this function would be:
func zz() -> (){
println("zap")
return ()
}
There's even a typealias for () called Void:
typealias Void = ()
So if the empty tuple is the absence of value in Swift, what is its relationship with nil? Why do we need both concepts? is nil defend in terms of ()?

nil is a special value that you can assign to an Optional to mean the optional doesn't have a value. nil is not really the absence of a value, it's a special value that means no proper value
() means that nothing is returned (or passed in), not even an optional. There is no return value, nor can there ever be. You can't assign it to anything unlike a return value of nil.
The situation is analogous to the difference between (in C)
void foo(void);
and
SomeType* bar(void);
if the latter function uses a return value of NULL to indicate some sort of failure. i.e.
someVariable = foo(); // Illegal
someVariable = bar(); // Not illegal
if (someVariable != NULL) { ... }

nil is absence of value, () is a tuple with 0 elements. Conceptually the same as comparing nil with an empty array: an empty array is not absence of value.
They are simply 2 different and unrelated things.
Just try this in a playground:
var x: Int?
x = () // <== () is not convertible to Int
that produces an error.

Related

compactMap() closure fails when adding irrelevant NOP declaration?

Playground
XCode Version 13.3 (13E113)
Swift 5.6
First print of compactMap() closure displays this:
["What\'s", "Going", "On?"]
The second print displays this:
[(), (), ()]
Seems like if I declare anything inside the closure, the output of the closure changes.
print( "What's\nGoing\nOn?".split(separator:"\n").enumerated().compactMap
{ idx, lineText in
lineText
})
print( "What's\nGoing\nOn?".split(separator:"\n").enumerated().compactMap
{ idx, lineText in
let _ : String
lineText
})
Is there a way to wrap some of it to hide the other declaration?
Is the closure confused about the type?
Is there any way to unconfuse it (or me)?
Is it a Swift bug?
Issue is root of why other things I'm trying to with this pattern aren't working.
UPDATE
As per #Shadowrun's answer below, I added a return statement in the 3rd example, but that leads to compile time errors. So is that resolvable?
print( "What's\nGoing\nOn?".split(separator:"\n").enumerated().compactMap
{ idx, lineText in
let _ : String
return lineText
})
expression failed to parse:
error: test playground.playground:38:52: error: generic parameter 'ElementOfResult' could not be inferred
print( "What's\nGoing\nOn?".split(separator:"\n").enumerated().compactMap
^
Swift.Sequence:2:28: note: in call to function 'compactMap'
#inlinable public func compactMap<ElementOfResult>(_ transform: (Self.Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]</b>
If you have a one line closure there's an implicit return, so the first one is returning lineText which is of type string. See "Functions With an Implicit Return" at https://docs.swift.org/swift-book/LanguageGuide/Functions.html
The second one doesn't actually return anything, once it is more than one line, there is no implicit return. So the return type is Void which is also spelled as the empty tuple, () and that's what you get there.
You need to say return lineText explicitly if you mean to return something.
This function:
{ idx, lineText in
let _ : String
lineText // This line evaluates the value of lineText and does nothing with the result
}
does not return a value. Any function that doesn't return a value returns a Void value. Void is a type with only one possible value, called (). Mapping to void is a pointless thing to do. Even if your function did a side effect, like printing something, it wouldn't be good style to use map just for side effects.
You can guard against this kind of mistake by being more explicit about the return type in the closure
{ idx, lineText -> String in ... }

What is the function of = sign in this particular closure statement?

I'm new to Swift and is trying to learn the concept of closure. I saw this code online:
var sayHelloClosure: () -> () = {
print("hello from closure")
}
when I remove the = sign, the compiler output the error message:
Missing return in a function expected to return '() -> ()'
Could someone please tell me the use of = in this particular context?
Let's break that statement down:
var sayHelloClosure
Ok, we're creating a mutable variable
: () -> ()
It has a type of () -> (), a function with no arguments that returns void.
=
It's being set to something
{
print("hello from closure")
}
And that thing is a closure (basically a unnamed function) that takes no arguments and returns nothing (void)
Basically you now have a variable that points to a function that does what's in those braces.

Error message: initialiser for conditional binding must have optional type, not '()'

I am getting error:
initialiser for conditional binding must have optional type, not '()'.
Using Swift language, below is the code:
if let result = brain.performOperation(operation)
I think I can answer your question, but I don't know how much it will help you.
The way if let someVar = someOptional { } is used is to check the value of a variable (someOptional) to see if it is nil or a "value". If it is not nil then someVar will be assigned the non-nil value of someOptional and execute the code between { } which can safely reference someVar, knowing it is not nil. If someOptional is nil then the code within { } is bypassed and not executed.
The comment you posted above indicates that the performOperation() method is this:
func performOperation(symbol:String) {
if let operation = knownOps[symbol] {
opStack.append(operation)
}
}
This method does not return anything, or more formally it returns void aka (). void, or () is not a value, nor is it nil.
So when you have this statement
if let result = brain.performOperation(operation) { }
the compiler complains because it expects brain.performOperation(operation)
to return either nil or a value, but not void aka () which is exactly what the method returns.
If you are still confused about optionals, be sure to read as much as you can of the Swift Language Reference. Optionals are a big part of the language and once you get used to them you will find them very invaluable.

Swift - Optional Void

I was busy using NSURLProtocolClient's URLProtocol function:
welf?.client?.URLProtocol(welf!, didReceiveResponse: operation.response, cacheStoragePolicy: NSURLCacheStoragePolicy.NotAllowed)
I was expecting it to return Void. But to my surprise it returns Void?
Why is it necessary to make a distinction between Void and Void?
I have read that Void is a type alias for the empty tuple type. So, does this have something to do with a distinction between the empty tuple type vs nil?
This is simply because you are using Optional Chaining. The method returns Void, but it is possible for the whole chain to return nil before the method is ever called.
Essentially, a return value of Void will mean the call was actually made (self and client both have values) while a nil result will mean that one of those were nil.
Note that, () and nil is different:
let a:Void? = ()
let b:Void? = nil
a == nil // -> false
b == nil // -> true
Using this, you can judge the method has really been invoked or not.
let result = welf?.client?.URLProtocol(welf!, didReceiveResponse: operation.response, cacheStoragePolicy: NSURLCacheStoragePolicy.NotAllowed)
if result != nil {
// success
}
else {
// `welf?.client` was `nil`
}

swift, optional unwrapping, reversing if condition

Let's say I have function which returns optional. nil if error and value if success:
func foo() -> Bar? { ... }
I can use following code to work with this function:
let fooResultOpt = foo()
if let fooResult = fooResultOpt {
// continue correct operations here
} else {
// handle error
}
However there are few problems with this approach for any non-trivial code:
Error handling performed in the end and it's easy to miss something. It's much better, when error handling code follows function call.
Correct operations code is indented by one level. If we have another function to call, we have to indent one more time.
With C one usually could write something like this:
Bar *fooResult = foo();
if (fooResult == null) {
// handle error and return
}
// continue correct operations here
I found two ways to achieve similar code style with Swift, but I don't like either.
let fooResultOpt = foo()
if fooResult == nil {
// handle error and return
}
// use fooResultOpt! from here
let fooResult = fooResultOpt! // or define another variable
If I'll write "!" everywhere, it just looks bad for my taste. I could introduce another variable, but that doesn't look good either. Ideally I would like to see the following:
if !let fooResult = foo() {
// handle error and return
}
// fooResult has Bar type and can be used in the top level
Did I miss something in the specification or is there some another way to write good looking Swift code?
Your assumptions are correct—there isn't a "negated if-let" syntax in Swift.
I suspect one reason for that might be grammar integrity. Throughout Swift (and commonly in other C-inspired languages), if you have a statement that can bind local symbols (i.e. name new variables and give them values) and that can have a block body (e.g. if, while, for), those bindings are scoped to said block. Letting a block statement bind symbols to its enclosing scope instead would be inconsistent.
It's still a reasonable thing to think about, though — I'd recommend filing a bug and seeing what Apple does about it.
This is what pattern matching is all about, and is the tool meant for this job:
let x: String? = "Yes"
switch x {
case .Some(let value):
println("I have a value: \(value)")
case .None:
println("I'm empty")
}
The if-let form is just a convenience for when you don't need both legs.
If what you are writing is a set of functions performing the same sequence of transformation, such as when processing a result returned by a REST call (check for response not nil, check status, check for app/server error, parse response, etc.), what I would do is create a pipeline that at each steps transforms the input data, and at the end returns either nil or a transformed result of a certain type.
I chose the >>> custom operator, that visually indicates the data flow, but of course feel free to choose your own:
infix operator >>> { associativity left }
func >>> <T, V> (params: T?, next: T -> V?) -> V? {
if let params = params {
return next(params)
}
return nil
}
The operator is a function that receives as input a value of a certain type, and a closure that transforms the value into a value of another type. If the value is not nil, the function invokes the closure, passing the value, and returns its return value. If the value is nil, then the operator returns nil.
An example is probably needed, so let's suppose I have an array of integers, and I want to perform the following operations in sequence:
sum all elements of the array
calculate the power of 2
divide by 5 and return the integer part and the remainder
sum the above 2 numbers together
These are the 4 functions:
func sumArray(array: [Int]?) -> Int? {
if let array = array {
return array.reduce(0, combine: +)
}
return nil
}
func powerOf2(num: Int?) -> Int? {
if let num = num {
return num * num
}
return nil
}
func module5(num: Int?) -> (Int, Int)? {
if let num = num {
return (num / 5, num % 5)
}
return nil
}
func sum(params: (num1: Int, num2: Int)?) -> Int? {
if let params = params {
return params.num1 + params.num2
}
return nil
}
and this is how I would use:
let res: Int? = [1, 2, 3] >>> sumArray >>> powerOf2 >>> module5 >>> sum
The result of this expression is either nil or a value of the type as defined in the last function of the pipeline, which in the above example is an Int.
If you need to do better error handling, you can define an enum like this:
enum Result<T> {
case Value(T)
case Error(MyErrorType)
}
and replace all optionals in the above functions with Result<T>, returning Result.Error() instead of nil.
I've found a way that looks better than alternatives, but it uses language features in unrecommended way.
Example using code from the question:
let fooResult: Bar! = foo();
if fooResult == nil {
// handle error and return
}
// continue correct operations here
fooResult might be used as normal variable and it's not needed to use "?" or "!" suffixes.
Apple documentation says:
Implicitly unwrapped optionals are useful when an optional’s value is confirmed to exist immediately after the optional is first defined and can definitely be assumed to exist at every point thereafter. The primary use of implicitly unwrapped optionals in Swift is during class initialization, as described in Unowned References and Implicitly Unwrapped Optional Properties.
How about the following:
func foo(i:Int) ->Int? {
switch i {
case 0: return 0
case 1: return 1
default: return nil
}
}
var error:Int {
println("Error")
return 99
}
for i in 0...2 {
var bob:Int = foo(i) ?? error
println("\(i) produces \(bob)")
}
Results in the following output:
0 produces 0
1 produces 1
Error
2 produces 99