Autor Beitrag
dummzeuch
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 593
Erhaltene Danke: 5


Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
BeitragVerfasst: Mi 29.10.08 21:26 
Hi,

gegeben ist eine Funktion, die ein Interface als Ergebnis zurueckliefert:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
function SomeFunc: ISomeInterface;
begin
  if IrgendeineBedingung then
    Result := TIrgendeinObjekt.Create;
end;


Dabei ist TIrgendeinObjekt eine Klasse, die ISomeInterface implementiert, und IrgendeineBedingung eine Funktion, die ein Boolean zurueckliefert.

Frage: Was liefert SomeFunc, wenn IrgendeineBedingung False ist?

Ich weiss, dass Interface-Variablen vom Compiler immer mit NIL initialisiert werden, aber gilt das auch fuer das Funktionsergebnis?

Muss ich evtl. noch ein
ausblenden Delphi-Quelltext
1:
  Result := nil;					

als erste Zeile einfuegen?

Hintergrund:
Ich hatte heute einen Bug, der nur manchmal auftrat. Das liess sich eigentlich nur damit erklaeren laesst, dass Result in diesem Fall nicht immer auf NIL initialisiert wird, aber manchmal schon. Nachdem ich ein Result := NIL; eingefuegt hatte, trat der Bug immer auf und war damit leicht zu finden.

twm
Gentleman89
Hält's aus hier
Beiträge: 5

Win XP
D7 Prof, TurboDelphi 2006
BeitragVerfasst: Fr 31.10.08 20:44 
Hallo,

eigentlich müsste die Funktion in diesem Fall den Wert nil zurückgeben.

Allerdings kannst du doch entweder am Beginn der Funktion ein Result:= nil setzen, oder einfach einen else-Zweig einbauen, der den Fall mit Result:= nil bedient. Das dürfte doch kein großes Problem darstellen?


Gruß,

Lennard
dummzeuch Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 593
Erhaltene Danke: 5


Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
BeitragVerfasst: Fr 31.10.08 21:38 
user profile iconGentleman89 hat folgendes geschrieben Zum zitierten Posting springen:

eigentlich müsste die Funktion in diesem Fall den Wert nil zurückgeben.


Das dachte ich eigentlich auch, bis ich dann diesen komischen Fehler hatte.

Zitat:

Allerdings kannst du doch entweder am Beginn der Funktion ein Result:= nil setzen, oder einfach einen else-Zweig einbauen, der den Fall mit Result:= nil bedient. Das dürfte doch kein großes Problem darstellen?


Die eigentliche Funktion, um die es mir geht, ist deutlich komplexer als ein einfaches if/then/else Statement, insbesondere enthaelt sie mehrere Exits. Das oben ist nur ein Beispiel. Klar, kann ich am Anfang ein Result := nil einfuegen, ich wollte halt wissen, ob bzw. warum es notwendig ist.

twm
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 01.11.08 15:50 
user profile icondummzeuch hat folgendes geschrieben Zum zitierten Posting springen:
Frage: Was liefert SomeFunc, wenn IrgendeineBedingung False ist?
Zufall, das kannst du nicht wissen, deshalb kommt ja auch eine entsprechende Warnung des Compilers, dass das Funktionsergebnis nicht immer definiert ist.

Da kann ein Pointer auf eine beliebige Adresse herauskommen, oder eben nil, aber was weißt du schlicht nicht.
dummzeuch Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 593
Erhaltene Danke: 5


Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
BeitragVerfasst: Sa 01.11.08 19:34 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
user profile icondummzeuch hat folgendes geschrieben Zum zitierten Posting springen:
Frage: Was liefert SomeFunc, wenn IrgendeineBedingung False ist?
Zufall, das kannst du nicht wissen, deshalb kommt ja auch eine entsprechende Warnung des Compilers, dass das Funktionsergebnis nicht immer definiert ist.

Da kann ein Pointer auf eine beliebige Adresse herauskommen, oder eben nil, aber was weißt du schlicht nicht.


