Skip to main content

Functions

Functions are code blocks that can be reused in different parts of the program, can accept input parameters, and return an output value. This helps organize code and make it more readable and maintainable. Additionally, by using functions, it's possible to avoid code repetition and facilitate debugging.

Like variables and objects, functions are also first-class values in JARU, meaning they can be assigned to variables, passed as parameters to other functions, and returned as values from other functions.

Parameters

In JARU, up to 255 parameters can be passed to a function, and pass by reference is used for function parameters, meaning if a variable is modified within a function, its value also changes outside the function.

Function Declaration

To declare a function in JARU, use the keyword func followed by the name you want to give the function, the parameters in parentheses, and end with the keyword end.

func myFunction(parameter1, parameter2) 
// function body
end

Function parameters are variables used to receive the values passed to the function when it's called. The number of parameters is optional, but can be a maximum of 255. Parameter passing in JARU is by reference, meaning if a parameter is modified inside the function, that modification will be reflected in the original value of the parameter.

To return a value from a function, use the keyword return followed by the value to return. If a function doesn't return any value, the return keyword is not necessary.

tip

Actually, in JARU all functions return a value. If return is not used in the function, it will return the value nil.

Function Declaration Examples

// Function that receives no parameters and returns no value
func print_message()
print("Hello world")
end

// Function that receives parameters and returns a value
func add(num1, num2)
return num1 + num2
end

// Function that receives multiple parameters and returns no value
func print_data(name, age, city)
print("Name: ", name, " Age: ", age, " City: ", city)
end

Calling a Function

Calling a function is the process of executing the code contained within that function. In JARU, you can call a function using its name followed by parentheses and, optionally, passing arguments inside the parentheses.

print_message("Hello world")

In this case, the print_message function would receive the argument "Hello world" and use it to print a message on screen.

It's also possible to store the value returned by a function in a variable:

result = add(3, 4)

In this case, the variable result would store the value 7.

info

Functions can be nested, meaning a function can call another function within its body.

Nested Function Declaration

In JARU, functions can be declared inside other functions:

func parent_function()
func child_function()
println("I am the child function")
end
println("I am the parent function")
child_function()
end

parent_function()

In this example, the "parent_function" function is the main function that contains "child_function" inside it. The "child_function" function can only be called inside "parent_function", since it's declared within that function.

It's also possible to pass parameters to the child function and return values from it:

func parent_function()
func child_function(num1, num2)
return num1 + num2
end
var result = child_function(2, 3)
print("The result is: ", result)
end

parent_function()

The console will show: The result is: 5

Anonymous functions (fn lambdas)

A lambda is a function without a name used as a value: you can store it in a variable, put it in a list or map, return it from a function, or pass it directly as a callback. It's written with the fn keyword, the parameter list, a colon and the body ending with end:

fn(parameters): body end
// In a variable
var double = fn(x): return x * 2 end
println(double(21)) // 42

// Inline as a callback: the star use case
use Timer
Timer.every(1000, fn(id, p, u):
println("tick")
end)

// In lists and maps (dispatch tables)
var commands = {"greet": fn(who): println("Hello, ", who) end}
var greet = commands["greet"]
greet("Jon")

Variable capture (closures)

A lambda can use the variables of the scope where it was created. Capture is by reference: the lambda sees later changes to the variable, and the variable stays alive as long as the lambda exists — even after the function where it was born has returned:

func makeCounter()
var n = 0
return fn():
n = n + 1
return n
end
end

var c1 = makeCounter()
var c2 = makeCounter()
println(c1(), " ", c1(), " ", c1()) // 1 2 3
println(c2()) // 1 (each counter has its own n)

Inside a class method, a lambda can also capture this:

class Button
def init()
this.pressed = 0
end
def handler()
return fn(): this.pressed++ end
end
end

Recursion with lambdas

A lambda has no name, so for recursion assign it to a variable first and call it through it:

var fact = nil
fact = fn(n):
if (n <= 1) then
return 1
end
return n * fact(n - 1)
end
println(fact(5)) // 120
Chained calls

If a function returns another function, call the result through an intermediate variable: var f = make() then f(x). The chained form make()(x) is not supported yet.

Recursion

In JARU, recursion is allowed, which is a function that calls itself to solve a problem. Recursion is often used to solve problems that can be divided into smaller subproblems of the same type.

To create a recursive function in JARU, you must define the function the same way you define any other function, but within the function, you must include a call to the same function.

func factorial(n)
if (n == 0) then
return 1
else
return n * factorial(n - 1)
end
end

In this example, the "factorial" function calls itself with a parameter one less until the base case is reached (n == 0).

Important

It's important to be careful when using recursive functions because if there's no adequate base case or if the arguments passed to the function don't lead to the problem's solution, it can cause an infinite loop and the program will stop due to stack overflow.

Common Recursion Examples

  • Search and sorting algorithms: Algorithms like quicksort and binary search use recursion to divide a problem into smaller problems and solve them independently.
  • Backtracking problems: Problems like the mouse maze and sudoku solutions can be solved using recursion to try different options and backtrack when reaching a path with no solution.
  • Mathematical problems: Problems like the Fibonacci series and factorial calculation can be efficiently solved using recursion.
  • Graph problems: Algorithms like depth-first search and breadth-first search for traversing a graph use recursion to explore different nodes.

Recursion is a powerful tool for solving problems that can be divided into independent subproblems, and JARU allows you to use it.