Chapter 5. Functions

A function is a block of statements enclosed within curly braces. This block is given a name and is invoked using the specified name.

One of the important reasons to use functions is that they help organize the code conceptually and logically, avoiding redundancy within your program. Functions help break the bulk of code into smaller chunks by logically grouping the statements. Typically the code that is called frequently within your program is moved to a function that is then invoked from multiple places instead of duplicating the same code in all the places. Sometimes this is referred to as the "divide and conquer" approach.

In JavaFX Script, functions can be classified into two types based on where they are located within your program; there are script-level functions and member functions of a class definition. Script-level functions are written directly within the script (an .fx file) and not inside any class definition present in the script. Functions of this type are visible to the entire script and within any class definitions that may exist in the script. It is also possible to make these functions visible outside the script, by specifying appropriate access specifiers; you will learn more about this in Chapter 7, "Access Specifiers."

Member functions (also known as instance functions) are functions defined within a class as a member of the class and are accessible within the class by default. To access these functions outside the class, you will have to create an instance of the class. Here also it is possible to make these members visible outside of the script by specifying appropriate access specifiers.

Note

All the examples in this chapter are script-private functions, meaning they will not have any access specifiers defined and would be accessible only within the script.

Functions are normally defined by the application developer depending on the requirement of the application. In addition to that, you can find many functions available in the JavaFX APIs that you can use within your application. For instance, you have seen many examples using println, which is a function offered by the JavaFX APIs that is implicitly available within any JavaFX application (no import required).

Let us see the syntax for defining a function:

[modifiers] function function-name([parameterName : parameterType , .. ] ) : [ return type ]
{
    // statements
}

The access modifiers that can be specified while declaring a function in JavaFX Script are package, protected and public. These modifiers are reserved words in JavaFX Script, and you will learn more about them in Chapter 7. Specifying an access modifier is optional; if nothing is specified, the default will be "script-private" access and will make the function visible only within the script where it is declared.

In addition to the access modifiers, you can also specify certain other modifiers such as bound, abstract and override in the function definition. Bound functions are explained in detail in Chapter 9, "Data Binding." You will learn more about abstract and overridden functions in Chapter 8, "Inheritance." They have been listed here in the syntax just for completeness. These modifiers are additive in nature and hence can be combined with the access modifiers.

Every function requires an identifier, which is the function name. The rules for naming variables that you have already learned apply to function naming as well. Arguments (or parameters) are the inputs for the function, and they are separated by commas. Arguments are enclosed within the parentheses. It is not mandatory that a function have an argument; you can define a function with no arguments. Similarly, even if you define an argument, it is not necessary to define the data type for the argument, as it will be inferred automatically by the compiler. Nevertheless, there are circumstances where you will declare the data type while defining the function arguments, as you will see later in this chapter. If the function returns a value, you specify the return type after the closing parenthesis separated by a colon. The return type of the function is optional as well; if it is not specified, the compiler tries to infer a valid return type automatically from the last statement in the function body. If the last statement is an expression that does not yield a value (such as a println statement), then the default return type of Void is assumed. The executable block of code that is enclosed with the curly braces forms the body of the function.

Let us see how to write a simple function. Listing 5-1 is our first example.

Example 5.1. Example of a simple function

1.    function sayHello ( name )  {
2.        println("Hello {name} ..!");
3.    }
4.    println("My team Members");
5.    sayHello("praveen");    // function call
6.    sayHello("lawrence");

     Output
My team Members
praveen
lawrence

Listing 5-1 is a very simple program that demonstrates how to write a function. The aim of the function is just to print some names with a welcome message. In this example the function is defined above the function call (the statement that calls the function). But it is not mandatory to define the function above the statement that calls it in JavaFX Script; we can define the function anywhere within the script.

This rule is similar to that for the main() function in Java, which can appear anywhere within the class definition.

How a Function Works