Der Compiler liefert keine Warnung (Delphi 2007)

twm
MSCH
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1448
Erhaltene Danke: 3

W7 64
XE2, SQL, DevExpress, DevArt, Oracle, SQLServer
BeitragVerfasst: Sa 01.11.08 19:52 
Delphi initialisiert nur Variablen mit nil (sofern Zeiger). Funktionen die einen Zeiger zurückgeben, liefern irgentwas zurück wenn nicht mit Result:=xx der Wert gesetzt wird.

Nunja, es zeugt von keinem guten Quellcode, wenn du Variablen und Funktionen (-deren Rückgabe) nicht initialisiert. Bei C# wirst du mit solchem Code nicht weit kommen, das lehnt das der Compiler ab.

:-)msch

_________________
ist das politisch, wenn ich linksdrehenden Joghurt haben möchte?
dummzeuch Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 593
Erhaltene Danke: 5


Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
BeitragVerfasst: Sa 01.11.08 20:44 
user profile iconMSCH hat folgendes geschrieben Zum zitierten Posting springen:
Delphi initialisiert nur Variablen mit nil (sofern Zeiger). Funktionen die einen Zeiger zurückgeben, liefern irgentwas zurück wenn nicht mit Result:=xx der Wert gesetzt wird.


Delphi initialisiert (lokale) Variablen nur in Ausnahmefaellen: Strings als Leerstrings und Interfaces mit NIL. Alle anderen sind undefiniert, egal ob Pointer oder integer. Normalerweise gibt es dann aber auch eine Compiler-Warnung, wenn man sie benutzt, ohne sie zu initialisieren. Das gilt auch fuer Funktionsergebnisse:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
function SomeFunc: integer;
begin
  if BoolscherAusdruck then
    result := 1;
end;


liefert die Warnung: "Result of function SomeFunc might not have been initialized" (oder so aehnlich)

Bei Funktionen, die Strings oder Interfaces zurueckliefern, gibt es keine Warnung, also war ich bisher davon ausgegangen, dass dort eine automatische Initialisierung stattfindet, genauso wie bei den Variablen. Das scheint aber nicht der Fall zu sein.

Zitat:

Nunja, es zeugt von keinem guten Quellcode, wenn du Variablen und Funktionen (-deren Rückgabe) nicht initialisiert. Bei C# wirst du mit solchem Code nicht weit kommen, das lehnt das der Compiler ab.


Ich bin kein C# Spezialist (hab' nie was damit gemacht), aber ist es nicht gerade bei C# so, dass Variablen automatisch initialisiert werden, weil sie alle als Objekte betrachtet werden? (oder war das in Java?)

twm
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: So 02.11.08 04:21 
Eventuell ist das ja die Unterscheidung, die Varianten als Unassigned vs. Null abbilden?

Das Interface an sich müsste ja eigentlich initialisiert werden: mit seiner GUID. Zumindest ist das ja das, was der Debugger dann anzeigt. Nur nutzt die GUID allein nicht viel...

Bei dieser Interpretation stellt sich aber die Frage, warum es dann nicht immer Fehler gab.

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
dummzeuch Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 593
Erhaltene Danke: 5


Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
BeitragVerfasst: So 02.11.08 16:20 
user profile iconMartok hat folgendes geschrieben Zum zitierten Posting springen:
Eventuell ist das ja die Unterscheidung, die Varianten als Unassigned vs. Null abbilden?

Das Interface an sich müsste ja eigentlich initialisiert werden: mit seiner GUID. Zumindest ist das ja das, was der Debugger dann anzeigt. Nur nutzt die GUID allein nicht viel...

Bei dieser Interpretation stellt sich aber die Frage, warum es dann nicht immer Fehler gab.


Interfaces in Delphi haben nicht notwendigerweise eine GUID. In diesem Fall hat es aber eine.

