Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Result einer Funktion "Stil Frage" (https://www.delphipraxis.net/171376-result-einer-funktion-stil-frage.html)

Jonas Shinaniganz 4. Nov 2012 11:42

Result einer Funktion "Stil Frage"
 
Wo grade schonmal eine ähnliche Frage gestellt wurde:
Ich habe mich schon vor einger Zeit gefragt, was in diesem Fall lesbarer / besser ist:

Delphi-Quellcode:
function Min(X1, X2 : Integer) : Integer;
begin
  if (X1 < X2) then
    Min := X1
  else
    Min := X2;
end;
VS

Delphi-Quellcode:
function Min(X1, X2 : Integer) : Integer;
begin
  if (X1 < X2) then
    Result := X1
  else
    Result := X2;
end;
Zum Einen ist es ersichtlich, was jetzt gesetzt wird. Also X1 ist Min finde Ich gut. Zum Anderen schreiben aber viele immer Result := ...

Wie ist dazu die Meinung?

Sir Rufo 4. Nov 2012 11:49

AW: Result einer Funktion "Stil Frage"
 
IMHO würde ich immer
Delphi-Quellcode:
Result
nehmen.

Jeder Andere (ausser mir) der meinen Code dann mal lesen sollte sieht auf einen Blick, dass es sich hier um den Rückgabewert der Funktion handelt

Bernhard Geyer 4. Nov 2012 11:58

AW: Result einer Funktion "Stil Frage"
 
Alte Pascal-Compiler kannten das result-Schlüsselwort noch nicht.
Die alte Version mit dem Funktionsnamen ist mehr oder minder nur noch wegen der Altkompatiblität vorhanden.

Uwe Raabe 4. Nov 2012 14:50

AW: Result einer Funktion "Stil Frage"
 
Es gibt noch einen anderen Vorteil bei der Verwendung von Result: man kann es auch als Wert verwenden - das geht bei dem Funktionsnamen nicht.

Delphi-Quellcode:
Function Sum(const Values: TBytes): Integer;
var
  B: Byte;
begin
  Result := 0;
  for B in Values do
    Result := Result + B; // bei Sum statt Result meckert hier der Compiler
end;
Sollte die Funktion keine Parameter haben meckert er zwar nicht, produziert aber eine wohl unerwünschte Rekursion.

sx2008 4. Nov 2012 15:53

AW: Result einer Funktion "Stil Frage"
 
3. Vorteil: man kann die Funktion problemlos umbenennen.
Verwendet man den Funktionsnamen anstelle von Result bringt jede Umbenennung einer Funktion zunächst Compilerfehler und dann lästiges Editieren mit sich.

himitsu 4. Nov 2012 16:52

AW: Result einer Funktion "Stil Frage"
 
Result ist immer besser.
- man erkennt genau was gemeint ist
- man kann mit dem Namen nicht rechnen
- und wenn man die Funktion umbenennt, muß man das auch immer mit anpassen

Rechnen:
In C wird meisten eine Hilfsvariable verwendet und das Ergebnis erst am Ende an RETURN übergeben.

In Delphi is t das nicht nötig, da man Result direkt verwenden kann, jedenfalls dann, wenn man nicht den funktionsnamen verwendet.

Delphi-Quellcode:
Result := 132;
...
Result := Result * 2;
...
end;
Am Beispiel von dem schon genannten "Sum" würd man schnell in einer Endlosschleife landen.
Denn "sum" wird nur bei Zuweisungen als Funktionsergebnis genommen und sonst ist es ein Aufruf.

Delphi-Quellcode:
Function Sum(const Values: TBytes): Integer;
var
  B: Byte;
begin
  Sum := 0; // entspricht Result :O 0;
  for B in Values do
    Sum := Sum + B; // hier würde es aber Result := Sum + B; sein, also ein rekursiver Aufruf
end;

Ach ja: Und das Result muß grundsätzlich immer initialisiert werden, selbst wenn man denkt, daß es bei String, dyn. Array und Interface auch ohne funtioniert.
Glaubt mir einfach, dem ist nicht so.

Uwe Raabe 4. Nov 2012 21:00

AW: Result einer Funktion "Stil Frage"
 
Zitat:

Zitat von himitsu (Beitrag 1189662)
Am Beispiel von dem schon genannten "Sum" würd man schnell in einer Endlosschleife landen.
Denn "sum" wird nur bei Zuweisungen als Funktionsergebnis genommen und sonst ist es ein Aufruf.

Delphi-Quellcode:
Function Sum(const Values: TBytes): Integer;
var
  B: Byte;
begin
  Sum := 0; // entspricht Result :O 0;
  for B in Values do
    Sum := Sum + B; // hier würde es aber Result := Sum + B; sein, also ein rekursiver Aufruf
end;

Das führt zunächst erstmal zu einem Compilerfehler, da Sum einen Parameter erwartet. Nur bei parameterlosen Funktionen kommt es zur Rekursion mit baldigem Stackoverflow (und nicht zu einer Endlosschleife).

Furtbichler 4. Nov 2012 21:03

AW: Result einer Funktion "Stil Frage"
 
Zitat:

Zitat von himitsu (Beitrag 1189662)
Und das Result muß grundsätzlich immer initialisiert werden, selbst wenn man denkt, daß es bei String, dyn. Array und Interface auch ohne funtioniert.

Und ich dachte immer, das lokale Variablen grundsätzlich initialisiert werden müssen, egal ob sie Result heißen oder Strings oder Interfaces sind. Selbst der Delph-Compiler dürfte doch eine Warnung ausgeben, oder?

Jonas Shinaniganz 4. Nov 2012 21:12

AW: Result einer Funktion "Stil Frage"
 
Okay die Frage hat sich gelohnt :) Danke!