Let us analyze how the function shown in Listing 5-1 works. When the function sayHello is invoked at line 5 with an argument of praveen, control goes to line 1, taking the value praveen and copying it to the variable name specified in the parameter list of the function. The value praveen in line 5 is called an actual argument, since it is the actual value that is passed to the function. The variable name in line 1 is called a formal argument, since it just collects the value passed from the function call. Formal arguments are also called formal parameters. The scope of the formal parameter is restricted to the body of the function. They are created when the function is called and destroyed when the function ends.

As you have seen in the syntax, specifying arguments and return types is optional in JavaFX Script. With this in mind, let us see the following combinations of function definitions in detail:

  • Functions with neither an argument nor a return value

  • Functions with an argument but without a return value

  • Functions without an argument but with a return value

  • Functions with both an argument and a return values

A Function with Neither an Argument nor a Return Value

Let us see how to define a function that does not take any arguments and does not return anything. Listing 5-2 shows an example.

Syntax

modifiers function-name( ) {
    // statements
}

or

modifiers function-name( ) : Void {
    // statements
}

Example 5.2. Example of a function with neither an argument nor a return value

1.    for(i in [1..5])  {
2.        sayHello();
3.    }
4.
5.    function sayHello(){
6.        println("This is a function without an argument and a return value");
7.    }

Output

This is a function without an argument and a return value
This is a function without an argument and a return value
This is a function without an argument and a return value
This is a function without an argument and a return value
This is a function without an argument and a return value

In Listing 5-2, we have defined a function called sayHello() from line 5 to line 7. This function doesn't take any argument (the parentheses are empty) and there is no return type as well. We are calling the same function five times in line 2 using a for loop. For each function call, the output statement is printed on the console as shown in the output section. Since the block expression that forms the body of the function does not have a valid value, the compiler would automatically infer a return type of Void.

A Function with Arguments but Without a Return Value

Let us see how to write a function with some arguments (or parameters) but without a return value.

Syntax

modifiers function-name(parameterName : parameterType , .. ) {
    // statements
}

or

modifiers function-name( parameterName : parameterType , ..) : Void {
    // statements
}

Listing 5-3 shows an example of a function that takes an argument but does not have a return value.

Example 5.3. Example of a function with arguments but no return value

1.    function factorial( num : Integer) : Void {
2.        var i : Integer = 1;
3.        var fact : Integer = 1;
4.        while(i <= num ){
5.            fact = fact * i++;
6.        }
7.        println("factorial of {num} is {fact}");
8.    }
9.
11.    var n2 : Integer = 6;
12.    factorial(5);
13.    factorial(n2);

Output

factorial of 5 is 120
factorial of 6 is 720

The aim of the function defined in Listing 5-3 is to find the factorial of a given number. From line 1 to line 8, we define the function named factorial, and in lines 12 and 13 we call the function. When the function is called, its body of the function is executed, accepting the argument passed. In this function body, a block expression calculates the factorial of the given number and prints it out. Please note that the value of this block expression is Void because the value of the last expression in the block is a println, which does not yield any value. Hence the return type of the function is considered to be Void.

Note

In JavaFX Script, unlike in Java, the arguments passed to a function are read-only and cannot be modified by the function. Trying to modify the parameters will result in a compilation error.

A Function Without an Argument but with a Return Value

Let us see how to write a function that does not accept any arguments but returns a valid value.

Syntax

modifiers function-name(  ) : [return type]  {
    // statements
    return expression ;
}

or

modifiers function-name(  )   {
    // statements
    return expression;
}

or

modifiers function-name( ) : [return type]{
    // statements
}

As you can see, there are three ways of declaring a function that does not accept an argument but returns a valid value. The first syntax shows a function declaration with its return type specified explicitly and a return statement within the body of the function. The second syntax shows a function declaration where the return type is not specified in the first line of the function declaration, but the function body specifies a return statement explicitly. In this case, the compiler will automatically infer the return type from the return statement. The third syntax shows a function declaration where we have specified the return type in the first line of the function declaration, but we have not specified anything within the function body. In this case the return type of the function is determined by the last statement of the function.

