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:


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 { Private declarations }


  public  { Public declarations  }


  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

user profile iconSlipstream hat folgendes geschrieben Zum zitierten Posting springen:
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

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
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.

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
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

user profile iconmandras hat folgendes geschrieben Zum zitierten Posting springen:

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.