Difference between revisions of "Function"

From Lazarus wiki
Jump to navigationJump to search
(→‎return value: noStackFrame)
(→‎top: relink)
 
(8 intermediate revisions by 3 users not shown)
Line 3: Line 3:
 
A '''function''' is a [[Routine|routine]] that, in contrast to [[Procedure|procedures]], returns a value.
 
A '''function''' is a [[Routine|routine]] that, in contrast to [[Procedure|procedures]], returns a value.
 
A call of a function is virtually substituted by its return value.
 
A call of a function is virtually substituted by its return value.
If the [[sExtendedsyntax|<syntaxhighlight lang="pascal" enclose="none">{$extendedSyntax}</syntaxhighlight> compiler switch]] state is off, function calls can not appear as non-productive statements, but have to be or be part of an expression.
+
If the [[$extendedSyntax|<syntaxhighlight lang="pascal" inline>{$extendedSyntax}</syntaxhighlight> compiler switch]] state is off, function calls can not appear as non-productive statements, but have to be or be part of an [[expression]].
  
The word <syntaxhighlight lang="pascal" enclose="none">function</syntaxhighlight> is a [[Reserved word|reserved word]].
+
The word <syntaxhighlight lang="pascal" inline>function</syntaxhighlight> is a [[Reserved word|reserved word]].
  
== return value ==
+
== Return value ==
In addition to a normal procedure, a function's formal signature contains a return [[Data type|type]]:
+
 
 +
In addition to a normal procedure, a function’s formal signature contains a return [[Data type|type]]:
 
The formal parameter list has to be succeeded by a [[Colon|colon]] and return type.
 
The formal parameter list has to be succeeded by a [[Colon|colon]] and return type.
For instance the following function returns a [[Boolean|<syntaxhighlight lang="pascal" enclose="none">boolean</syntaxhighlight>]].
+
For instance the following function returns a [[Boolean|<syntaxhighlight lang="pascal" inline>Boolean</syntaxhighlight>]].
 +
 
 
<syntaxhighlight lang="pascal">
 
<syntaxhighlight lang="pascal">
function myFunction(const firstParameter: real): boolean;
+
function myFunction(const firstParameter: real): Boolean;
 
</syntaxhighlight>
 
</syntaxhighlight>
  
When implementing functions there are several ways to define the function's return value.
+
When implementing functions there are several ways to define the function’s return value.
 +
 
 
<syntaxhighlight lang="pascal" line highlight="10">
 
<syntaxhighlight lang="pascal" line highlight="10">
 
program functionDemo(input, output, stderr);
 
program functionDemo(input, output, stderr);
Line 29: Line 32:
 
end;
 
end;
 
</syntaxhighlight>
 
</syntaxhighlight>
If <syntaxhighlight lang="pascal" enclose="none">{$modeswitch result+}</syntaxhighlight>, which is set by [[Mode ObjFPC|<syntaxhighlight lang="pascal" enclose="none">{$mode objFPC}</syntaxhighlight>]] and [[Mode Delphi|<syntaxhighlight lang="pascal" enclose="none">{$mode Delphi}</syntaxhighlight>]], inside the implementation block the special [[Identifier|identifier]] <syntaxhighlight lang="pascal" enclose="none">result</syntaxhighlight> is available, too:
+
 
 +
If <syntaxhighlight lang="pascal" inline>{$modeswitch result+}</syntaxhighlight>, which is set by [[Mode ObjFPC|<syntaxhighlight lang="pascal" inline>{$mode objFPC}</syntaxhighlight>]] and [[Mode Delphi|<syntaxhighlight lang="pascal" inline>{$mode Delphi}</syntaxhighlight>]], inside the implementation block the special [[Identifier|identifier]] <syntaxhighlight lang="pascal" inline>result</syntaxhighlight> is available, too:
 +
 
 
<syntaxhighlight lang="pascal" line start="13" highlight="4">
 
<syntaxhighlight lang="pascal" line start="13" highlight="4">
 
// using special `result` identifier
 
// using special `result` identifier
Line 37: Line 42:
 
end;
 
end;
 
</syntaxhighlight>
 
</syntaxhighlight>
Additionally, in <syntaxhighlight lang="pascal" enclose="none">{$mode objFPC}</syntaxhighlight>  the routine {{Doc|package=RTL|unit=system|identifier=exit|text=<syntaxhighlight lang="pascal" enclose="none">exit</syntaxhighlight>}} will set the return value, too, ''and'' leave the stack frame.
+
 
In the previous two examples further statements could have appeared, and they would have been executed, whilst after an <syntaxhighlight lang="pascal" enclose="none">exit</syntaxhighlight> the routine is ''done''.
+
Additionally, in <syntaxhighlight lang="pascal" inline>{$mode objFPC}</syntaxhighlight>  the routine {{Doc|package=RTL|unit=system|identifier=exit|text=<syntaxhighlight lang="pascal" inline>exit</syntaxhighlight>}} will set the return value, too, ''and'' leave the stack frame.
This is the behavior a <syntaxhighlight lang="C" enclose="none">return</syntaxhighlight> statement in C or other programming languages has.
+
In the previous two examples further statements could have appeared, and they would have been executed, whilst after an <syntaxhighlight lang="pascal" inline>exit</syntaxhighlight> the routine is ''done''.
 +