Now let us see a simple example (Listing 5-4).

Example 5.4. Example of a function without an argument but with a return value

1.    function getPI( ) {
2.        return 22.0/7.0;
3.    }
4.
5.    function getOddsLessThanTen( ) {
6.        [1..10 step 2];
7.    }
8.
9.    function printName() : String{
10.
11.
12.             "Jack and Jill";
13.    }
14.
15.    var pi = getPI();
16.    println("pi value = {pi}");
17.    var nos : Integer [] = getOddsLessThanTen( );
18.    println(" Odd numbers = {nos}");
19.    println(printName());

Output

pi value = 3.142857
 Odd numbers = 13579
Jack and Jill

This example has three different functions that show how functions return their values. The first function, getPI(), returns the value of Pi. We have explicitly specified the return statement.

The second function, getOddsLessThanTen(), returns a range from 1 to 9 with a step of 2. We have not specified any return statement or the return type for this function, so in this case the compiler automatically infers that the function getOddsLessThanTen() returns a Sequence by looking at the last statement of the function.

The third function, printName(), returns a String depending upon the if expression. In this function we have specified both the return type and the return statement.

A Function with Arguments and a Return Value

Let us see how to write a function that accepts some arguments and returns a valid value.

Syntax

modifiers function-name( parameterName : parameterType , .. ) : [return type] {
    // statements
    return expression;
}

Listing 5-5 shows an example.

Example 5.5. Example of a function that has arguments and a return value

1.    function functionExpression(a:Integer, b:Integer):Number {
2.        var x = a + b;
3.        var y = a - b;
4.        return squareOfNumber(x) / squareOfNumber (y);
5.    }
6.
7.    function squareOfNumber(n:Integer): Number {
8.        n * n;
9.    }
10.    println("{ functionExpression(5,8) }");

Output

18.777779

This example demonstrates how one function calls another within the body of the function and, at the same time, plays the role of the expression that decides the return value.

Note

A function can take any number of arguments of any data type, but it can return only one return value. If you need to return multiple values, use a Sequence as the return type of the function.

Variable Access within a Function

A function can access script-level variables, parameters, and local variables. Let's see each of them in detail.

Script-Level Variables

A variable defined within the script is called a script-level variable. Such a variable can be accessed anywhere within the script: within the script functions, within the blocks, within the class member functions, and so on. The value of this variable can be changed anywhere within the script. Script-level variables are like static variables in Java. Listing 5-6 shows an example.

Example 5.6. Using a script-level variable

