AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Projekte Störende Elemente der Delphi-Syntax / Vorschläge für neuen Dialekt
Thema durchsuchen
Ansicht
Themen-Optionen

Störende Elemente der Delphi-Syntax / Vorschläge für neuen Dialekt

Ein Thema von implementation · begonnen am 11. Jan 2012 · letzter Beitrag vom 24. Jan 2012
Antwort Antwort
Seite 4 von 5   « Erste     234 5      
Benutzerbild von implementation
implementation
Registriert seit: 5. Mai 2008
Hallo liebe Delphisten,

im Laufe der Zeit haben sich bei mir einige Dinge angehäuft, die mich an der aktuellen Syntax von Object Pascal stören.
Darunter sind folgende:
  • Es muss eine strikte Reihenfolge von interface->implementation eingehalten werden. Das heißt, ich kann keine globale Eigenschaft deklarieren, die auf eine private Variable zurückgreift.
  • Interfaces sind per se immer an Referenzzählung und COM-Kompatibilität gebunden. In meinem halbjährigen Ausflug nach C# habe ich erfahren, wie schön es sein kann, a) in Interfaces für Properties nicht gleich eine Getter/Setter-Methode angeben zu müssen, sondern dies der Implementierung zu überlassen, b) Objekt- und Interfacereferenzen mischen zu können
  • Methoden und nichtmethodische Routinen sind im implementation-Teil sprachlich nicht gruppiert (höchstens durch Kommentare)
  • Man kann zwar mehrere verschiedene benannte Destruktoren deklarieren, das hilft aber nichts, weil Free immer nur einen ganz bestimmten aufruft. Wozu haben wir denn unser schönes Benennungsfeature?

Daher habe ich mir mal einen Entwurf für einen neuen kleinen Dialekt überlegt, der diese Dinge besser machen soll, ich nenne ihn bisher "Thrym".

Hier mal ein Ausschnitt:
Delphi-Quellcode:
// Thrym

unit sample;

// Uses-Klausel außerhalb von public/private/implementation
uses
  ...

// public + private statt interface
public

  type
    TExample = class
    public
      procedure Sample;
    end;
    
    // Counted Interfaces:
    // Klassische COM-Interfaces, auf Methoden beschränkt,
    // Properties gehen den Weg über diese
    // (Referenzzählung!!)
    IExample = counted interface
      ['{GUID}']
      procedure SetTest(AValue: Integer);
      function GetTest: Integer;
      property Test: Integer read GetTest write SetTest;
    end;
    
    // Uncounted Interfaces:
    // Von COM komplett unabhängig, keine Referenzzählung
    // Properties müssen nicht direkt einen Getter/Setter
    // zugewiesen bekommen, dies ist Sache der Implementierung
    // Implementierende Klassen müssen nicht AddRef/Release/
    // QueryInterface unterstützen
    ISample = uncounted interface
      property Test: Integer read write;
    end;
    ...
  
  const
    ...
    
  var
    ...
    
private

  type
    // Schema-Typ, wie in GPC:
    TCharArray(start, length: Integer) = array [start..start+length] of char;
    TSample = TCharArray(0,6);
    ...
    
  const
    ...
    
  var
    ...
    FProp: Integer;
    
// können auch mehrere public/private sections sein
public

  // z.B. um global properties besser zum ermöglichen
  property Prop: Integer read FProp write FProp;
  
implementation // oh, it's me!

  // In den Implementation-Teil kommt
  // tatsächlich nur noch die Implementierung
  // der im public- und private-Teil deklarierten
  // Methoden und nichtmethodischen Routinen

  // Methoden gruppieren nach Klasse
  TExample: begin
  
    procedure Sample;
    var obj: TExampleObject;
    begin
      obj := TExampleObject.Create;
      try
        // Do Something
      finally
        // den Destruktor gefahrenlos direkt aufrufen können
        // damit benannte Destruktoren auch endlich wieder Sinn
        // machen - wozu kann man sonst mehrere Destruktoren
        // deklarieren, wenn man eh nur Destroy über Free verwenden
        // kann
        obj.Destroy;
        // schön wäre es jetzt noch, wenn obj gleich auf Nil gesetzt würde
        // dazu aber dick: Fragezeichen ?
      end
    end;
  
  end;

end.
Nun möchte ich das ganze aber nicht einfach verschlimmbessern, daher Frage an euch: Was haltet ihr von diesen Änderungen, insbesondere dem automatischen nil-setzen?

Je nach Feedback setze ich das ganze vllt. in Zukunft mal durch einen Präcompiler um, der dies dann in FreePascal-Code oder Delphi-Code umschreibt.

Verbesserungsvorschläge, Kritiken und Featurerequests sind gern willkommen (dazu mache ich den Thread ja auf )
 
Benutzerbild von himitsu
himitsu

 
Delphi 12 Athens
 
#31
  Alt 13. Jan 2012, 15:26
Eine Möglichkeit gäbe es.

