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

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.

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

Why does Swift think that my array is a function?

// Complete the miniMaxSum function below.
func birthdayCakeCandles(arr: [Int]) -> Int {
let a = arr.sorted
let highest = a().last!
return 0
}
birthdayCakeCandles(arr: [1, 7, 3, 12, 5])
I tried to create a sorted array "a" from an unsorted array "arr", to solve a problem from HackerRank. But compiler gives following error:
main.swift:5:19: error: function 'a' was used as a property; add () to
call it
let highest = a.last!
^
()
Why does it think, that "a" is a function?
error: function 'a' was used as a property; add () to call it
Swift doesn't think that your array is a function. Xcode just tells you, that sorted is a method and you have to call it with () at the end
let a = arr.sorted()
let a = arr.sorted
Why does it think, that "a" is a function?
Because that is just what it is. sorted is the name of a function. So a is now the sorted function.
What you want is for a to be the result of calling a function. But every function call involves parentheses, e.g. sorted(). You have no parentheses.
In short that line of your code talks about sorted. But it never calls sorted. It just renames it.
arr.sorted evaluates to a method of [Int]. If you want a sorted copy of the array call that method:
func birthdayCakeCandles(arr: [Int]) -> Int {
let a = arr.sorted()
let highest = a.last!
return 0
}
Otherwise, the compiler is right: a contains a function: The sorted method.
I believe what you want to do is the following:
func birthdayCakeCandles(arr: [Int]) -> Int {
return arr.max() ?? 0
}
In your code, a is not an array, it is a function with the following signature () -> [Int], because arr.sorted is an instance method. You can check the type of a variable by Alt + clicking on the variable in Xcode. To execute this function you need to invoke it using (). Which you are doing in the following line. The output of a() is an array of integers, on which you are calling the last property.
If your arr is empty, .last! will cause an error/app crash, since you'd be unwrapping nil (there is no last element in an empty array). This is why in the suggested code above, I've used the nil-coalescing operator ??, which would guarantee that the function would return 0 if the array arr is empty.
For more in-depth reading on instance methods, have a look here.

Difference between nil and () in 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.

What is this swift declaration doing?

According to the author of this page this is declaring a dictionary of dictionaries in swift:
var routeMap : Dictionary<String, Dictionary<String, () -> ()>> = [:]
can you explain what are this doing, specially the part with these hieroglyphs () -> ()>> = [:] at the end?
It appears that the guy is joining a series of commands together. If this is the case, if you can unfold that code into several lines I appreciate.
thanks.
Let's start at the way end.
[:]
This is simply initializing an empty Dictionary. It is very similar to calling "" to initialize an empty String, or [] to initialize an empty Array.
Now, let's jump to the type declaration.
Dictionary<String, Dictionary<String, () -> ()>>
This is a dictionary that maps Strings to Dictionaries. Let's look closer at the type of those inner dictionaries.
Dictionary<String, () -> ()>
This maps a String to a closure. A closure is pretty much just a block from Objective C. That's what the () -> () means. Let's dive deeper.
() -> ()
This is the syntax for declaring a closure. The left value are the parameters. The right are the return types. In this case, we have one parameter, and one return type.
()
This means void in Swift. In fact, in Swift.h, we can see this on line 3953:
typealias Void = ()
So ultimately, we have a closure that gives no (void) parameters, and has no (void) return value.
Some more examples of closures might help understand the syntax. Let's imagine a closure that takes a String and converts it to an int. The type would look like this:
let stringToInt: (String) -> (Int) = ...
Now, one with a void input. Let's have a random number generator:
let randomDouble: () -> (Double) = ...
This takes no inputs, and returns a Double.
Finally, let's have a void to void.
let printHelloWorld: () -> () = ...
You can see this takes no arguments and returns nothing. It's more of a method than a function, but it can still do stuff, like modify properties, or in this case, print to the console.

Is there any way to not return something using CoffeeScript?

It seems like CoffeeScript automatically returns the last item in a scope. Can I avoid this functionality?
You have to explicitly return nothing, or to leave an expression evaluating to undefined at the bottom of your function:
fun = ->
doSomething()
return
Or:
fun = ->
doSomething()
undefined
This is what the doc recommends, when using comprehensions:
Be careful that you're not accidentally returning the results of the comprehension in these cases, by adding a meaningful return value — like true — or null, to the bottom of your function.
You could, however, write a wrapper like this:
voidFun = (fun) ->
->
fun(arguments...)
return
(Notice the splat operator here (...))
And use it like this when defining functions:
fun = voidFun ->
doSomething()
doSomethingElse()
Or like this:
fun = voidFun(->
doSomething()
doSomethingElse()
)
Yes , with a return as the last line of a function.
For example,
answer = () ->
42
extrovert = (question) ->
answer()
introvert = (question) ->
x = answer()
# contemplate about the answer x
return
If you'd like to see what js the coffee compiles to, look at this. (I've used coffeescript redux for my example)
Just something fun(ctional)
suppressed = _.compose Function.prototype, -> 'do your stuff'
Function.prototype itself is a function that always return nothing. You can use compose to pipe your return value into this blackhole and the composed function will never return anything.
longRunningFunctionWithNullReturn = ->
longRunningFunction()
null
It seems functions in CoffeeScript must always return something, even null. In C, you have void as a return type.
->, the empty function, compiles to (function() {}), so it's the only function that doesn't return anything.