This is the behavior a <syntaxhighlight lang="C" inline>return</syntaxhighlight> statement in C or other programming languages has.
 +
 
 
<syntaxhighlight lang="pascal" line start="19" highlight="4">
 
<syntaxhighlight lang="pascal" line start="19" highlight="4">
 
// using exit routine
 
// using exit routine
function even(const x: longint): boolean;
+
function even(const x: longint): Boolean;
 
begin
 
begin
 
exit(not odd(x));
 
exit(not odd(x));
 
end;
 
end;
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 
In [[Assembly language|assembly language]] other rules apply.
 
In [[Assembly language|assembly language]] other rules apply.
 
If the return type is an integral value, the accumulator register is used, provided it fits in there:
 
If the return type is an integral value, the accumulator register is used, provided it fits in there:
 +
 
<syntaxhighlight lang="pascal" line start="25" highlight="9,12,23">
 
<syntaxhighlight lang="pascal" line start="25" highlight="9,12,23">
 
// in assembly language:
 
// in assembly language:
 
// return type fits into a single register => use accumulator register
 
// return type fits into a single register => use accumulator register
function zero(const x: int64): boolean;
+
function zero(const x: int64): Boolean;
 
{$ifDef CPUx86_64}
 
{$ifDef CPUx86_64}
 
assembler; register;
 
assembler; register;
Line 59: Line 68:
 
// xor modifies flags => put it in front of test
 
// xor modifies flags => put it in front of test
 
xor rax, rax    // rax := 0    (remove residue)
 
xor rax, rax    // rax := 0    (remove residue)
+
 
test x, x        // x = 0 ?
 
test x, x        // x = 0 ?
 
setz al          // rax := ZF
 
setz al          // rax := ZF
Line 76: Line 85:
 
{$endIf}
 
{$endIf}
 
</syntaxhighlight>
 
</syntaxhighlight>
Otherwise, depending on which [[sAsmmode|<syntaxhighlight lang="pascal" enclose="none">{$asmMode}</syntaxhighlight>]] is active, the <syntaxhighlight lang="asm" enclose="none">@result</syntaxhighlight> (Intel) or <syntaxhighlight lang="asm" enclose="none">__result</syntaxhighlight> (AT&T) macro can be used.
+
 
<syntaxhighlight lang="pascal" line start="48" highlight="20,31,36,40,41">
+
Otherwise, depending on which [[sAsmmode|<syntaxhighlight lang="pascal" inline>{$asmMode}</syntaxhighlight>]] is active, the <syntaxhighlight lang="asm" inline>@result</syntaxhighlight> (Intel) or <syntaxhighlight lang="asm" inline>__result</syntaxhighlight> (AT&T) macro can be used.
 +
 
 +
<syntaxhighlight lang="pascal" line start="51" highlight="20,31,36,40,41">
 
type
 
type
 
bodyAttributes = record
 
bodyAttributes = record
Line 122: Line 133:
 
{$endIf}
 
{$endIf}
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 
Originally Pascal expected ''exact one'' [[Becomes|assignment]] to the result variable (whichever is used).
 
Originally Pascal expected ''exact one'' [[Becomes|assignment]] to the result variable (whichever is used).
 
[[FPC]] however does not prohibit multiple assignments.
 
[[FPC]] however does not prohibit multiple assignments.
 
It will emit a warning if none of the possible result identifiers were used or the exit routine is not written.
 
It will emit a warning if none of the possible result identifiers were used or the exit routine is not written.
 +
 
<blockquote>
 
<blockquote>
 
; Warning: Function result does not seem to be set
 
; Warning: Function result does not seem to be set
: You can get this warning if the compiler thinks that a function return value is not set. This will not be displayed for assembler procedures, or procedures that contain assembler blocks.
+
: You can get this warning if the [[Compiler|compiler]] thinks that a function return value is not set. This will not be   displayed for assembler procedures, or procedures that contain assembler blocks.
 
</blockquote>
 
</blockquote>
<syntaxhighlight lang="pascal" line start="92">
+
 
 +
<syntaxhighlight lang="pascal" line start="95">
 
begin
 
begin
 
writeLn(sphere(2.0).surfaceArea);
 
writeLn(sphere(2.0).surfaceArea);
Line 135: Line 149:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
== see also ==
+
Note, in the case of [[Operator overloading|operator overloads]], a special form of a function, a result variable identifier has to be declared in the formal signature.
 +
See the article for details.
 +
 
 +
== Remarks ==
 +
 
 +
[[Pure functions]] are functions that do not depend on an external state.
 +
 
 +
== See also ==
 +
 
 +
* [[Pascal basics]]
 