Und die Frage, warum der Fehler nicht immer auftrat, war der Grund, weshalb ich hier nachgefragt habe. Konkret hatte ich schlichtweg vergessen, in einem der If-Zweige Result zu setzen und das knallte dann manchmal (bei einer speziellen Eingabe), aber komischerweise nicht immer. Wenn Result automatisch mit NIL initialisiert wuerde, haette es immer knallen muessen.

Ok, was lernen wir daraus:
1. Bei Funktionen, die ein Interface zurueckliefern, muss man Result auf jeden Fall setzen, auch auf NIL.
2. Delphi (20007) gibt keine Warnung aus, wenn man es nicht tut.
3. Hier im Forum wusste das auch keiner.

twm
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 04.11.08 19:52 
user profile icondummzeuch hat folgendes geschrieben Zum zitierten Posting springen:
2. Delphi (20007) gibt keine Warnung aus, wenn man es nicht tut.
Da ich ohnehin generell alles initialisiere (ich initialisiere ja auch z.B. meine Tasse mit leer bevor ich was eingieße, wenn da noch was drin sein sollte :D), habe ich das Verhalten des Compilers da nicht so verfolgt.

Generell sollte der Compiler, wenn es für ihn erkennbar ist, dass eine Variable bzw. ein Funktionsergebnis uninitialisiert sein kann, eine Warnung ausgeben. Bei komplizierteren Sachen als das oben genannte Beispiel ist das aber nicht unbedingt ohne weiteres erkennbar und dann gibt es natürlich auch keine Warnung.
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Di 04.11.08 20:16 
user profile icondummzeuch hat folgendes geschrieben Zum zitierten Posting springen:
Ok, was lernen wir daraus:
1. Bei Funktionen, die ein Interface zurueckliefern, muss man Result auf jeden Fall setzen, auch auf NIL.
Sollte man als guter Entwickler sowieso machen.

und hat folgendes geschrieben Zum zitierten Posting springen:
2. Delphi (20007) gibt keine Warnung aus, wenn man es nicht tut.
Außer, man stellt es in den Compileroptionen ein.

und dann hatta auch noch hat folgendes geschrieben Zum zitierten Posting springen:
3. Hier im Forum wusste das auch keiner.
Witzbold.

_________________
Na denn, dann. Bis dann, denn.
dummzeuch Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 593
Erhaltene Danke: 5


Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
BeitragVerfasst: Mi 05.11.08 21:50 
user profile iconalzaimar hat folgendes geschrieben Zum zitierten Posting springen:
user profile icondummzeuch hat folgendes geschrieben Zum zitierten Posting springen:
Ok, was lernen wir daraus:
1. Bei Funktionen, die ein Interface zurueckliefern, muss man Result auf jeden Fall setzen, auch auf NIL.
Sollte man als guter Entwickler sowieso machen.


Ueber nunnoetige Initialisierung kann man sich vermutlich leanger streiten als ich Lust habe.

Zitat:

und hat folgendes geschrieben Zum zitierten Posting springen:
2. Delphi (20007) gibt keine Warnung aus, wenn man es nicht tut.
Außer, man stellt es in den Compileroptionen ein.


Ich habe alle, ausser den dotNET- und platform-warnings, eingeschaltet. Ebenso alle Hints.

Meine Programme produzieren idealerweise keins von beidem mehr.

Zitat:

und dann hatta auch noch hat folgendes geschrieben Zum zitierten Posting springen:
3. Hier im Forum wusste das auch keiner.
Witzbold.


Danke, oh Allwissender.

twm
dummzeuch Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 593
Erhaltene Danke: 5


Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
BeitragVerfasst: Mi 05.11.08 22:07 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
user profile icondummzeuch hat folgendes geschrieben Zum zitierten Posting springen:
2. Delphi (20007) gibt keine Warnung aus, wenn man es nicht tut.
Da ich ohnehin generell alles initialisiere (ich initialisiere ja auch z.B. meine Tasse mit leer bevor ich was eingieße, wenn da noch was drin sein sollte :D), habe ich das Verhalten des Compilers da nicht so verfolgt.

