Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - gleicher Name von Variable und Variablentyp
harryp - Sa 28.01.17 19:58
Titel: gleicher Name von Variable und Variablentyp
Liebe EE-Experten,
einer meiner Schüler hat mich in der gerade endenden Woche überrascht. Ich war bisher fest davon überzeugt, dass Variablen und Variablentypen in Delphi unterschiedliche Bezeichner benötigen. Wenn ich das beim Deklarieren von Variablen teste (z.B. einen Typen a = String[10]; festlege und var a:a; teste), bekomme ich auch die erwartete Fehlermeldung.
Nun hat der Schüler sein Memofeld netterweise TMemo genannt. Hier entsteht keine Fehlermeldung, etwa beim Aufruf von TMemo.Lines.Add('...'); sondern das Programm läuft problemlos.
Daher meine Fragen:
- Kennt ihr einen erklärbaren Grund, dass Delphi hier scheinbar bei Komponenten eine Ausnahme macht?
- Kann es bei der Gleichbenennung von Objekt und zugehöriger Komponentenklasse zu Problemen im Aufruf kommen (z.B. bei Konstruktormethoden) oder gibt es andere gute Gründe (abgesehen vom Programmierstil) dafür, dass man seine Objekte nicht wie die Komponenten benennt?
Vielen Dank vorab für die Antworten und ein schönes Restwochenende.
Slipstream - Sa 28.01.17 23:32
Habe das soeben einmal mit D7 getestet:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35:
| unit UnitMain;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type TFormMain = class(TForm) TMemo: TMemo; TButton: TButton; procedure TButtonClick(Sender: TObject);
private
public
end;
var FormMain: TFormMain;
implementation {$R *.dfm}
procedure TFormMain.TButtonClick(Sender: TObject); begin TMemo.Lines.Append('Das ist ein Text.'); end;
end. |
Dass das tatsächlich funktioniert, dürfte mit den unterschiedlichen Namensräumen zusammenhängen. Der Typ TMemo oder ein anderer wie TButton ist in der Unit StdCtrls deklariert und stellt eine eigene Klasse dar. Beim Parsen weiss der Delphi-Compiler sofort, dass das TMemo vor dem Doppelpunkt eine Variable sein muss, die nur innerhalb der Forumlarklasse (TFormMain) Gültigkeit besitzt. Vor dem Doppelpunkt stehen nämlich immer Variablen. Beim Parsen des TMemo hinter dem Doppelpunkt weiss der Delphi-Compiler sofort, dass es sich um einen Typ handeln muss, denn hinter dem Doppelpunkt steht immer der Typ. Der Parser findet jedoch keinen solchen Typen in der Formularklasse. Also klappert er die Uses ab und findet dort in der Unit StdCtrls den Typen TMemo. Damit sind die beiden zwar identischen Bezeichner dennoch korrekt unterschiedlichen Ursprüngen zugewiesen.
Probleme kann es eigentlich nicht geben, denn Delphi verhindert das Compilieren von Code, der doppelte Deklarationen enthält. Wenn du also in derselben Klasse oder in derselben Unit zweimal denselben Bezeichner verwenden würdest, würde der Build-Vorgang mit einer entsprechenden Fehlermeldung abbrechen.
Man sollte sich aber dennoch an die
Konventionen [
https://de.wikipedia.org/wiki/Namenskonvention_%28Datenverarbeitung%29] zur
Vergabe von Bezeichnern [
https://de.wikipedia.org/wiki/Variable_%28Programmierung%29#Namenswahl] halten und Typen stets mit einem vorangestellten T markieren. Variablen sollten diese vorangestellte T dagegen nicht aufweisen. Diese Konventionen dienen vor allem der besseren Lesbarkeit von Code, egal in welcher Programmiersprache.
Delete - So 29.01.17 00:41
- Nachträglich durch die Entwickler-Ecke gelöscht -
jaenicke - So 29.01.17 02:06
Slipstream hat folgendes geschrieben : |
Beim Parsen weiss der Delphi-Compiler sofort, dass das TMemo vor dem Doppelpunkt eine Variable sein muss, die nur innerhalb der Forumlarklasse (TFormMain) Gültigkeit besitzt. Vor dem Doppelpunkt stehen nämlich immer Variablen. Beim Parsen des TMemo hinter dem Doppelpunkt weiss der Delphi-Compiler sofort, dass es sich um einen Typ handeln muss, denn hinter dem Doppelpunkt steht immer der Typ. |
So schlau ist der Compiler nicht. Bezeichner müssen eindeutig sein.
Das lässt sich auch leicht zeigen. Das funktioniert auch nicht:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| procedure Test; const TMemo = False; var TestVariable: TMemo; begin
end; |
Delphi findet unter dem Namen TMemo die Konstante und wirft einen Fehler.
Das Entscheidende ist der Scope. Es wird immer der Bezeichner genommen, der "am nächsten dran" deklariert ist.
Übrigens kompiliert auch das:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| procedure Test; const True = False; begin if True then ShowMessage('Ja') else ShowMessage('Nein'); end; |
Und es wird auch wirklich Nein angezeigt. ;-)
Slipstream - So 29.01.17 02:51
jaenicke hat folgendes geschrieben : |
So schlau ist der Compiler nicht. Bezeichner müssen eindeutig sein. Das lässt sich auch leicht zeigen. Das funktioniert auch nicht:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| procedure Test; const TMemo = False; var TestVariable: TMemo; begin
end; |
Delphi findet unter dem Namen TMemo die Konstante und wirft einen Fehler. |
Du verwendest hier aber ein ganz anderes Beispiel, auf das meine Behauptung gar nicht zutreffen kann. Wenn der Compiler TYPE liest, dann ist doch die Anzahl der möglichen Kombinationen für den Compiler schonmal reduziert: Hinter einem Bezeichner, gefolgt von einem Doppelpunkt, muss ein Typenbezeichner stehen. Findet der Compiler dort keinen solchen oder kann der den dortigen Typenbezeichner nicht auflösen, erfolgt eine Fehlermeldung.
jaenicke hat folgendes geschrieben : |
Das Entscheidende ist der Scope. Es wird immer der Bezeichner genommen, der "am nächsten dran" deklariert ist. |
Bei
TYPE TMemo : TMemo wäre dann das TMemo hinter dem Doppelpunkt am nächsten dran, weil die Deklaration der neuen Variable TMemo (vor dem Doppelpunkt) zu diesem Zeitpunkt noch nicht abgeschlossen ist und deshalb das TMemo als Variablenbzeichner noch gar nicht existiert, das TMemo als Typ dagegen schon. Richtig?
mandras - Mi 01.02.17 21:05
Du kannst auch sagen
var
integer : byte;
boolean : char;
weiter unten geht dann auch:
boolean := '4';
Es liegt einfach daran daß links ein Variablenname erwartet wird, rechts ein Typ.
Durch Definition einer Variable mit Namen "integer" wird der Typ Integer auch nicht gelöscht, überschrieben oder ähnliches.
Was nicht geht:
var
string : integer;
Da schreit Delphi, das liegt aber daran, daß "string" im Ggs zum Rest ein reserviertes Wort ist (wird vom Syntaxhighlighter auch immer fett angezeigt)
jaenicke - Fr 03.02.17 04:39
mandras hat folgendes geschrieben : |
Durch Definition einer Variable mit Namen "integer" wird der Typ Integer auch nicht gelöscht, überschrieben oder ähnliches.
|
Trotzdem ist er aber im Scope der Variablen nicht mehr als Typ nutzbar. Genau das habe ich ja mit dem Quelltext oben gezeigt.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2024 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!