* [https://www.freepascal.org/docs-html/ref/refch14.html § “Using functions and procedures” in the Reference Guide]
 
* [https://www.freepascal.org/docs-html/ref/refch14.html § “Using functions and procedures” in the Reference Guide]
* [https://www.freepascal.org/docs-html/prog/progse10.html § “Intel 80x86 Inline assembler” in the Programmer's Guide]
+
* [https://www.freepascal.org/docs-html/prog/progse10.html § “Intel 80x86 Inline assembler” in the Programmer’s Guide]

Latest revision as of 14:48, 20 February 2021

Deutsch (de) English (en) español (es) suomi (fi) français (fr) русский (ru)

A function is a routine that, in contrast to procedures, returns a value. A call of a function is virtually substituted by its return value. If the {$extendedSyntax} compiler switch state is off, function calls can not appear as non-productive statements, but have to be or be part of an expression.

The word function is a reserved word.

Return value

In addition to a normal procedure, a function’s formal signature contains a return type: The formal parameter list has to be succeeded by a colon and return type. For instance the following function returns a Boolean.

function myFunction(const firstParameter: real): Boolean;

When implementing functions there are several ways to define the function’s return value.

 1program functionDemo(input, output, stderr);
 2
 3{$mode objFPC}
 4
 5// traditional syntax:
 6// the result is stored in the variable
 7// its name is the same as the function's
 8function myLine(const x: real): real;
 9begin
10	myLine := 0.5 * x + 2;
11end;

If {$modeswitch result+}, which is set by {$mode objFPC} and {$mode Delphi}, inside the implementation block the special identifier result is available, too:

13// using special `result` identifier
14function myParabola(const x: real): real;
15begin
16	result := sqr(x) - 1;
17end;

Additionally, in {$mode objFPC} the routine exit will set the return value, too, and leave the stack frame. In the previous two examples further statements could have appeared, and they would have been executed, whilst after an exit the routine is done. This is the behavior a return statement in C or other programming languages has.

19// using exit routine
20function even(const x: longint): Boolean;
21begin
22	exit(not odd(x));
23end;

In assembly language other rules apply. If the return type is an integral value, the accumulator register is used, provided it fits in there:

25// in assembly language:
26// return type fits into a single register => use accumulator register
27function zero(const x: int64): Boolean;
28{$ifDef CPUx86_64}
29assembler; register;
30{$asmMode intel}
31asm
32	// xor modifies flags => put it in front of test
33	xor rax, rax     // rax := 0    (remove residue)
34	
35	test x, x        // x = 0 ?
36	setz al          // rax := ZF
37	
38	// When you examine the assembler output
39	// you will notice the compiler automatically inserts code
40	// that moves the contents of rax to the right spot on the stack,
41	// unless the noStackFrame hint
42	// (automatically set by some optimization levels)
43	// instructs the compiler to omit the stack frame if possible.
44end;
45{$else}
46begin
47	result := x = 0;
48end;
49{$endIf}

Otherwise, depending on which {$asmMode} is active, the @result (Intel) or __result (AT&T) macro can be used.

51type
52	bodyAttributes = record
53		surfaceArea: real;
54		volume: real;
55	end;
56
57// in assembly language:
58// return type doesn't fit into accumulator => @result macro gives address
59function sphere(const radius: real): bodyAttributes;
60{$ifDef CPUx86_64}
61assembler;
62{$asmMode intel}
63const
64	three: longint = 3;
65	four: longint = 4;
66var
67	r: real;
68asm
69	pextrq r, radius, 0 // r := (@radius+0)^
70	lea rax, @result    // rax := @result
71	fld r               // radius
72	
73	fld st(0)           // radius radius
74	fild four           // 4 radius radius
75	fldpi               // pi 4 radius radius
76	fmul                // 4*pi radius radius
77	fxch                // radius 4*pi radius
78	fld st(0)           // radius radius 4*pi radius
79	fmul                // radius^2 4*pi radius
80	fmul                // 4*pi*radius^2 radius
81	fst [rax].bodyAttributes.surfaceArea
82	
83	fmul                // 4*pi*radius^3
84	fild three          // 3 4*pi*radius^3
85	fdivp               // 4/3*pi*radius^3
86	fst [rax].bodyAttributes.volume
87end;
88{$else}
89begin
90	sphere.surfaceArea := 4 * pi() * sqr(radius);
91	sphere.volume := 4 / 3 * pi() * sqr(radius) * abs(radius);
92end;
93{$endIf}

Originally Pascal expected exact one assignment to the result variable (whichever is used). FPC however does not prohibit multiple assignments. It will emit a warning if none of the possible result identifiers were used or the exit routine is not written.

Warning
Function result does not seem to be set
You can get this warning if the compiler thinks that a function return value is not set. This will not be displayed for assembler procedures, or procedures that contain assembler blocks.
95begin
96	writeLn(sphere(2.0).surfaceArea);
97end.

Note, in the case of operator overloads, a special form of a function, a result variable identifier has to be declared in the formal signature. See the article for details.

Remarks

Pure functions are functions that do not depend on an external state.

See also