Functional Programming Course- Swift Functions and Swift Closure Tutorial 5.7

 

In this latest swift article we will look at how swift functional programming, closure programming, swift function, methods and swift closures are declared and used within swift programming language tutorial.


What is a Swift Function?

A function in swift is a named block of code that can be called upon to perform a specific task. It can be provided data on which to perform the task and is capable of returning results to the code that called it. 

For swift example, if a particular arithmetic calculation needs to be performed in a Swift program, the code to perform the arithmetic can be placed in a function. The function can be programmed to accept the values on which the arithmetic is to be performed (referred to as parameters) and to return the result of the calculation. At any point in the program code where the calculation is required the function is simply called, parameter values passed through as arguments and the result returned through as  call by value and call by reference in c


What is a Method in swift programming?

A method is essentially a swift function that is associated with a particular class, structure or enumeration. If, for swift example, you declare a function within a Swift class. 


Functions and Closures in Swift | A Basic Tutorial ; Closure Scope Chain:



How to Declare a Swift Function?

A Swift function is declared using the following syntax: 

func <function name> (<para name>: <para type>,
    // Function code

This combination of function name, parameters and return type are referred to as the function signature. Explanations of the various fields of the function declaration are as follows.

• func – The prefix keyword used to notify the Swift compiler that this is a function.
<function name> - The name assigned to the function. This is the name by which the function will be use.

referenced when it is called from within the application code.

<para name> - The name by which the parameter is to be referenced in the function code. <para type> - The type of the corresponding parameter.

<return type> - The data type of the result returned by the function. If the function does not return a result then no return type is specified.

Function code - The code of the function that does the work.

As an example, the following function takes no parameters, returns no result and simply displays a message:

func sayHello() {
    print("Hello")
}

The following swift example function, on the other hand, takes an integer and a string as parameters and returns a string result:

func buildMessageFor(name: String, count: Int) -> String {
       return("\(name), you are customer number \(count)")
}


What is an implicit return Swift Apple programming language?

Implicit Returns from Single Expressions:- 

In the previous swift functional example, the return statement was used to return the string value from within the buildMessageFor() function. It is worth noting that if a function contains a single expression, the return statement may be omitted. The buildMessageFor() method could, therefore, be rewritten as follows.

func buildMessageFor(name: String, count: Int) -> String {
       return("\(name), you are customer number \(count)")
}

The return statement can only be omitted if the function contains a single expression. The following coding functions, for example, will fail to compile since the function contains two expressions requiring the use of the return statement.

func buildMessageFor(name: String, count: Int) -> String {
       let uppername = name.uppercased()
       "\(uppername), you are customer number \(count)" // Invalid expression
}


How do you call a function argument in Swift?

Calling a Swift Function:

Once declared, swift functions are called using the following syntax.

<function name> (<arg1>, <arg2>, ... )

Each argument passed through to a function must match the parameters the function is configured to accept. For swift example, to call a function named sayHello that takes no parameters and returns no value, we would write the following code function.

sayHello()


Handling Return Values:

To call a function named buildMessageFor that takes two parameters and returns a result, on the other hand, we might write the following code.

let message = buildMessageFor(name: "John", count: 100)

In the above example, we have created a new variable called message and then used the assignment operator (=) to store the result returned by the function.


What does _: mean in Swift?

When developing in Swift, situations may arise where the result returned by a method or function call is not used. When this is the case, the return value may be discarded by assigning it to "_". the underscore operator (_) represents an unnamed parameter/label. For swift example

_ = buildMessageFor(name: "John", count: 100)


Function External And Internal Parameter Name Swift Example:

Internal names for swift function-

When the preceding example functions were declared, they were configured with parameters that were assigned names which, in turn, could be referenced within the body of the function code. When declared in this way, these names are referred to as swift local parameter names.

What is external parameter Swift?

In addition to local names, function parameters may also have external parameter names. These are the names by which the parameter is referenced when the function is called. By default, function parameters are assigned the same local and external parameter names. Consider, for example, the previous call to the buildMessageFor swift method.

let message = buildMessageFor(name: "John", count: 100)

As declared, the function uses "name" and "count" as both the local and swift external parameter names.

The default external parameter names assigned to parameters may be removed by preceding the local parameter names with an underscore (_) character as follows. 

func buildMessageFor(_ name: String, _ count: Int) -> String {
       return("\(name), you are customer number \(count)")
}

With this change implemented, the function may now be called as follows.

let message = buildMessageFor("John", 100)

Alternatively, external parameter names can be added simply by declaring the external parameter name before the local parameter name within the function declaration. In the following code, for example, the external names of the first and second parameters have been set to "username" and "usercount" respectively.

func buildMessageFor(username name: String, usercount count: Int) -> String {
       return("\(name), you are customer number \(count)")
}

When declared in this way, the external parameter name must be referenced when calling the swift function.

func buildMessageFor(username name: String, usercount count: Int) -> String {
       return("\(name), you are customer number \(count)")
}

Regardless of the fact that the external names are used to pass the arguments through when calling the function, the local names are still used to reference the parameters within the body of the function. It is important to also note that when calling a function using external parameter names for the arguments, those arguments must still be placed in the same order as that used when the function was declared.


What is the default parameter of a function?

Declaring Default swift Function Parameters:-

Swift provides the ability to designate a default parameter value to be used in the event that the value is not provided as an argument when the function is called. This simply involves assigning the default value to the parameter when the function is declared. Swift also provides a default external name based on the local parameter name for defaulted parameters (unless one is already provided) which must then be used when calling the function.

To see default parameters in action the buildMessageFor function will be modified so that the string “Customer” is used as a default in the event that a customer name is not passed through as an argument.

func buildMessageFor(_ name: String = "Customer", count: Int ) -> String
{
    return ("\(name), you are customer number \(count)")
}

The function can now be called without passing through a name argument.

let message = buildMessageFor(count: 100)
print(message)

When executed, the above function call will generate output to the console panel which reads.

Customer, you are customer 100


How to return multiple values from a function in Swift iOS?

Returning Multiple Results from a Function called Tuple :

A function can return multiple result values by wrapping those results in a tuple. A tuple allows you to group together multiple values of different types which can then be returned from a function as a single entity.

The following function takes as a parameter a measurement value in inches. The function converts this value into yards, centi meters and meters, returning all three results within a single tuple instance.

func sizeConverter(_ length: Float) -> (yards: Float, centimeters: Float,
                                        meters: Float) {
    let yards = length * 0.0277778
    let centimeters = length * 2.54
    let meters = length * 0.0254
    return (yards, centimeters, meters)
}

The return type for the function indicates that the function returns a tuple containing three values named yards, centi meters and meters respectively, all of which are of type Float.

-> (yards: Float, centimeters: Float, meters: Float)

Having performed the conversion, the function simply constructs the tuple instance and returns it. Usage of this function might read as follows.

let lengthTuple = sizeConverter(20)
print(lengthTuple.yards)
print(lengthTuple.centimeters)
print(lengthTuple.meters)


Variable Numbers of Function Parameters:-

It is not always possible to know in advance the number of parameters a function will need to accept when it is called within application code. Swift handles this possibility through the use of variadic parameters. Variadic parameters are declared using three periods (...) to indicate that the function accepts zero or more parameters of a specified data type. Within the body of the function, the parameters are made available in the form of an array object. The following function, for swift example, takes as parameters a variable number of String values and then outputs them to the console panel.

func displayStrings(_ strings: String...)
{
    for string in strings {
        print(string)
} }
displayStrings("one", "two", "three", "four")


Swift function with parameters as Variables:-

All swift parameters accepted by a function are treated as constants by default. This prevents changes being made to those parameter values within the function code. If changes to parameters need to be made within the function body, therefore, shadow copies of those parameters must be created. The following function, for example, is passed length and width parameters in inches, creates shadow variables of the two values and converts those parameters to centimeters before calculating and returning the area value.

func calcuateArea(length: Float, width: Float) -> Float {
    var length = length
    var width = width
    length = length * 2.54
    width = width * 2.54
    return length * width
}
print(calcuateArea(length: 10, width: 20))

Working with In-Out Parameters:-

When a variable is passed through as a parameter to a function, we now know that the parameter is treated as a constant within the body of that function. We also know that if we want to make changes to a parameter value we have to create a shadow copy as outlined in the above section. Since this is a copy, any changes made to the variable are not, by default, reflected in the original variable. Consider, for example, the following code:

var myValue = 10
func doubleValue (_ value: Int) -> Int {
    var value = value
    value += value
    return(value)
}
print("Before function call myValue = \(myValue)")
print("doubleValue call returns \(doubleValue(myValue))")
print("After function call myValue = \(myValue)")

The code begins by declaring a variable named myValue initialized with a value of 10. A new function is then declared which accepts a single integer parameter. Within the body of the function, a shadow copy of the value is created, doubled and returned.

The remaining lines of code display the value of the myValue variable before and after the function call is made. When executed, the following output will appear in the console:

Before function call myValue = 10
doubleValue call returns 20
After function call myValue = 10

Clearly, the function has made no change to the original myValue variable. This is to be expected since the mathematical operation was performed on a copy of the variable, not the myValue variable itself.

In order to make any changes made to a parameter persist after the function has returned, the parameter must be declared as an in-out parameter within the function declaration. To see this in action, modify the doubleValue function to include the inout keyword, and remove the creation of the shadow copy as follows:

func doubleValue (_ value: inout Int) -> Int { var value = value
value += value
return(value)
}

Finally, when calling the function, the inout parameter must now be prefixed with an & modifier:

print("doubleValue call returned \(doubleValue(&myValue))")

Having made these changes, a test run of the code should now generate output clearly indicating below.

Before function call myValue = 10
doubleValue call returns 20
After function call myValue = 20

function modified the value assigned to the original myValue variable.

Swift Functions as Parameters:-

An interesting feature of functions within Swift is that they can be treated as data types. It is perfectly valid, for example, to assign a function to a constant or variable as illustrated in the declaration below:

func inchesToFeet (_ inches: Float) -> Float {
    return inches * 0.0833333
}
let toFeet = inchesToFeet

The above swift coding declares a new function named inchesToFeet and subsequently assigns that function to a constant named toFeet. Having made this assignment, a call to the function may be made using the constant name instead of the original function name:

let result = toFeet(10)

In the above example, since the function accepts a floating-point parameter and returns a floating-point result, the function’s data type conforms to the following:

(Float) -> Float

A function which accepts an Int and a Double as parameters and returns a String result, on the other hand, would have the following data type:

(Int, Double) -> String

In order to accept a function as a parameter, the receiving function simply declares the data type of the function it is able to accept.

For the purposes of an example, we will begin by declaring two unit conversion functions and assigning them to constants:

func inchesToFeet (_ inches: Float) -> Float {
    return inches * 0.0833333
}
func inchesToYards (_ inches: Float) -> Float {
    return inches * 0.0277778
}
let toFeet = inchesToFeet
let toYards = inchesToYards

The swift example now needs an additional function swift. In order to demonstrate functions as parameters, this new function will take as a parameter a function type that matches both the inchesToFeet and inchesToYards function data type together with a value to be converted. Since the data type of these functions is equivalent to (Float) -> Float, our general-purpose function can be written as follows:

func outputConversion(_ converterFunc: (Float) -> Float, value: Float) {
    let result = converterFunc(value)
    print("Result of conversion is \(result)")
}

When the outputConversion function is called, it will need to be passed a function matching the declared data type. That function will be called to perform the conversion and the result displayed in the console panel. This means that the same function can be called to convert inches to both feet and yards. For swift example-

outputConversion(toYards, value: 10) // Convert to Yards
outputConversion(toFeet, value: 10) // Convert to Inches

Functions can also be returned as a data type simply by declaring the type of the function as the return type. The following function is configured to return either our toFeet or toYards function type (in other words a function which accepts and returns a Float value) based on the value of a Boolean parameter:

func decideFunction(_ feet: Bool) -> (Float) -> Float
{
if feet {
return toFeet
} else {
        return toYards
    }
}


Swift Closure Expressions:-

Having covered the basics of functions in Swift it is now time to look at the concept of closures and closure

expressions. Although these terms are often used interchangeably there are some key differences.
Closure expressions are self-contained blocks of code. The following code, for example, declares a closure

expression and assigns it to a constant named sayHello and then calls the function via the constant reference:

let sayHello = { print("Hello") }
sayHello()

Closure expressions may also be configured to accept parameters and return results. The syntax for this is as follows:

{(<para name>: <para type>, <para name> <para type>, ... ) ->
         // Closure expression code here
}
<return type> in

The following swift closure expression, for example, accepts two integer parameters and returns an integer result:

let multiply = {(_ val1: Int, _ val2: Int) -> Int in
}   return val1 * val2
let result = multiply(10, 20)

Note that the syntax is similar to that used for declaring Swift functions with the exception that the closure expression does not have a name, the parameters and return type are included in the braces and the in keyword is used to indicate the start of the closure expression code. Functions are, in fact, just named closure expressions.

Closure expressions are often used when declaring completion handlers for asynchronous method calls. In other words, when developing iOS applications, it will often be necessary to make calls to the operating system where the requested task is performed in the background allowing the application to continue with other tasks. Typically, in such a scenario, the system will notify the application of the completion of the task and return any results by calling the completion handler that was declared when the method was called. Frequently the code for the completion handler will be implemented in the form of a closure expression. Consider the following code example:

eventstore.requestAccess(to: .reminder, completion: {(granted: Bool,
                    error: Error?) -> Void in
    if !granted {
            print(error!.localizedDescription)
    }
})

When the tasks performed by the requestAccess(to:) method call are complete it will execute the closure expression declared as the completion: parameter. The completion handler is required by the method to accept a Boolean value and an Error object as parameters and return no results, hence the following declaration:

{(granted: Bool, error: Error?) -> Void in

In actual fact, the Swift compiler already knows about the parameter and return value requirements for the completion handler for this method call and is able to infer this information without it being declared in the closure expression. This allows a simpler version of the closure expression declaration to be written:

eventstore.requestAccess(to: .reminder, completion: {(granted, error) in if !granted {
            print(error!.localizedDescription)
    }
})

Shorthand Argument Names:-

A useful technique for simplifying closures involves using shorthand argument names. This allows the parameter names and “in” keyword to be omitted from the declaration and the arguments to be referenced as $0, $1, $2 etc.

Consider, for example, a closure expression designed to concatenate two strings:

let join = { (string1: String, string2: String) -> String in
    string1 + string2
}

Using shorthand argument names, this declaration can be simplified as follows:

let join: (String, String) -> String = {
$0 + $1 }

Note that the type declaration ((String, String) -> String) has been moved to the left of the assignment operator since the closure expression no longer defines the argument or return types.

Closures in Swift:-

A closure in computer science terminology generally refers to the combination of a self-contained block of code (for example a function or closure expression) and one or more variables that exist in the context surrounding that code block. Consider, for example the following Swift function:

func functionA() -> () -> Int {
    var counter = 0
    func functionB() -> Int {
    }   return counter + 10
    return functionB
}
let myClosure = functionA()
let result = myClosure()

In the above code, functionA returns a function named functionB. In actual fact functionA is returning a closure since functionB relies on the counter variable which is declared outside the functionB’s local scope. In other words, functionB is said to have captured or closed over (hence the term closure) the counter variable and, as such, is considered a closure in the traditional computer science definition of the word. Later we will discuss with the new Swift Closure Tutorial.

 -------------------------------------------

Thanks for reading!!



Post a Comment

0 Comments