A function is a collection of instructions. With Genesys is it a collection of expressions, separated by a semicolon.
You define a function like a variable, its data type is code. The easiest way is a procedure which does not get any input and does not deliver any result.
Therefore you need an identifier - the name of the procedure - and some code. To call a procedure you just type the name of the procedure and add empty parenthesis.
Due to the fact that your identifier 'sayHello' is not assigned with an expression you want to be calculated as a result you have to use the := to set a instruction as collection. The instruction collection is set between curly brackets. Here we only have just one instruction: the print-Command.
sayHello is code :=
{
  print "Hello\n";
};
sayHello();
If you only have just one instruction do not need the curly brackets:
sayHello is code := print "Hello\n";
Now let us define a procedure with an parameter:
saySomething( something is string ) is code := print something, "\n"; saySomething( "Hello" );
You can add as many parameters as you like. You only need to separate them with the comma-operator (',').
saySomething( something is string
            , newline is boolean ) is code :=
{
  print something;
  
  newline?
  then print "\n";
};
saySomething( "Hello", true );
You can overload function and procedures by using the body instruction. Therefor you just define the identifier as code and put the arguments to several body instructions:
saySomething is code :=
{
  body( something is string ) :=
    print something, "\n";
    
  body( something is string, newline is boolean ) :=
  {
    print something;
  
    newline?
    then print "\n";
  };
};
saySomething( "Hello", false );
saySomething( " World" );
A procedure delivering a result is called a function. To define a function you just put the 'as'-instruction behind 'code' followed by the resulting data type:
add is code( addend1, addend2 is int ) as int := return addend1 + addend2; int sum = add( 1, 2 ); print "Sum is ", sum$, ".\n";
Overloading works like procedures:
add is code as int :=
{
  body( addend1, addend2 is int ) := 
    return addend1 + addend2;
  body( addend1, addend2, addend3 is int ) := 
    return addend1 + addend2 + addend3;
};
These short functions are quite common, so you can assign the result expression to the function directly. You can format you source code as a table so you have get an overview easily.
Note that we use the ':'-Operator and omit the return-instruction:
add is code as int :=
{
  body( addend1, addend2          is int ) : addend1 + addend2;
  body( addend1, addend2, addend3 is int ) : addend1 + addend2 + addend3;
};
You also can overload functions with different result types:
add is code :=
{
  body( addend1, addend2          is    int ) as    int : addend1 + addend2;
  body( addend1, addend2, addend3 is    int ) as    int : addend1 + addend2 + addend3;
  body( addend1, addend2          is double ) as double : addend1 + addend2;
};
And you can collect function definitions for a result type:
add is code :=
{
  as int:
    body( addend1, addend2          is    int ) : addend1 + addend2;
    body( addend1, addend2, addend3 is    int ) : addend1 + addend2 + addend3;
    
  as double:
    body( addend1, addend2          is double ) : addend1 + addend2;
};