Autor |
Beitrag |
dummzeuch
      
Beiträge: 593
Erhaltene Danke: 5
Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
|
Verfasst: Mi 29.10.08 21:26
Hi,
gegeben ist eine Funktion, die ein Interface als Ergebnis zurueckliefert:
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
Delphi-Quelltext
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
|
Verfasst: 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 
      
Beiträge: 593
Erhaltene Danke: 5
Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
|
Verfasst: Fr 31.10.08 21:38
Gentleman89 hat folgendes geschrieben : |
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
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 01.11.08 15:50
dummzeuch hat folgendes geschrieben : | 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 
      
Beiträge: 593
Erhaltene Danke: 5
Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
|
Verfasst: Sa 01.11.08 19:34
|
|
MSCH
      
Beiträge: 1448
Erhaltene Danke: 3
W7 64
XE2, SQL, DevExpress, DevArt, Oracle, SQLServer
|
Verfasst: 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 
      
Beiträge: 593
Erhaltene Danke: 5
Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
|
Verfasst: Sa 01.11.08 20:44
MSCH hat folgendes geschrieben : | 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:
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
      
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: 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 
      
Beiträge: 593
Erhaltene Danke: 5
Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
|
Verfasst: So 02.11.08 16:20
Martok hat folgendes geschrieben : | 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
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Di 04.11.08 19:52
dummzeuch hat folgendes geschrieben : | 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  ), 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
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Di 04.11.08 20:16
dummzeuch hat folgendes geschrieben : | 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 : | 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 : | 3. Hier im Forum wusste das auch keiner. |
Witzbold.
_________________ Na denn, dann. Bis dann, denn.
|
|
dummzeuch 
      
Beiträge: 593
Erhaltene Danke: 5
Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
|
Verfasst: Mi 05.11.08 21:50
alzaimar hat folgendes geschrieben : | dummzeuch hat folgendes geschrieben : | 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 : | 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 : | 3. Hier im Forum wusste das auch keiner. | Witzbold. |
Danke, oh Allwissender.
twm
|
|
dummzeuch 
      
Beiträge: 593
Erhaltene Danke: 5
Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
|
Verfasst: Mi 05.11.08 22:07
jaenicke hat folgendes geschrieben : | dummzeuch hat folgendes geschrieben : | 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 ...
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
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Mi 05.11.08 22:20
dummzeuch hat folgendes geschrieben : | 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!  Eine Funktion, die ein Interface, aber in einem Codepfad kein Ergebnis liefert, wird nicht bemängelt.
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  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.
dummzeuch hat folgendes geschrieben : | 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 
      
Beiträge: 593
Erhaltene Danke: 5
Delphi 5 ent, Delphi 6 bis Delphi XE8 pro
|
Verfasst: Do 06.11.08 08:22
|
|
|