1.    var scriptLevelVar  : Number = 10;
2.
3.    public  function simpleFunction(  ) {
4.        println("Accessing scriptLevelVar with in the simple function = {scriptLevelVar}");
5.        // modifing the value of scriptLevelVar
6.        scriptLevelVar = 45.34;
7.        println("Modified value of scriptLevelVar in simple function = {scriptLevelVar}");
8.    }
9.
10.    function run (){
11.        println("Accessing the scriptLevelVar in run function 
scriptLevelVar = {scriptLevelVar}");
12.        simpleFunction(  ) ;
13.        ;  scriptLevelVar++;
14.        println("Modified value in run function scriptLevelVar = {scriptLevelVar}");
15.    }

Output

Accessing the scriptLevelVar in run function
scriptLevelVar = 10.0
Accessing scriptLevelVar with in the function = 10.0
Modified value of scriptLevelVar in function = 45.34
Modified value in run function scriptLevelVar = 46.34

This example demonstrates how a script-level variable can be accessed and modified from within a function.

Note

Script-level variables are created before the run() function is invoked.

Local Variables

Local variables are variables that are defined within the function and can only be accessed within it. The life-span of such variables is same as that of the function in which they are declared. These variables are created when the function is called and are destroyed when the function completes execution. Their value can be changed any number of times within the body of the function.

Function Overloading

Function overloading is typically about a set of functions sharing the same function name, but accepting different arguments and performing different activities depending on the kind of parameters sent to them. This is also known as polymorphism in OOP (Object Oriented Programming). When an overloaded function is called, the JavaFX Script checks the number and type of parameter(s) of all the functions defined with the same name and calls the one whose parameters exactly match the calling statement. Listing 5-7 shows an example.

Example 5.7. Example of an overloaded function

1.    function fun() {
2.        println("Function Overloaded without any argument.");
3.    }
4.
5.    function fun(a : Integer , b : Integer) {
6.        println("Function Overloaded with  Integer argument a ={ a } , b = {b}");
7.    }
8.
9.    function fun(n : Number ) {
10.        println("Function Overloaded with  Number argument n = {n}");
11.    }
12.
13.    fun();
14.    fun(5, 10);
15.    fun(22.0/7.0);
16.    fun(40);

Output

Function Overloaded without any argument.
Function Overloaded with Integer argument a = 5 , b = 10
Function Overloaded with Number argument n = 3.142857
Function Overloaded with Number argument n = 40.0

The example in Listing 5-7 has different functions sharing the same function name. Each function has a different set of arguments. The first function doesn't take any argument, the second function takes two Integer arguments, and the third function takes one Number argument. When the function is called from line 13 to line 16, the JavaFX Script compiler checks the number and type of parameters and calls the corresponding function.

Line 16 is a special type of function call. The function argument doesn't match any of the function declarations directly. When this situation arises, JavaFX Script's automatic type conversion plays an important role in solving the issue. At Line 16, the function call has an Integer value, but none of the function declarations match. However, the last function matches in the number of arguments but differs in data type. Nevertheless, the function expects a Number type, which has a greater precision than the Integer, so it is actually safe to promote an Integer to a Number data type without any data loss. Hence the compiler converts 40 to a Number and calls the fun() function, which accepts a Number. You can easily see from the output that a plain 40 is converted into 40.0.

Recursive Functions

A function that calls itself either directly or indirectly until a condition is satisfied is called a recursive function. Let us take the most common example of the recursive function that calculates the factorial of a given number and the Fibonacci series. You have already seen the factorial example in this chapter. Listing 5-8 illustrates how the same problem can be solved using a recursive function.

Example 5.8. Example of a recursive function

1.    function factorial( n : Integer ) : Integer{
2.        if( ( n==0) or ( n == 1 ) ) {
3.            return n;
4.        }
5.        else {
6.            return n * factorial(n - 1 );
7.        }
8.    }
9.
10.    println("factorial of 5 = {factorial(5) }");
11.    var fact = factorial(8);
12.    println("factorial of 8 = {fact}");

Output

factorial of 5 = 120
factorial of 8 = 40320

In Listing 5-8, the function factorial() takes an Integer as the argument and returns an Integer as output. In line 2 we are checking whether the argument n value is either 0 or 1. If the value of n is 1, then we are just returning the value of n. if the value is more than 1, the else part is executed. It calls the same function, passing n - 1. This recursion continues until the condition given in line 2 is satisfied.

Note

It is mandatory to declare the return type of a recursive function explicitly. Failing to do so will result in a compilation error.

Listing 5-9 shows another example of a recursive function.

Example 5.9. Example of a recursive function with multiple invocations

1.        function fibonacciFun(n:Integer):Integer {
2.        if (n<2) {
3.            return n
4.        }
5.        else {
6.              (fibonacciFun(n-1) + fibonacciFun(n-2));
7.         }
8.    }
9.
10.    println(" fibonacci of 10 = { fibonacciFun(10) }");
11.    println(" fibonacci of 1 = { fibonacciFun(1) }");

Output

fibonacci of 10 = 55

Anonymous Functions

An anonymous function is one that doesn't have a function name. Using anonymous functions, we can convert a function in an expression, called a function expression.

The first step to write an anonymous function is to define a variable of type Function.

Syntax

var function_variable_name : function ( : parameter, : parameter ) : [return type];

Example

var x  : function( : Integer,  : Integer) : Integer;

This section is very simple; it's just providing the signature of the function, without specifying the function name. It is similar to declaring a variable, but instead of the data type, we are specifying the function type.

Here, function_variable_name is the variable that holds the function expression ,followed by the function keyword, which specifies that this is a variable of Function type. A Function type must also define the parameters within a pair of parentheses. If there is no parameter, then it could just be the opening and closing parentheses. Following the parameters is the return type of the function.

Note

It is mandatory to specify the type of the parameter(s), as there is no body of the function defined here. If we omit the data type of the parameters a compilation error is thrown.

Syntax

function_variable_name = function(argument name1 , argument name2 ) : [return type] {
        // statements
}

From this syntax, you see that an anonymous function is similar to a normal function, except that the function name is missing and we are assigning the function to a variable of the Function type.

Now let us see how to call the function variable that refers to an anonymous function expression, a step called closure. This is similar to calling the function using the function name and passing values to the arguments. But instead of a function name we are calling the anonymous function with the function variable name to which we have assigned the function expression.

Let's put it all together to make a complete script, as shown in Listing 5-10.

Example 5.10. Example of an anonymous function

1.    var x : function(   : Integer ,   : Integer ) : Integer ;
2.
3.    x = function(a,b ) {
4.        if(a > b ) {
5.             a;
6.        }
7.        else {
8.             b;
9.        }
10.    };
11.
12.    println("greatest number of 5 and 10 = { x(5,10) }");

Output

greatest no of 5 and 10 = 10

In line 1, we have declared the variable x of type Function, which takes two Integers as arguments and whose return type is Integer. From line 3 to line 10 we have defined the function expression assigned to variable x. In line 12 we have an output statement which calls the anonymous function through the x variable (of Function type) by passing the values 5 and 10, and finally the return value of the function expression is printed.

Listing 5-11 shows another example of an anonymous function.

Example 5.11. Example of a variable of type function with automatic type inference

1.    var fact = function (num : Integer )  {
2.        var i : Integer = 1;
3.        var fact : Integer = 1;
4.        while(i <= num ){
5.            fact = fact * i++;
6.        }
7.        return fact;
8.    }
9.    println("Factorial of 5 = { fact(5) } ");

Output

Factorial of 5 = 10

In Listing 5-10, we had declared function variable separately and function expression separately, but in Listing 5-11 we have combined the statements.

Now we know that in JavaFX Script, a variable can be of the Function type. Functions are described as first-class objects in JavaFX Script, which allows the programmers not only to create variables of type functions but also to pass such a variable arguments to other functions and return it as a return type from other functions.

The run() Function

The run() function is a special function in JavaFX Script that acts as the entry point to your application, similar to the main() function in Java. This function is implicitly created by the compiler internally as long as you do not have a public member (a variable, or a class, or a function) defined in your main script. However, if you have defined a public member, then the compiler lets you create the run() function as well and no longer generates it implicitly. If you fail to specify one despite having some public member, the compiler will throw a compilation error.

This function will be automatically called when you execute your application through the javafx executable, and any command-line arguments that the user may pass will be given to this function. Listing 5-12 shows a simple example of the run() function.

Example 5.12. Example of the run() function

1.    function run (){
2.        println("This is the entry point for JavaFX Scripting..!");
3.    }

Let's call this script EntryPoint.fx. When this script is executed, we see the following output on the console. This run() function is called by the JavaFX runtime automatically.

Output

This is the entry point for JavaFX Scripting..!

Let's see another of the run() function (Listing 5-13).

Example 5.13. Example that enforces addition of a run() function

1.    public  function areaOfCircle(radius :Number):Number {
2.        return  3.142 * radius * radius;
3.    }
4.
5.    function run(){
6.    println("This is the entry point for JavaFX Scripting..!");
7.    println("Area of the circle = {areaOfCircle( 7) } " );
8.    }

Output

This is the entry point for JavaFX Scripting..!
Area of the circle = 153.958

In this example we have defined a function called areaOfCircle and implemented the run() function. When the script is executed, the output shown is printed on the console. Notice that the function areaOfCircle is called within the run() function. Since the run() function is the entry point of the script, it will be called first, before areaOfCircle. If we move the function call areaOfCircle from line 7 to outside the run() function, say line 4, we will get a compilation error. This is because we have a public member in the script areaOfCircle and if there is a public member, JavaFX Script compiler enforces you to move all the loose expressions in to a run() function. In such a case, the run() function become mandatory. If you want to try this yourself, do the following in Listing 5-13.

  1. Move the function call at line 7 to line 4.

  2. Comment out the run() function entirely.

  3. Remove the public keyword from the function areaOfCircle.

Now you will be able to compile and run the example without any errors.

Note

When there is a public member in the script, a run() function becomes mandatory, and all the loose expressions in the script must be moved to that function. Otherwise, the compiler will throw an error.

Command-Line Arguments

The run() function can be defined with or without parameters. We have seen the function without parameter in the previous examples; let's see how to get the command-line arguments within the run function.

Syntax

function run( sequence of String ) {
                                   // statements
                                      }

Example 5.14. ModifiedRun.fx, an example of a function with command-line arguments

1.    function run (cmdLine : String[]){
2.        println("Printing Command-line arguments");
3.        for( arg in cmdLine ){
4.            println(arg);
5.        }
6.    }

Run the script as follows:

D:javafx-sdk1.3injavafx ModifiedRun Learning JavaFX Script Command-line argument

Output

Printing Command-line arguments
Learning
JavaFX
Script
Command-line
argument

There is also another way of accessing the command-line attributes. The JavaFX API contains a class, named FX in the javafx.lang package that is implicitly imported into any JavaFX script (just like java.lang classes). There is a method getArguments() in the FX class that returns a sequence of strings representing the command-line arguments. If no arguments are passed, this method returns a null value. Listing 5-15 shows an example.

Example 5.15. CommandLineArgsDemo.fx, an example using the getArguments() method

1.    public  function area_of_circle( radius :Number):Number {
2.        return 2 * 3.142 * radius ;
3.    }
4.
5.    function run (){
6.        println("Learning FX.getArguments() ..!");
7.        var args : String []  = FX.getArguments();
8.        println(area_of_circle (java.lang.Integer.parseInt(args[0])));
9.    }

Output

D:javafx-sdk1.3injavafx  CommandLineArgsDemo 20
Learning FX.getArguments() ..!
125.68

There is also another variant of getArguments() that accepts a string parameter, and this can be used when the incoming values are represented as key-value pairs. You would find this variant very useful typically when dealing with the browser version of the JavaFX Application (Applets). You can get more information about this from the JavaFX API documentation.

Summary

In this chapter you have learned about functions in detail. A function is a set of statements that are enclosed in curly braces. A function is accessed by its name, called a function name. A function definition may optionally include one or more modifiers, parameters and the return type. Overloaded functions are functions that share the same function name but differ in their number and type of arguments. Function parameters are read-only and hence cannot be modified. A function can be made anonymous by omitting a function name and instead assigning it to a variable of type Function. Anonymous functions can be invoked using the corresponding variable name, and such variables can be passed as parameters to other functions as well. The run() function acts as the entry point to any FX application, and the programmer has to define it if there is a public member declared within the script. Using this run() function and the Javafx.lang.FX class, you can get access to the command-line arguments.

In the next chapter, you will learn more about class definitions and how to go about defining and using classes and object literals within JavaFX Script.

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

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