Autor Beitrag
harryp
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 52
Erhaltene Danke: 9

Win 8.1
Delphi 7, XE8
BeitragVerfasst: Sa 28.01.17 19:58 
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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 26
Erhaltene Danke: 5



BeitragVerfasst: Sa 28.01.17 23:32 
Habe das soeben einmal mit D7 getestet:

ausblenden volle Höhe 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 zur Vergabe von Bezeichnern 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.

Für diesen Beitrag haben gedankt: harryp
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: So 29.01.17 00:41 
- Nachträglich durch die Entwickler-Ecke gelöscht -

Für diesen Beitrag haben gedankt: harryp
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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:
ausblenden 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:
ausblenden 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. ;-)

Für diesen Beitrag haben gedankt: harryp
Slipstream
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 26
Erhaltene Danke: 5



BeitragVerfasst: 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:
ausblenden 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?

Für diesen Beitrag haben gedankt: harryp
mandras
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 429
Erhaltene Danke: 107

Win 10
Delphi 6 Prof, Delphi 10.4 Prof
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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.