Functions and variablesA first simple functionLet's continue defining factorial(x)=1*2*3*...*x: function fact x -> y The sign '->' is used to introduce the result of the function. 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) RecursivityWe 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 Arguments access modeThe 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 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. function zero x 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 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. 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 but then, things like this would be accepted by the compiler: var Array:Int a 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 Others possible values are 'oarg_rw', 'oarg_R', 'oarg_RW' and 'oarg_C'. Exiting the function immediatelyAt any point in a function execution, the function can be exited immediately through calling 'return' instruction with no argument: function fact x -> y If 'return' instruction is provided an argument, it will set the result before exiting: function fact x -> y 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. MethodsIn Pliant, a method is just a function that will be called with the first argument before the identifier: method s twice -> s2 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 ImplicitWhen 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 could be written as: method p sum -> z 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 variablesA 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. 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 variablesA 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" If the function is a method, just use the dotted notation introduced in the methods presentation section: method s twice -> s2 '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 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 functionsEnabling 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 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. 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 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 attributsUse C operating standard calling convension for the operating system Pliant is running on: function foo x Use C variable number of arguments calling convension: function foo x Force the function to be inlined. You should not do that because Pliant automatically decides to inline very short functions: function foo x 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 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 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 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 function foo x 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 The new definition cannot conflict with any previous one, because if it does, the new one will be used: function foo x 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 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 |