Functions and variables

A first simple function

Let's continue defining factorial(x)=1*2*3*...*x:

function fact x -> y
  arg Int x y
  y := 1
  for (var Int i) 2 x
    y := y*i
console "factorial(5) = " (fact 5) eol

The sign '->' is used to introduce the result of the function.
An argument is a bit like a variable, but it's type is defined by 'arg' instead of 'var'.

Please also notice that when calling a function, Pliant way of writing is to put the left parenthesis before the function name rather than after, so we write (fact 5) whereas the classical math notation is fact(5)

Recursivity

We could define the same function recursively, which means define factorial(x) as a modification of factorial(x-1) instead of computing it from scratch:

function fact x -> y
  arg Int x y
  y := shunt x=0 1 x*(fact x-1)

Arguments access mode

The default access mode for arguments is read only for all of them but the result. If we want the function to be able to modify a caller variable, we have to use arg_rw access mode:

function increment x
  arg_rw Int x
  x := x+1
var Int i := 3
increment i
console i eol

There is also one just a bit different kind of argument access mode, introduced by arg_w instead of arg_rw. The semantic of arg_w is the same as for arg_rw, but it more over asserts that the value of the argument when the function execution ends does not depend on the value of the argument when it started. This is used by Pliant optimizer to provide more efficient code.
Here is an example of possible use:

function zero x
  arg_w Int x
  x := 0
var Int i := 3
zero i
console i eol

Please notice that the access mode for the result of a function is always arg_w, even if we define it's type using arg.

If you are reading Pliant documentation for the first time, just jump to 'Local versus global variables'.

The default for Pliant is to pass read only atomic arguments by value (atomic means that the data is scalar and has the same size as processor registers, so 32 bits on a 32 bits platform; scalar roughly means that it contains no pointer, has no 'build' or 'destroy' method, and so on). You can force any argument the be passed by address through using 'arg_r' instead of 'arg', also I just see no reason to do that.

Three other kind of result argument exist that are introduced by 'arg_R' 'arg_RW' and 'arg_C'. All the three will return a pointer instead of a value. 'arg_R' means that the pointed data should be only accessed by the calling function, and 'arg_RW' than it can be both accessed and modified. 'arg_C' means that the calling function can modify the pointed data if an only if it had write access to the first argument of the function. Here is a sample that returns a pointer to the last element of an array:

function a last -> l
  arg Array:Int a ; arg_C Int l
  check a:size>0
  l :> a a:size-1
((the_function '. last' Array:Int -> Int) arg 1) maps := 1

The last line is completely un-understandable for a non expert. It say that in the 'last' method (so '. last' function) we have just defined, the argument with index 1 (that is 'l' because 'a' has index 0) can point to some part of argument with index 0 (that is 'a') on return.
1 stands for 2^0 because 'maps' field is a bits set, and 0 stands for 'a' index.
Defining this is important because if the 'a' data is discarded a few instructions letter in the program, they the 'l' data gets inconsistent as a side effect. So, the strange line says to the optimizer: keep 'a' unmodified as long as 'l' value needed. Without this rule, 'a' variable could be used for something else too soon. The reason is that one data in a function can be used to store several local variables value provided no clash appends; I mean it used for something else only when the previous content will not be used any more.

Still for the experts, we could just get rid of 'arg_R' 'arg_RW' and 'arg_C' and use pointers instead, such as:

function a last -> l
  arg Array:Int a ; arg Pointer:Int l

but then, things like this would be accepted by the compiler:

var Array:Int a
var Int i
a last :> i

If the function expects some of it's argument to be not just standard instances, but rather real Pliant objects (real Pliant objects have a header in front of them that provide reference count support and effective data type enabling using generic methods), you can add an 'o' letter in front of the various 'arg' variants to enforce stronger type checking:

function image_copy from to
  oarg ImagePrototype from ; oarg_w ImagePrototype to
  ...

