Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Funktionsaufruf mit Null-Werten


sbdre - Mi 03.11.10 15:06
Titel: Funktionsaufruf mit Null-Werten
Hallo Delphi-Programmierer,

ich bin an folgendes Problem bei Funktionsaufrufen geraten.
Zunächst der Quellcode:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
procedure MyTest(x : string ; b : boolean ; i : integer);
begin
  //inhalt egal
end;

MyTest(Null,Null,Null);


Der obige Code lässt sich compilieren, was ich sehr überraschend finde. D.h. Delphi (Delphi 2009) erkennt den Typkonflikt nicht.

Zur Laufzeit wird dann eine Exception ausgelöst:
"Variante des Typs (Null) konnte nicht in Typ (Integer) konvertiert werden"
[Delphi beginnt beim letzten Parameter, spielt aber keine Rolle]

Das Beispiel ist zwar trivial. Aber wir haben zahlreiche kombinierte Funktionsdefinitionen, wo gleichzeitig typisierte und Variant-Parametern vorkommen. Insofern liegt hier ein Risikopotential, wenn nicht ordentlich geprüft wird.

Kann man den Delphi-Compiler zu einer Prüfung schon während des compilierens veranlassen?

Vielen Dank im voraus


jaenicke - Do 04.11.10 07:00

user profile iconsbdre hat folgendes geschrieben Zum zitierten Posting springen:
Der obige Code lässt sich compilieren, was ich sehr überraschend finde. D.h. Delphi (Delphi 2009) erkennt den Typkonflikt nicht.
Es gibt auch keinen Typkonflikt. Der Typ ist Variant und damit passend. Der Inhalt (eben nichts) passt nicht. Inhalte prüft der Compiler aber normalerweise nicht (wie auch?).

Dass ein Null-Variant nicht umgewandelt werden kann, kann der Compiler so erst einmal nicht wissen. Natürlich ließe sich das über Compilermagic für diesen speziellen Typ lösen, aber wenn man diesen Null-Variant selbst angibt, dann kann Delphi wohl davon ausgehen, dass man das auch möchte.

Anders sieht es zur Laufzeit aus. Da kann ein Variant eben Null sein (Datenbankergebnis, ...) oder aus anderen Gründen nicht in den Zieltyp umwandelbar, deshalb wird das bei der Umwandlung geprüft.


sbdre - Do 04.11.10 11:26

Vielen Dank für die schnelle Antwort. Die Erklärung ist plausibel. Ich hatte insgeheim gehofft, dass es einen Compilerschalter gibt, der generell die Übergabe von Variant an typisierte Parameter unterbindet (und damit auch die Null).

Hintergrund der Frage: Wir haben zwei Funktionen zum Hinzufügen eines Datenbankfeldes per SQL, einmal kann ein Vorgabewert (DefaultValue) übergeben werden und einmal ein Berechnungsausdruck (DefaultExpression).


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
function addField( TableName:String
                   Fieldname:string;
                   FieldType:TFieldType;
                   Size:integer;
                   DefaultValue:Variant       // -- Vorgabe als Wert
                   ):integer;overloadvirtual;
function addField( TableName:String
                   Fieldname:string;
                   FieldType:TFieldType;
                   Size:integer;
                   DefaultExpression:String;  // -- Vorgabe als Berechnung
                   NotNull:boolean
                   ):integer;overloadvirtual;

Nun muss man natürlich höllisch aufpassen, wenn man auf einen Vorgabewert verzichtet. Bei der 1. Funktion übergibt man eine Null, bei der zweiten einen Leerstring. Übergibt man aus Versehen Null an die zweite Funktion kracht es.
Wäre halt schön gewesen, wenn der Compiler soetwas bereits beim Compilieren erkennt.


jasocul - Do 04.11.10 15:15

In dem Fall würde ich auch dort die Deklaration vom Typ Variant nehmen und innerhalb der Funktion prüfen, ob der Parameter den "richtigen" Typ zur weiteren Verarbeitung hat.

Also etwas so:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
function addField( TableName:String
                   Fieldname:string;
                   FieldType:TFieldType;
                   Size:integer;
                   DefaultExpression:Variant;  // -- Vorgabe als Berechnung
                   NotNull:boolean
                   ):integer;
begin
  if VarType(DefaultExpression) = varString then
    ...

end;

(ungeprüfter Source)


sbdre - Do 04.11.10 15:33

Das ist eine gute Idee und auf so etwas wird es nun hinauslaufen.
Fehler werden leider damit auch erst zur Laufzeit erkannt.