himitsu 4. Nov 2012 21:39

AW: Result einer Funktion "Stil Frage"
 
Zitat:

Zitat von Furtbichler (Beitrag 1189686)
Und ich dachte immer, das lokale Variablen grundsätzlich initialisiert werden müssen, egal ob sie Result heißen oder Strings oder Interfaces sind. Selbst der Delph-Compiler dürfte doch eine Warnung ausgeben, oder?

Nein, der Delphi-Compiler gibt leider nicht immer eine Warnung aus.

Praktisch gesehn werden "einfach" lokale Variablen nicht initialisiert, was man, im Prinzip, als eine Optimierung ansehn kann. (unnötiger/doppelter compilerseitiger Code)

Aber gewisse Typen, speziell alle, welche von Delphi eine automatische Speicherverwaltung bekommen haben, werden prinzipbedingt auch automatisch initialisiert, dazu zählen "lange" Strings (AnsiString, RawByteString, UTF8String und UnicodeString, aber keine ShortString), WideString, dynamische Arrays, Interfaces und der Variant, bzw. OleVariant.

Denn für die speicherverwaltung braucht es unbedingt einen definierten Grundzustand.


Der Witz daran ist, daß ein Result nicht immer eine lokale Variable ist, so wie man es vermuten könnte,
denn bei oben genannten Typen, ist das in Wirklichkeit kein "Result", sondern ein Var-Parameter.
Delphi verwaltet dieses Typen, sowie auch "größere" Array und Records als zusätzlichen Var-Parameter, welcher an die anderen Parameter angehängt wird.
Wo schlußendlich die "Result-Variable herkommt, ist also unklar.

Leider geht der Compiler nun, bei den genannten Typen, davon aus, daß diese somit initialisiert sind.
Welches aber gerade beim Result nicht "direkt" stimmt.

Die externe Variable wurde ordnungsgemäß initialisiert, aber, in Bezug auf die folgende Funktion, ist dieses nicht der Fall.
Delphi-Quellcode:
function Test: string;
begin
  Result := Result + 'abc';
end;

for i := 0 to 2 do
  S := Test;