Die System.pas verändern, neu kompilieren und dann auch noch alle BPLs neu kompilieren.
Statt einem Operator könnte man Klassenmethoden verwenden, welche jeweils einen vorgegebenen Namen und bestimmte Parameter haben müßten.

Aber vorallem das Ändern der System.pas und vorallem der BPLs, ist nicht grade optimal schön.
  Mit Zitat antworten Zitat
Benutzerbild von implementation
implementation

 
FreePascal / Lazarus
 
#32
  Alt 13. Jan 2012, 15:27
Die System.pas verändern, neu kompilieren und dann auch noch alle BPLs neu kompilieren.
Ich dachte, die System.pas sei nur ein Dummy und ihre Funktionalität fest im Compiler verankert?
Marvin
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

 
Delphi 12 Athens
 
#33
  Alt 13. Jan 2012, 15:31
Hab ich auch gedacht, aber mit ein paar speziellen Parametern (Einstellungen) seitens des Compilers, soll es möglich sein.

Denn Records haben, vorallem im Zusammenhang mit Mathematikbibliotheken, einige Vorteile.

Objekte => garkeine automatische Speicherverwaltung, der Objektvariable
Interfaces => automatische Freigabe, wenn der letzte Weg ist
Records => automatische Speicherreservierung, Freigabe für jede Variable einzeln, Umkopieren bei Variablenzuweisung usw.
  Mit Zitat antworten Zitat
Benutzerbild von JamesTKirk
JamesTKirk

 
FreePascal / Lazarus
 
#34
  Alt 13. Jan 2012, 16:13
Wahrscheinlich (ich werde für den Delphi Compiler jedoch keine Hand ins Feuer legen) wird diese geänderte System.pas aber nur funktionieren, wenn das Record auch Felder von "managed" Typen wie Strings, Arrays oder Interfaces enthält. Ansonsten wird sich der Compiler wahrscheinlich denken: "och, da muss ich nichts machen, also machen wir ein einfaches "Verringern des Stackpointers" (Speicherplatz belegen), "Move" (Zuweisung), "Erhöhen des Stackpointers" (Speicherfreigabe, wobei das auch meist durch ein "ret" abgedeckt wird).

Für FPC muss ich erst nachschauen, was der bei Records mit "managed" Feldern überhaupt aufruft

Ein wichtiger Punkt ist bei diesem Feature jedoch dabei: ein RTTI Lookup für die "Ereignisbehandlungsroutine" ist relativ aufwendig. Wenn dies also bei jedem Record gemacht wird, dann wird es relativ teuer Records zu verwenden (dann muss man fast schon zu den guten, alten Objects greifen, wenn man den Overhead vermeiden möchte ).

Gruß,
Sven
Sven
  Mit Zitat antworten Zitat
Blup

 
Delphi 10.4 Sydney
 
#35
  Alt 13. Jan 2012, 16:16
Ich hätte gern Mehrfachvererbung für Interfaces:
Delphi-Quellcode:
type
  MyInterface3 = interface(MyInterface1, MyInterface2)
  end;

var
  v1: MyInterface1;
  v2: MyInterface2;
  v3: MyInterface3;
begin
  v1 := v3;
  v2 := v3;
Mehrere Class-Helper sollten sich für eine Klasse nicht gegenseitig ausschließen.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

 
Delphi 12 Athens
 
#36
  Alt 13. Jan 2012, 16:57
Jupp, und auch deshalb muß es direkt von Embarcadero implementiert werden, dann dort könnte man diese Optimierung dann anpassen und auch ein ordentlicher Operator wäre dann möglich/vorhanden.


Mehrfachvererbung geht nunmal nicht. Aus dem selben Grund, warum es auch bei Klassen nicht geht.
Bei den "einfachen" Interfaces werden die Methoden über einen Index aufgerufen.
Bei Interface-Vererbung baut das neue Interface auf das alte auf, also es wird weitergezählt und weiterzählen ist nur für einem Vorfahren möglich, bzw. es können keine Indize mehrfach belegt sein, was bei mehrere Vorfahren aber zutreffen würde.


Für gewisse COM-Interfaces, wo die Methoden über einen Namen aufgerufen würden, würde es theoretisch gehen, aber da die Möglichkeit von gleichen Namen bestünde, ist das also unsicher und somit besser ganz ausgeschlossen.

Geändert von himitsu (13. Jan 2012 um 17:04 Uhr)
  Mit Zitat antworten Zitat
Blup

 
Delphi 10.4 Sydney
 
#37
  Alt 23. Jan 2012, 07:49
Mehrfachvererbung geht nunmal nicht. Aus dem selben Grund, warum es auch bei Klassen nicht geht.
Bei den "einfachen" Interfaces werden die Methoden über einen Index aufgerufen.
Bei Interface-Vererbung baut das neue Interface auf das alte auf, also es wird weitergezählt und weiterzählen ist nur für einem Vorfahren möglich, bzw. es können keine Indize mehrfach belegt sein, was bei mehrere Vorfahren aber zutreffen würde.
Ich verstehe deine Bedenken, aber gerade bei Interfaces sind nicht unbedingt die selben Einschränkungen wie für Klassen nötig.
Delphi-Quellcode:
type
  TMyClass = class(TObject, MyInterface1, MyInterface2)
  end;
