# Parameters & Delegates
Go beyond simple value passing with advanced parameter modifiers and procedural types.
## Parameter Modifiers
How a value is passed to a subroutine significantly affects both performance and behavior.
| Modifier | Description |
| :--- | :--- |
| (none) | **Value**: A copy of the value is passed. Changes inside the subroutine do not affect the original. |
| `var` | **Reference**: A pointer to the original variable is passed. Changes inside affect the original. |
| `const` | **Constant**: Passed by reference for efficiency, but the compiler prevents modification. |
| `lazy` | **Lazy**: The expression is only evaluated when accessed inside the body. This is useful for conditional logic or logging. |
## Lazy Evaluation
The `lazy` modifier is a unique feature of DWScript that defers the evaluation of an expression passed as a parameter until the moment it is actually accessed within the subroutine body.
**Key behavior:**
1. If the parameter is never accessed, the expression is never evaluated.
2. If the parameter is accessed multiple times, the expression is **re-evaluated each time**.
```pascal
procedure LogIf(condition : Boolean; lazy message : String);
begin
if condition then begin
// 'message' is evaluated here
PrintLn('LOG 1: ' + message);
// ...and re-evaluated here!
PrintLn('LOG 2: ' + message);
end;
end;
var counter := 0;
function GetStatus : String;
begin
Inc(counter);
Result := 'Status ' + IntToStr(counter);
end;
// GetStatus is NOT called here
LogIf(False, GetStatus);
// GetStatus IS called (twice!)
LogIf(True, GetStatus);
// OUTPUT
// LOG 1: Status 1
// LOG 2: Status 2
```
## Optional Parameters
You can define default values for parameters. Optional parameters must always appear at the end of the parameter list.
```pascal
procedure Connect(host : String; port : Integer = 80);
begin
PrintLn('Connecting to ' + host + ' on port ' + IntToStr(port));
end;
Connect('localhost'); // Uses port 80
Connect('localhost', 443); // Uses port 443
// OUTPUT
// Connecting to localhost on port 80
// Connecting to localhost on port 443
```
## Procedural Types (Delegates)
Procedural types allow you to treat subroutines as first-class citizens. You can assign them to variables, store them in arrays, or pass them as parameters to other subroutines.
### Standard Delegates
Points to a standalone global procedure or function.
```pascal
type
TNotifyEvent = procedure(msg: String);
// OUTPUT NONE
```
### Method Pointers
In DWScript, the `of object` syntax allows you to point to a method of a specific object instance. When the delegate is called, it executes the method in the context of that object.
```pascal
type
TClickEvent = procedure(x, y : Integer) of object;
type
TButton = class
OnClick : TClickEvent;
procedure Click(x, y : Integer);
begin
if Assigned(OnClick) then
OnClick(x, y);
end;
end;
type
TForm = class
procedure ButtonClicked(x, y : Integer);
begin
PrintLn('Button clicked at ' + IntToStr(x) + ', ' + IntToStr(y));
end;
end;
var f := new TForm;
var b := new TButton;
b.OnClick := f.ButtonClicked;
b.Click(10, 20);
// OUTPUT
// Button clicked at 10, 20
```
## Anonymous Methods
For one-off logic, you can use anonymous methods (lambdas) which can capture local variables from their surrounding scope. See the [Lambdas](/lang/advanced/lambdas) page for more details.
Parameters & Delegates
Go beyond simple value passing with advanced parameter modifiers and procedural types.
Parameter Modifiers
How a value is passed to a subroutine significantly affects both performance and behavior.
Modifier
Description
(none)
Value: A copy of the value is passed. Changes inside the subroutine do not affect the original.
var
Reference: A pointer to the original variable is passed. Changes inside affect the original.
const
Constant: Passed by reference for efficiency, but the compiler prevents modification.
lazy
Lazy: The expression is only evaluated when accessed inside the body. This is useful for conditional logic or logging.
Lazy Evaluation
The lazy modifier is a unique feature of DWScript that defers the evaluation of an expression passed as a parameter until the moment it is actually accessed within the subroutine body.
Key behavior:
If the parameter is never accessed, the expression is never evaluated.
If the parameter is accessed multiple times, the expression is re-evaluated each time.
procedure LogIf(condition :Boolean; lazy message :String);beginif condition thenbegin// 'message' is evaluated here
PrintLn('LOG 1: '+ message);// ...and re-evaluated here!
PrintLn('LOG 2: '+ message);end;end;var counter :=0;function GetStatus :String;begin
Inc(counter);
Result :='Status '+ IntToStr(counter);end;// GetStatus is NOT called here
LogIf(False, GetStatus);// GetStatus IS called (twice!)
LogIf(True, GetStatus);
Result
LOG 1: Status 1
LOG 2: Status 2
Optional Parameters
You can define default values for parameters. Optional parameters must always appear at the end of the parameter list.
procedure Connect(host :String; port :Integer=80);begin
PrintLn('Connecting to '+ host +' on port '+ IntToStr(port));end;
Connect('localhost');// Uses port 80
Connect('localhost',443);// Uses port 443
Result
Connecting to localhost on port 80
Connecting to localhost on port 443
Procedural Types (Delegates)
Procedural types allow you to treat subroutines as first-class citizens. You can assign them to variables, store them in arrays, or pass them as parameters to other subroutines.
Standard Delegates
Points to a standalone global procedure or function.
type
TNotifyEvent =procedure(msg:String);
Method Pointers
In DWScript, the of object syntax allows you to point to a method of a specific object instance. When the delegate is called, it executes the method in the context of that object.
type
TClickEvent =procedure(x, y :Integer)ofobject;type
TButton =class
OnClick : TClickEvent;procedure Click(x, y :Integer);beginif Assigned(OnClick)then
OnClick(x, y);end;end;type
TForm =classprocedure ButtonClicked(x, y :Integer);begin
PrintLn('Button clicked at '+ IntToStr(x)+', '+ IntToStr(y));end;end;var f :=new TForm;var b :=new TButton;
b.OnClick := f.ButtonClicked;
b.Click(10,20);
Result
Button clicked at 10, 20
Anonymous Methods
For one-off logic, you can use anonymous methods (lambdas) which can capture local variables from their surrounding scope. See the Lambdas page for more details.