ShowMessage(S);
Was für eine Message angezeigt wird, kannst du gerne ausprobieren.
(wenn es nicht zufällig eine Schleife wäre, dann wäre es natürlich "meistens" das 'abc')

Furtbichler 5. Nov 2012 07:19

AW: Result einer Funktion "Stil Frage"
 
Ui, vielen Dank für diese Lehrstunde.

Halten wir fest:
1. Grundsätzlich sollte man (immer! ohne Ausnahme!) das Funktionsresultat initialisieren. Delphi macht das zwar machnmal, aber guter Programmierstil sollte ohne wenn und aber gleichförmig sein.
2. Der Compiler sollte die Warnung 'Rückgabewert... könnte undefiniert sein' auf alle Funktionstypen ausweiten. So wie bei C# zum Beispiel.

JamesTKirk 5. Nov 2012 08:32

AW: Result einer Funktion "Stil Frage"
 
Nur als Bemerkung am Rande: in Free Pascal ist in den Modi fpc und objfpc der Funktionsname als "rvalue" erlaubt. Möchte man hier einen rekursiven Aufruf (bei einer parameterlosen Funktion), so muss ein leeres Klammerpaar angehängt werden.

Delphi-Quellcode:
program resulttest;

{$ifdef fpc}
{$mode objfpc}
{$endif}
{$apptype console}

function Sum: LongInt;
const
  Values: array[0..4] of Byte = (
    1, 2, 3, 4, 5
  );
var
  b: Byte;
begin
  Sum := 0;
  for b in Values do
    Sum := Sum + b; // Sum() würde die Funktion rekursiv aufrufen
end;

begin
  Writeln(Sum); // ergibt "15" und nicht "stack overflow" ;)
end.
Gruß,
Sven

Stevie 5. Nov 2012 15:18

AW: Result einer Funktion "Stil Frage"
 
Zitat:

Zitat von himitsu (Beitrag 1189697)
Wo schlußendlich die "Result-Variable herkommt, ist also unklar.

Das ist keineswegs unklar, denn wie du zuvor richtigerweise ausgeführt hast, ist das ein var Parameter.
Im Fall einer Zuweisung ist es die Variable, welcher du zuweist. Andernfalls eine vom Compiler erzeugte Variable.

Das kann man sich auch in der CPU Ansicht anschauen.

Im von dir gezeigten Beispiel wird dort s übergeben

Code:
s := Test;
8D45F4           lea eax,[ebp-$0c]
E8A4FFFFFF      call Test
Weist man auf etwas zu, was nicht als var Parameter übergeben werden kann (z.b. eine Property), dann wird die compiler erzeugte Variable benutzt:
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
var
  i: Integer;
  s: string;
begin
  for i := 0 to 2 do
    Caption := Test;
  ShowMessage(s);
end;
Code:
Caption := Test;
8D45EC          lea eax,[ebp-$14]
E8A1FFFFFF      call Test
8B55EC          mov edx,[ebp-$14]
8B45FC          mov eax,[ebp-$04]
E8C662FBFF      call TControl.SetText

himitsu 5. Nov 2012 15:25

AW: Result einer Funktion "Stil Frage"
 
Ich meinte unklar, aus Sicht der Funktion.

Die Funktion weiß nicht wo die Variable ihrer Results genau herkomm. Das kann eine Globale sein, irgenein Feld einer Klasse oder eine fremde Lokale.
Ist aber im Prinzip auch egal, da die Funktion nicht sicher sein kann, daß die externe Variable "leer" ist.

Darlo 5. Nov 2012 15:33

AW: Result einer Funktion "Stil Frage"
 
Zitat:

Zitat von himitsu (Beitrag 1189697)
Die externe Variable wurde ordnungsgemäß initialisiert, aber, in Bezug auf die folgende Funktion, ist dieses nicht der Fall.
Delphi-Quellcode:
function Test: string;
begin
  Result := Result + 'abc';
end;

for i := 0 to 2 do
  S := Test;
ShowMessage(S);

Autsch... muss gleich mal ein paar Funktionen durchgehen...


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:26 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz