Defining functions

A function is an object that gets a number of arguments (the argument list, arglist) as the input, then does something with these values in the function body, and returns none, one, or more value(s). Multiple arguments are separated by commas (,) in an arglist (in fact, they form a tuple, as do the return values; refer to the Tuples section of Chapter 5, Collection Types). The arguments are also optionally typed, and the type(s) can be user-defined. The general syntax is as follows:

function fname(arglist) 
    # function body... 
    return value(s) 
end

A function's argument list can also be empty; in this case, it is written as fname().

The following is a simple example:

# code in functions101.jl 
function mult(x, y) 
       println("x is $x and y is $y") 
       return x * y 
end 

Function names such as mult are, by convention, in lower-case. They can contain Unicode characters, which are useful in mathematical notations. The return keyword in the last line is optional; we could have written the line as x * y. In general, the value of the last expression in the function is returned, but writing return is mostly a good idea in multiline functions to increase readability.

The function called with n = mult(3, 4) returns 12, and assigns the return value to a new variable, n. You can also execute a function just by calling fname(arglist) if you only need its side-effects (that is, how the function affects the program state; for instance, by changing the global variables). The return keyword can also be used within a condition in other parts of the function body to exit the function earlier, as in this example:

function mult(x, y) 
    println("x is $x and y is $y") 
    if x == 1  
      return y  
    end 
    x * y 
end 

In this case, return can also be used without a value so that the function returns nothing.

Functions are not limited to returning a single value. Here is an example with multiple return values:

function multi(n, m) 
    n*m, div(n,m), n%m 
end 

This returns the tuple (16,4,0) when called with multi(8, 2). The return values can be extracted to other variables such as x, y, z = multi(8, 2); then x becomes 16, y becomes 4, and z becomes 0. In fact, you can say that Julia always returns a single value, but this value can be a tuple that can be used to pass multiple variables back to the program.

We can also have a variable with a number of arguments using the ellipsis operator (...). An example of this operator is as follows:

function varargs(n, m, args...) 
    println("arguments : $n $m $args") 
   end 

Here, n and m are just positional arguments (there can be more or none at all). The args... argument takes in all the remaining parameters in a tuple. If we call the function with varargs(1, 2, 3, 4), then n is 1, m is 2, and args has the value (3, 4). When there are still more parameters, the tuple can grow; or if there are none, it can be empty ().The same splat operator can also be used to unpack a tuple or an array into individual arguments. For example, we can define a second variable argument function as follows:

function varargs2(args...) 
    println("arguments2: $args") 
end 

With x = (3, 4), we can call varargs2 as varargs2(1, 2, x...). Now, args becomes the tuple (1, 2, 3, 4); the tuple x was spliced. This also works for arrays. If x = [10, 11, 12], then args becomes (1, 2, 10, 11, 12). The receiving function does not need to be a variable argument function, but then the number of spliced parameters must exactly match the number of arguments.

It is important to realize that, in Julia, all arguments to functions (with the exception of plain data such as numbers and chars) are passed by reference. Their values are not copied when they are passed, which means they can be changed from inside the function, and the changes will be visible to the calling code.

For example, consider the following code:

function insert_elem(arr) 
  push!(arr, -10) 
end 
 
arr = [2, 3, 4] 
insert_elem(arr) 
# arr is now [ 2, 3, 4, -10 ] 

As this example shows, arr itself has been modified by the function.

Due to the way Julia compiles, a function must be defined by the time it is actually called (but it can be used before that in other function definitions).

It can also be useful to indicate the argument types, to restrict the kind of parameters passed when calling. Our function header for floating point numbers would then look like: function mult(x::Float64, y::Float64). When this is the only mult function, and we call this function with mult(5, 6), we receive an error, ERROR: MethodError: no method matching mult(::Int64, ::Int64), proving that Julia is indeed a strongly typed language. It does not accept integer parameters for floating point arguments.

If we define a function without types, it is generic; the Julia JIT compiler is ready to generate versions called methods for different argument types when needed. Define the previous function mult in the REPL, and you will see the output as mult (generic function with 1 method).

There is also a more compact, one-line function syntax (the assignment form) for short functions, for example, mult(x, y) = x * y. Use this, preferably, for simple one-line functions, as it will lend the code greater clarity. Because of this, mathematical functions can also be written in an intuitive form:

f(x, y) = x^3 - y + x * y; f(3, 2) #=> 31

A function defines its own scope. The set of variables that are declared inside a function are only known inside the function, and this is also true for the arguments. Functions can be defined as top-level (global) or nested (a function can be defined within another function). Usually, functions with related functionality are grouped in their own Julia file, which is included in a main file. Or, if the function is big enough, it can have its own file, preferably with the same name as the function.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.162.49