Difference between revisions of "How to use procedural variables"

From Lazarus wiki
m (Actually add page template :-)
 
(15 intermediate revisions by 8 users not shown)
Line 1: Line 1:
=== These are also known as procedural pointers. ===
+
{{How_to_use_procedural_variables}}
  
 +
Copy the text below and it will demonstrate the use of procedural variables, this is a fully working program. You don't even need to understand how it works. The syntax is pretty simple.
  
Copy the text below and it will demonstrate the use of function pointers, this is a full working program. You don't even need to understand how it works the syntax is pretty simple.
+
<syntaxhighlight lang=pascal>
 
+
program Test;
----
 
<pre>
 
program test;
 
  
 
{$mode objfpc}{$H+}
 
{$mode objfpc}{$H+}
Line 13: Line 11:
 
   cthreads,
 
   cthreads,
 
   {$ENDIF}{$ENDIF}
 
   {$ENDIF}{$ENDIF}
   Classes
+
   Classes;
  { add your units here };
+
 
//Make the Types the type corresponds to a function signature
+
// Make the Types the type corresponds to a function signature
 
type
 
type
    TFuncNoArgs_String = function():String;
+
  TFuncNoArgsString = function(): String;
    TFuncOneArgs_String = function(x:string):string;
+
  TFuncOneArgsString = function(x: string): string;
  
//example functions
+
// Example functions
function Hello():String;
+
function Hello: String;
 
begin
 
begin
    result:='Hello There';
+
  Result := 'Hello There';
 
end;
 
end;
function Woah(G:String):String;
+
 
 +
function Woah(G: String): String;
 
begin
 
begin
    result:='Woah ' + G;
+
  Result := 'Woah ' + G;
 
end;
 
end;
  
//overloaded function takes the two types of function
+
// Overloaded function takes the two types of function
//pointers created above
+
// pointers created above
procedure Take(f:TFuncNoArgs_String);overload;
+
procedure Take(f: TFuncNoArgsString); overload;
 
begin
 
begin
    writeln(f());
+
  WriteLn(f());
 
end;
 
end;
  
procedure Take(f:TFuncOneArgs_String);overload;
+
procedure Take(f: TFuncOneArgsString); overload;
 
begin
 
begin
    writeln(f('there!!!'));
+
  WriteLn(f('there!!!'));
 
end;
 
end;
  
 +
var
 +
  ptr: Pointer;
 +
  List: TList;
 
begin
 
begin
// the "@" symbol turns the variable into a pointer.
+
  // the "@" symbol turns the variable into a pointer.
// This must be done in order pass a function as a  
+
  // This must be done in order pass a function as a
// paramater.  This also demonstrates that pascal
+
  // parameter.  This also demonstrates that pascal
// keeps track of the pointer type so the overloading works!
+
  // keeps track of the pointer type so the overloading works!
 +
 
 +
  Take(@Hello);
 +
  Take(@Woah);
  
Take(@Hello);
+
  // Now put a function in an untyped pointer
Take(@Woah);
+
  ptr := @Hello;
readln;
+
  // Type the pointer and call it all at the same time
end.  
+
  WriteLn(TFuncNoArgsString(ptr));
</pre>
+
  // A TList Example
 +
  List := TList.Create;
 +
  List.Add(@Hello);
 +
  WriteLn(TFuncNoArgsString(List[0]));
 +
  ReadLn;
 +
end.</syntaxhighlight>
  
----
+
With <code>{$modeswitch classicprocvars+}</code> the [[@|<code>@</code>-address-operator]] is not necessary to refer to methods.
 +
Also, if you are using the <code>@</code>-address-operator usage of <code>{$typedaddress on}</code> is advised in order to prevent programming mistakes.

Latest revision as of 08:30, 17 February 2020

English (en)

Copy the text below and it will demonstrate the use of procedural variables, this is a fully working program. You don't even need to understand how it works. The syntax is pretty simple.

program Test;

{$mode objfpc}{$H+}
uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes;

// Make the Types the type corresponds to a function signature
type
  TFuncNoArgsString = function(): String;
  TFuncOneArgsString = function(x: string): string;

// Example functions
function Hello: String;
begin
  Result := 'Hello There';
end;

function Woah(G: String): String;
begin
  Result := 'Woah ' + G;
end;

// Overloaded function takes the two types of function
// pointers created above
procedure Take(f: TFuncNoArgsString); overload;
begin
  WriteLn(f());
end;

procedure Take(f: TFuncOneArgsString); overload;
begin
  WriteLn(f('there!!!'));
end;

var
  ptr: Pointer;
  List: TList;
begin
  // the "@" symbol turns the variable into a pointer.
  // This must be done in order pass a function as a
  // parameter.  This also demonstrates that pascal
  // keeps track of the pointer type so the overloading works!

  Take(@Hello);
  Take(@Woah);

  // Now put a function in an untyped pointer
  ptr := @Hello;
  // Type the pointer and call it all at the same time
  WriteLn(TFuncNoArgsString(ptr));
  // A TList Example
  List := TList.Create;
  List.Add(@Hello);
  WriteLn(TFuncNoArgsString(List[0]));
  ReadLn;
end.

With {$modeswitch classicprocvars+} the @-address-operator is not necessary to refer to methods. Also, if you are using the @-address-operator usage of {$typedaddress on} is advised in order to prevent programming mistakes.