(Swift) nested function, function as return, argument - swift

Regarding the code below, I was wondering how nested functions such as stepForward, stepBackward, when they are actually called through 'moveNearerToZero(currentValue), take currentValue as their arguments.
According to the definition of the function chooseStepFunction, the return type is (Int) -> Int. Then, is it because of the parenthesis around Int that the nested functions are able to take currentValue as their arguments?
I can't undesrtand how the value of -4 of currentValue is captured in two nested functions.
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
func stepForward(input: Int) -> Int { return input + 1 }
func stepBackward(input: Int) -> Int { return input - 1 }
return backward ? stepBackward : stepForward
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
while currentValue != 0 {
print("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")

Functions in Swift are first class citizens. This means that functions can be passed around or stored like a variable, just like any other swift type.
Anything that follows the first -> is the type being returned by that method. In this case chooseStepFunction returns another method that takes one parameter (Int) and returns one value (Int). The parenthesis around the first Int, mean that it's an input parameter.
With that in mind, moveNearerToZero is function that takes one Int and returns another Int. To call that method, you then simply do moveNearerToZero(1) and so on.
I highly recommend you read Apple's section on functions to better understand how functions can be used or passed around.
https://docs.swift.org/swift-book/LanguageGuide/Functions.html

chooseStepFunction(backward: currentValue > 0) returns "stepForward" function. In "stepForward" function as the value is incremental by 1. So, first -4 is getting printed than -3(-4+1) is getting printed and so on until currentValue reaches 0 where the while loop terminates.

Related

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.

i cannot understand a method behaviour

func mymethod(getno:Int)->(myval :Int,defaults :Int){
return (getno,8)
}
print(mymethod(getno: 2))
the output for the above program is
my val is 2 default is 8
ok, i can understand above program
but the below method is doubtful for me
func makeIncrementer() -> ((Int) -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
var increment = makeIncrementer()
increment(7)
i can't understand this line (var increment=makeIncrementer()) what's happening there ?
Is there somebody who can explain me this briefly?
makeIncrementer returns a function that accepts an Int and return an Int , so this
var increment = makeIncrementer()
makes increment variable to be equal to
func addOne(number: Int) -> Int {
return 1 + number
}
so increment(7) = addOne(7)
You may read Functions chapter in Swift book
You are not alone. I found it hard to wrap my head around this when I first started as well :)
What you are seeing is "a function returning another function". Think of functions as black boxes that take stuff in and spit stuff out. Now imagine passing these around as if they were values like 10 or "Hello".
makeIncrementer returns a function. Which function? This:
func addOne(number: Int) -> Int {
return 1 + number
}
See the line return addOne? That is not calling the function, but returning it!
So when you assign the return value of makeIncrementer to increment:
var increment = makeIncrementer()
increment now has the value of addOne. Calling increment would be the same as calling addOne. The above line is syntactically no different from:
var myString = getMyString()
The difference is that you are working with functions instead of strings.
Now you understand why increment(7) is 8.
If you want to burn your brain more, try looking up currying functions.

Simple Pointer Operations in Swift?

Let's say I do the following in C++:
int i = 1;
int* ptr = &i;
*ptr = 2;
cout << i << '\n';
And I want to do something similar in swift. Could I do the following?
var i : Int = 1
var iptr : UnsafeMutablePointer<Int> = &i
iptr.memory = 2
print(i)
And achieve the same result?
Yes-ish.
You can't do it exactly as you've attempted in the question. It won't compile. Swift won't let you directly access the address of a value like this. At the end of the day, the reason is mostly because there's simply no good reason to do so.
We do see the & operator in Swift however.
First of all, there is the inout keyword when declaring function parameters:
func doubleIfPositive(inout value: Float) -> Bool {
if value > 0 {
value *= 2
return true
}
return false
}
And to call this method, we'd need the & operator:
let weMadeARadian = doubleIfPositive(&pi)
We can see it similarly used when we have a function which takes an argument of type UnsafeMutablePointer (and other variants of these pointer structs). In this specific case, it's primarily for interoperability with C & Objective-C, where we could declare a method as such:
bool doubleIfPositive(float * value) -> bool {
if (value > 0) {
value *= 2;
return true;
}
return false;
}
The Swift interface for that method ends up looking somethin like this:
func doubleIfPositive(value: UnsafeMutablePointer<Float>) -> Bool
And calling this method from Swift actually looks just like it did before when using the inout approach:
let weMadeARadian = doubleIfPositive(&pi)
But these are the only two uses of this & operator I can find in Swift.
With that said, we can write a function that makes use of the second form of passing an argument into a method with the & operator and returns that variable wrapped in an unsafe mutable pointer. It looks like this:
func addressOf<T>(value: UnsafeMutablePointer<T>) -> UnsafeMutablePointer<T> {
return value
}
And it behaves about as you'd expect from your original code snippet:
var i: Int = 1
var iPtr = addressOf(&i)
iPtr.memory = 2
print(i) // prints 2
As noted by Kevin in the comments, we can also directly allocate memory if we want.
var iPtr = UnsafeMutablePointer<Int>.alloc(1)
The argument 1 here is effectively the mount of space to allocate. This says we want to allocate enough memory for a single Int.
This is roughly equivalent to the following C code:
int * iPtr = malloc(1 * sizeof(int));
BUT...
If you're doing any of this for anything other than interoperability with C or Objective-C, you're most likely not Swifting correctly. So before you start running around town with pointers to value types in Swift, please, make sure it's what you absolutely need to be doing. I've been writing Swift since release, and I've never found the need for any of these shenanigans.
Like this (not the only way, but it's clear):
var i : Int = 1
withUnsafeMutablePointer(&i) {
iptr -> () in
iptr.memory = 2
}
print(i)
Not a very interesting example, but it is completely parallel to your pseudo-code, and we really did reach right into the already allocated memory and alter it, which is what you wanted to do.
This sort of thing gets a lot more interesting when what you want to do is something like cycle thru memory just as fast as doing pointer arithmetic in C.

Swift error "Cannot invoke 'makeNoise' with an argument type '((UInt32))'"

I have been doing some Swift coding and I got "Cannot invoke 'makeNoise' with an argument type '((UInt32))'". Here is the full code:
func makePetMakeNoise(){
var randomNumber = arc4random_uniform(9)
self.pet.makeNoise(randomNumber)
I am using arc4random_uniform(9) to make A random number between 1 and 9. How would I fix the error?
Your method call returns an Int, it doesn't accept one. Although, you never actually return from it. Based on what you have here, your call should be:
self.pet.makeNoise()
and the method declaration should be:
func makeNoise()
{
//Your if statement that prints stuff.
}
arc4random_uniform(UInt32) takes a UInt32 as an argument and returns a UInt32 which is not the same as your function takes. And according to the function you provided, it does not take a parameter so it does not work. Make the function take an Int(and adjust accordingly) or a UInt32 as a parameter then use the parameter. I'm not exactly sure what you're trying to do with Bool(canMakeNoise), but I think you're trying to check the random number against a given value?
function:
func makeNoise(x: Int) {
if x == 0 { // Or some value the pet can make
println("(name) (noise)")
} else {
println("(name) remains silent")
}
}
call:
let x = Int(arc4random_uniform(5)) // This is now an Int not a UInt32
makeNoise(x)

Function taking a variable number of arguments

In this document: https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/GuidedTour.html#//apple_ref/doc/uid/TP40014097-CH2-XID_1
It mentions that when creating for loops we can use the shorthand of 0..3 and 0...3 to replace i = 0; i < 3; ++i and i = 0; i <= 3; ++i respectively.
All very nice.
Further down the document in the Functions and Closures section it says that functions can have a variable number of arguments passed via an array.
However, in the code example we see the ... again.
func sumOf(numbers: Int...) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
Is this a mistake? It seems to me that a more intuitive syntax would be numbers: Int[].
A few examples down we see another code sample which has exactly that:
func hasAnyMatches(list: Int[], condition: Int -> Bool) -> Bool {
In case of all arguments are Int numbers: Int[] would be intuitive. But if you have code like this:
func foo(args:AnyObject...) {
for arg: AnyObject in args {
println(arg)
}
}
foo(5, "bar", NSView())
output:
5
bar
<NSView: 0x7fc5c1f0b450>
The type of parameter in sumOf are known as 'variadic' parameter.
The parameters passed are accepted just as a group of elements and is then converted into array before using it within that function.
A great example would be this post.
Passing lists from one function to another in Swift