Selbst wenn beide Interfaces auf die selben Methoden verweisen würden, ist dies kein Problem.

Der Compiler müsste für die Realisierung der Mehrfachvererbung bei der Prüfung von Zuweisungen die doppelte Vererbung berücksichtigen und an dieser Stelle ein "QueryInterface" einfügen.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

 
Delphi 12 Athens
 
#38
  Alt 23. Jan 2012, 08:10
Das ist aber keine Mehrfachverwebung.

Es wird nur von TObject geerbt.
Die Interfaces werden nur implementiert. Das eine Objekt wird mit mehreren Interfaces verbunden, was natürlich geht, aber wenn man sich einen Interfacezeiger von diesem Objekt holt, dann zeigt der immer nur auf jeweils eines der möglichen Interfaces.

Das hier ist eine Interfacevererbung (ein Interface erbt von einem anderem Interface):
Delphi-Quellcode:
type
  IMyIntertface = interface(IOtherInterface)
    [MyGUID]
    ...
  end;
Objekte erben nur von Objekten und Interfaces nur von Interfaces ... eine Vermischung der Rassen tritt nicht ein.

Geändert von himitsu (23. Jan 2012 um 08:12 Uhr)
  Mit Zitat antworten Zitat
Blup

 
Delphi 10.4 Sydney
 
#39
  Alt 23. Jan 2012, 16:14
Ich wollte nur zeigen was bisher möglich ist und wie der Compiler arbeiten müsste, um Mehrfachvererbung zu ermöglichen. Natürlich ist intern eine Sonderbehandlung durch den Compiler notwendig. Im Detail stelle ich mir das ungefähr so vor:
Delphi-Quellcode:
type
  MyInterface1 = interface
    procedure My1;
    procedure MyX;
    procedure MyY;
  end;
  
  MyInterface2 = interface
    procedure My2;
    procedure MyX;
    procedure MyY(AValue: Integer);
  end;

  MyInterface3 = interface(MyInterface1, MyInterface2)
// Compiler-Magie -> MyInterface3 = interface()
// automatisch unsichtbar hinzugefügt ->
    procedure My1; // aus MyInterface1
    procedure MyX; // aus MyInterface1, MyInterface2 -> nur einmal da eindeutig
    procedure MyY; overload; // aus MyInterface1, andere Parameter
    procedure My2; // aus MyInterface2
    procedure MyY(AValue: Integer); overload; // aus MyInterface2, andere Parameter
// vom Entwickler neu definiert ->
    procedure MyZ;
  end;

  TMyObject = class(TInterfacedObject, MyInterface3)
// automatisch durch den Compiler hinzugefügt: MyInterface1, MyInterface2
    procedure My1;
    procedure MyX;
    procedure MyY; overload;
    procedure My2;
    procedure MyY(AValue: Integer); overload;
    procedure MyZ;
  end;

var
  v1: MyInterface1;
  v2: MyInterface2;
  v3: MyInterface3;
begin
  v1 := v3; // Compiler erkennt Mehrfachvererbung -> v3.QueryInterface(MyInterface1, v1);
  v2 := v3; // Compiler erkennt Mehrfachvererbung -> v3.QueryInterface(MyInterface2, v2);
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

 
Delphi 12 Athens
 
#40
  Alt 23. Jan 2012, 18:17
Und das ist bei den normalen/einfachen Interfaces falsch, denn es geht nicht um Methodennamen ... diese sind vollkommen egal.
Delphi-Quellcode:
  MyInterface1 = interface
    procedure My1; // Methode 1 (Index 0)
    procedure MyX; // Methode 2 (Index 1)
    procedure MyY; // Methode 3 (Index 2)
  end;
  
  MyInterface2 = interface
    procedure My2; // Methode 1 (Index 0)
    procedure MyX; // Methode 2 (Index 1)
    procedure MyY(AValue: Integer); // Methode 3 (Index 1)
  end;
Beim Objekt verlinkt der Compiler nun die Interfaces und hinterlegt, bei den Methodenlisten er Interfaces, die Zeiger zu den jeweiligen Methoden.

Will man nun mehrere Interfaces vererben, dann müßten im abgeleiteten Interface nun jeweiles mehere Methoden zu einem Index hinterlegt werden, was natürlich nicht geht.
Auch den Indize verschieben geht nicht, da es dann nicht mehr zum Vorfahren paßt.

Selbst wenn nur die Indize hinereinander gelegt würden, also die Indize des zweiten Interfaces werden verschoben, ohne daß das Vorfahreninterface wirklich "implementiert" würde, also quasi der Vorfahre wird nur als Vorlage verwendet, wäre das keine sichere Methode, denn wenn man den Vorfahren verändert, würde das eigene Interface verändert.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 4 von 5   « Erste     234 5      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:21 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz