procedure test(out foo);

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
PascalDragon
Beiträge: 963
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: procedure test(out foo);

Beitrag von PascalDragon »

Mathias hat geschrieben: Sa 23. Nov 2024, 19:00
Daher würde ich sogar sagen das der Pointer weg mit "@" sogar effektiv der bessere ist, denn nach dem motto: Besondere Semantik braucht besondere Syntax, wenn du von einem wert den Pointer nimmst weist du schon direkt beim lesen "Hey hier passiert grade was spezielles"
Dies hat noch ein Vorteil, man kann auch nil übergeben.
Geht auch mit var und Freunden ;)

Code: Alles auswählen

program tvar;

{$mode objfpc}

procedure Test1(var aArg: Integer);
begin
  Writeln(HexStr(@aArg));
end;

procedure Test2(var aArg);
begin
  Writeln(HexStr(@aArg));
end;

begin
  Test1(Integer(Nil^));
  Test2(Integer(Nil^));
end.
Ausgabe:

Code: Alles auswählen

PS C:\fpc\git> .\testoutput\tvar.exe
0000000000000000
0000000000000000
FPC Compiler Entwickler

Mathias
Beiträge: 6958
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: procedure test(out foo);

Beitrag von Mathias »

Geht auch mit var und Freunden ;)
Und wie machst du dies mit "var" ?

Code: Alles auswählen

  procedure pointerTest(i: PInteger);
  begin
    if i <> nil then begin
      i^ := 123;
    end;
  end;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 2145
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: procedure test(out foo);

Beitrag von Warf »

Code: Alles auswählen

if assigned(@i) then
Aber ob man das wirklich machen will ist eine andere frage

Mathias
Beiträge: 6958
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: procedure test(out foo);

Beitrag von Mathias »

Die wird zB. in SDL3 vielfach verwendet.

ZB. in solcher einer Function:

Code: Alles auswählen

function CreateTexture(x, y: pinteger): PTexture;
begin
  if x = nil then // Default X-Wert;
  if y = nil then // Default Y-Wert;
end;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 2145
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: procedure test(out foo);

Beitrag von Warf »

Wobei es je nach Anwendungsfall da auch bessere Optionen geht.
Z.B. wenn man nur die Möglichkeiten haben will nil zu übergeben kann man z.b. TNullPtr oder TNullable benutzen:

Code: Alles auswählen

procedure Foo(optX, optY: specialize TNullable<Integer>);
var
  x,y: Integer;
begin
  x:=optX.ValueOr(42);
  y:=optY.ValueOr(32);
  ...
end;

// Beispiel
Foo(1,2);
Foo(null,2);
Foo(1,null);
Foo(null,null);
Ich bin mir grade nicht sicher ob man für records auch einen Default wert setzen kann, falls ja kann man mit "= null" auch einen Default setzen

Ansonsten was man auch machen kann mit TNullPtr aus Trunk

Code: Alles auswählen

procedure foo(x: integer);
...
procedure foo(x: TNullPtr); inline;
begin
  foo(42);
end;
Durch inlining sollte das keine Laufzeitkosten haben, benötigt aber exponentiell viele Deklaration pro optionalen parameter

Mathias
Beiträge: 6958
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: procedure test(out foo);

Beitrag von Mathias »

Ansonsten was man auch machen kann mit TNullPtr aus Trunk
Was wird da noch für eine Unit benötigt ?
ich kann TNullPtr nicht finden. Meine Trunk ist recht aktuell.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 2145
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: procedure test(out foo);

Beitrag von Warf »

TNullPtr ist in der Unit types, sowie die konstante NullPtr die du dann Übergeben kannst

Mathias
Beiträge: 6958
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: procedure test(out foo);

Beitrag von Mathias »

Da bleibe ich lieber bei den Pointern, auch wen man da @ oder ^ machen muss.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 2145
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: procedure test(out foo);

Beitrag von Warf »

Naja es ist halt semantisch was komplett anderes. Zum einen kannst du keine Konstanten übergeben, zum anderen kann der wert überschrieben werden, was ja auch eine komplett andere Semantik hat. Zu guter letzt, ists laufzeit Polymorphismus, d.h. es gehen ein paar CPU zyklen flöten.

Beispiel:

Code: Alles auswählen

procedure Foo(x: Integer);
begin
  while x > 0 do
  begin
    WriteLn(x);
    Dec(x);
  end;
end;

procedure Foo(_: TNullPtr);inline;
begin
  Foo(3);
end;

begin
  Foo(NullPtr);
  Foo(2);
end. 
In diesem Fall wird Foo(NullPtr) wegen inlining direkt zu Foo(3) ersetzt, somit ist absolut kein Laufzeit code notwendig um den Default wert zu setzen. Gleichzeitig kann X als normaler value parameter verwendet werden, d.h. Foo hat eine eigene Kopie von x, womit dieses in der Funktion verändert werden kann, ohne das es Seiteneffekt auf die Aufrufende funktion hat.
Zu guter letzt weil es ein call by value ist, kann man die Konstante 2 übergeben, ohne sie vorher in eine Temporäre Variable schreiben zu müssen.

Das beste Beispiel wie sowas nützlich sein kann sind die Unpack funktionen von der Tuples unit:

Code: Alles auswählen

function MyTuple: specialize TTriple<Integer, Char, Double>;
begin
  Result := specialize Triple<Integer, Char, Double>(42, 'c', 3.14);
end;

...
var
  i: Integer;
  c: Char;
  d: Double;
begin
  MyTuple.Unpack(_, c, d); // Ignoriert den ersten Wert und entpackt die anderen in c und d
  MyTuple.Unpack(i, _, _); // Enpackt den ersten wert nach i und ignoriert die anderen 
end;
Und wenn du in die Unpack funktionen reinschaust siehst du das da kein einziges if-then-else drin ist, sondern das wird ausschließlich über compiletime polymorphismus gelöst und somit wird kein unnötiger code zur Laufzeit erzeugt

Antworten