Also ich hole mir lieber eine frische Tasse aus dem Schrank und verlasse mich darauf, dass ich sie nicht "initialisieren" brauche.

Zitat:

Generell sollte der Compiler, wenn es für ihn erkennbar ist, dass eine Variable bzw. ein Funktionsergebnis uninitialisiert sein kann, eine Warnung ausgeben. Bei komplizierteren Sachen als das oben genannte Beispiel ist das aber nicht unbedingt ohne weiteres erkennbar und dann gibt es natürlich auch keine Warnung.


Sowas ...
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
function TEineKlasse.bla: IEinInterface;
begin
  if bedingung1 then
    Result := self
  else if Bedingung2 then
   exit
  else if Bedingung3 then
    Result := TEineAndereKlasse.Create
  else if Bedingung4 then
    exit
  else if Bedingung5 then
    Result := TEineDritteKlasse.Create;
  if Bedingung6 then
    EineAndereMethode;
end;


... halte ich nicht fuer besonders kompliziert. Wie man sieht, gibt es zwei exits, welche dazu fuehrten, dass Result nicht gesetzt wird. Ich bin der Meinung, dass der Compiler das durchaus feststellen koennte.

Naja, egal, ich weiss jetzt, dass ich mich darauf nicht verlassen kann.

Viel witziger sind Funktionen, bei denen man einerseits eine Warnung bekommt, dass das Ergbenis nicht initialisiert sei, andererseits, wenn man das dann am Funktionsanfang prophylaktisch tut, einen Hinweis, dass dieser Wert nicht verwendet wird.

twm
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Mi 05.11.08 22:20 
user profile icondummzeuch hat folgendes geschrieben Zum zitierten Posting springen:
Ueber nunnoetige Initialisierung kann man sich vermutlich leanger streiten als ich Lust habe.

Eine undefiniertes Funktionsergebnis ist nicht direkt 'unnötig', sondern eher Grundvoraussetzung für ordendlichen Code. Und streiten muss man deswegen wirklich nicht, weil es ja -wie gesagt- Grundvoraussetzung ist.

Aber Du hast Recht! :beer: Eine Funktion, die ein Interface, aber in einem Codepfad kein Ergebnis liefert, wird nicht bemängelt.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
Function Foo : IUnknown;
Begin
End;

Function Bar : Integer;
Begin
End;

'Foo' wird nicht bemängelt, 'Bar' schon.
Übrigens kein Wunder, dass das keiner im Forum weiss: Man implementiert hier auch normalerweise vollständige Funktionen, auch wenn sie Interfaces liefern :mrgreen: Und da wir das tun, fällt eben nicht auf, wenn man es nicht macht.

Nun sind wir also -dank Dir- alle um eine überflüssige (außer für Dich) Information reicher. Du wirst nun also Interface-Funktionen vollständig implementieren. Andere zwar nicht, weil das ja eine 'unnötige Initialisierung' ist, aber das ist ja dein Bier.

Um es kurz zu machen (was ich eigentlich sagen wollte): Deine strunzdämliche letzte Bemerkung (Punkt 3) solltest du dir einfach sparen, denn es war ein wunderbares Eigentor aber es war wenigstens deinem Nick entsprechend. :wink:

user profile icondummzeuch hat folgendes geschrieben Zum zitierten Posting springen:
Viel witziger sind Funktionen, bei denen man einerseits eine Warnung bekommt, dass das Ergbenis nicht initialisiert sei, andererseits, wenn man das dann am Funktionsanfang prophylaktisch tut, einen Hinweis, dass dieser Wert nicht verwendet wird.
Hast mal ein Beispiel parat?

_________________
Na denn, dann. Bis dann, denn.
dummzeuch Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 593
Erhaltene Danke: 5


Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
BeitragVerfasst: Do 06.11.08 08:22 
end of thread