Others possible values are 'oarg_rw', 'oarg_R', 'oarg_RW' and 'oarg_C'.

Exiting the function immediately

At any point in a function execution, the function can be exited immediately through calling 'return' instruction with no argument:

function fact x -> y
  arg Int x y
  if x=0
    y := 1
    return
  y := x*(fact x-1)

If 'return' instruction is provided an argument, it will set the result before exiting:

function fact x -> y
  arg Int x y
  if x=0
    return 1
  y := x*(fact x-1)

Please notice that in Pliant, as opposed to C, the standard way to return a value is just to set the result variable, so that 'return' instruction is to be used only to prevent function execution to continue.

Methods

In Pliant, a method is just a function that will be called with the first argument before the identifier:

method s twice -> s2
  arg Str s s2
  s2 := s+s

console ("abc" twice) eol

This is so much true that the method could also be used through:

console ('. twice' "abc") eol

and could has well have been defined through:

function '. twice' s -> s2
  arg Str s s2
  s2 := s+s

Implicit

When defining a method, specifying the object name repeatedly sometime makes the program less clear. 'implicit' can be used to avoid specifying the object name:

type Pair x y
  field Int x y

method p sum -> z
  arg Pair p ; arg Int z
  z := p:x + p:y

could be written as:

method p sum -> z
  arg Pair p ; arg Int z
  implicit p
    z := x + y

Please notice that 'implicit' semantic is not related to methods in facts. It can be used anywhere, with any keyword, and just says to the compiler: if an expression does not compile, try to put the provided keyword ahead and see if it helps.

Local versus global variables

A global variable is declared using 'gvar' keyword:

gvar Int my_var

A global variable is always a Pliant object. See the 'Pointers and memory allocation' article for a detailed specifications of what a Pliant object is. Basically, an object is a data with a header that contains it's exact type and references count, so enables to use reference count memory allocation and to call generic functions.

Nothing prevents you to declare a global variable in the middle of a function, also it is probably a very bad idea.

A local variable is declared using 'var' keyword:

var Int i

A local variable is local to a function, so can be declared only in a function. It is created when the processor enters the function, and discarded when the processor leaves the function, as opposed to being created when the execution pointer passes over the instruction that declared the variable.

You can declare a local variable anywhere when using the Pliant interpreter because, when you press the 'Execute' button, all the code you typed will be turned to a function with no argument, then this function will be called once, and finally discarded.
An 'ui_path' (see 'A first graphic mode application' article) also silently creates a function.

On the other hand, many samples in this documentation use 'var' without defining a function. This is just to make writing easier. I just assume that the few sample lines will be in the middle of a function in your real code.

You can also declare several local or global variables at once:

var Int i j k

For the beginners: if you don't know if a variable should be declared as local or global, then it should probably be declared as local.

Constants, object variables

A constant is like a global variable, but receives a value at creation time, that cannot be modified later:

constant million 10^6

Indirect functions

- Starting from here, the article is for advanced programmers only -

It is sometime useful to receive some function to execute as an argument. As an example, when implementing sorting, one can either use genericity to make the compiler silently compile a new instance of the algorithm for each data type it will be used on, or one can compile a single instance that will receive the comparison function as a parameter.

Here is how to get a pointer to the factorial function defined at the beginning of this document:

module "/pliant/language/compiler.pli"
var Link:Function f :> the_function fact Int -> Int

If the function is a method, just use the dotted notation introduced in the methods presentation section:

method s twice -> s2
  arg Str s s2
  s2 := s+s
var Link:Function f :> the_function '. twice' Str -> Str

'the_meta' also exists to get the link to a meta function, which is also a function. Rarely used: see code.

Then calling the function is done though generating a prototype function:

function math_function x fun -> y
  arg Int x y ; arg Function fun
  indirect
...
var Link:Function f :> the_function fact Int -> Int
...
console (math_function 5 f) eol

Please notice that, compare to the real function that will be called in the end, the prototype function has an extra argument with type 'Function'.

External functions

Enabling Pliant to use function defined in an external library is just a mater of providing the function prototype, and using 'external' instruction to provide the library name and function name in the library:

function os_open name flags rights -> handle
  arg CStr name ; arg Int flags rights handle
  external "libc.so.6" "open"

The only situation that will be tricky is if the function has argument with C type 'float' or 'double', and the reason is that these arguments are passed by value on the stack by C compiler whereas Pliant has a rule that only atomic arguments (the ones that fit registers size) can be passed by value. So, the easiest would be to use 'float *' or 'double *' in the C part, but if you cannot change the prototype, you will have to do dirty hacks in Pliant at the moment.
Some dirty hack sample to pick a result with type 'double' in provided in /pliant/linux/multimedia/libmpeg3.pli
At documentation writing time, I have not found any code showing how to call a C function with an argument with C type 'double', so if you have one, please drop hubert.tonneau@fullpliant.org. I will help you and update the documentation accordingly.
Last point about 'external': please notice that it will automatically set the 'external_calling_convention' flags (see bellow).

Under Linux, kernel functions are not called the same way as the ones in external libraries, so a 'kernel_function' instruction is provided to enable to tel to Pliant how to call a kernel function:

function os_exit retcode
  arg Int retcode
  kernel_function 1

The function number is to pick in Linux unistd.h, and the problem is that this number is platform specific, so Pliant is ported to new platforms at some point, it will have to be adjusted for each new platform. Also, meta programming would enable to make it automatic through scanning kernel source files, a bit like GCC is used to find exact fields offsets when the platform is Posix (see 'os_field_offset' in /pliant/language/os/posix.pli module).

Changing functions attributs

Use C operating standard calling convension for the operating system Pliant is running on:

function foo x
  arg Int x
  external_calling_convention
  ...

Use C variable number of arguments calling convension:

function foo x
  arg Int x
  varargs_calling_convention
  ...

Force the function to be inlined. You should not do that because Pliant automatically decides to inline very short functions:

function foo x
  arg Int x
  inline
  ...

Defines the function as a generic method for the data type of the function first argument. Generic methods are a not exact equivalent of C++ virtual methods:

method x foo
  oarg MyClass x
  generic
  ...

Sometime, several functions call each other so that it is not possible to define them without trouble with standard Pliant way of coding, because in Pliant, you can't call a function that has not been defined yet. 'later' enables to declare the function prototype, a bit like in C, so that it can be used immediately in another function, but will be defined later. Please use with care since I'm not sure it always works.

function foo x
  arg Int x
  later
...
function foo x
  arg Int x
   ...

A hidden function is a function that cannot be called directly. 'the_function' has to be used to get it's address, so that it can be provided to an indirect function prototype. Probably just another useless feature.

function foo x
  arg Int x
  hidden_function
  ...
...
var Link:Function f :> the_function foo Int
...

A new Pliant function is assumed to have side effects if and only if it calls a function having side effects. If the rule would be wrong for one of your functions, you can force it:

function foo x
  arg Int x
  has_side_effects
  ...

function foo x
  arg Int x
  has_no_side_effects
  ...

When several definitions of the same identifier is provided, 'foo' in these examples, Pliant expect one and one to match the provided set of arguments. If two or more match, Pliant will report and 'ambiguous' error.

The new definition cannot conflict with any previous one, because if it does, the previous one will be used:

function foo x
  arg Int x
  weak_definition
  ...

The new definition cannot conflict with any previous one, because if it does, the new one will be used:

function foo x
  arg Int x
  strong_definition
  ...

The new definition cannot conflict with any other one, past or further, because if it does, this one will be ignored. Use with care:

function foo x
  arg Int x
  always_weak_definition
  ...

The new definition cannot conflict with any other one, past or further, because if it does, this one will be used. Use with great care:

function foo x
  arg Int x
  always_strong_definition
  ...