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 3 von 5     123 45      
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 )
 
Medium

 
Delphi 2007 Enterprise
 
#21
  Alt 12. Jan 2012, 12:40
Von mir aus dann eben TMyClass.CreateManaged() oooder in TObject bereits einen Parameter einführen: TObject.Create(isManaged: Boolean);
Letztlich gehopst wie gesprungen, wobei ich die syntaktische Unschönheit von new nachfühlen kann. Die Alternative mit Parameter oder Benamung hätte nur ggf. den Nachteil, dass man die Eindeutigkeit in Ableitungen sehr leicht (und fahrlässig) verschleiern könnte, und man es der IDE beim Unterscheiden zusätzlich schwer machen würde. (Sie müsste schon regelrechte Interpreterfähigkeiten bekommen, aber vielleicht wäre das ja mal ein Anreiz die IDE-Features mehr an den Compiler zu knurpseln als z.B. das dolle ErrorInsight oder wie sich die vielen falschen roten Unterwellungen schimpfen, die scheinbar eher selten Plan von der Projektstruktur haben.)

Oder, wobei ich das so garnicht mag: Annotations. Wobei diese dann in die Klassendeklaration gehörten, und somit die GC-Bindung nur per Klasse (und all ihrer Nachfahren) gegeben wäre, und man nicht die Freiheit hätte von Instanz zu Instanz zu unterscheiden. Eher bäh.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

 
Delphi 12 Athens
 
#22
  Alt 12. Jan 2012, 12:47
Drum meinte ich ja, im Falle von bar := new TMyFooClass(); würde der Compiler dann Standard-Constructor "Create" aufrufen, sich einen Suchen, welche den übergebenen Parametern entspricht, falls es diesen gibt und am Ende es zu einem bar := TMyFooClass.Create(); umwandeln.
Und schon wäre das OOP-Prinzip gewahrt.

Nur wird es eben schwer einen neues "reserviertes Wort" einzuführen.
Das ist wohl auch der Grund, warum es "Class Helper" und nicht nur "Helper" heißt, da durch das reservierte "Class" das Helper geschützt/eingeleitet wird, womit die Syntax dennoch kompatibel bleibt.


Wenn man eine Syntax von Grund auf neu baut, könnte man z.B. NEW gleich reservieren.
Mit den großen Neuerungen und vielen Änderungen seitens D2009/XE2 hätte man diesbezüglich schnell noch ein paar neue "reservierte" Wörter mit einführen und alte Makel in der Syntax ausbessern können.
Wenn sowieso genug angepaßt werden muß, dann kommt es auf die paar Änderungen auch nicht mehr an.


Sowas wäre syntaktisch möglich:
Delphi-Quellcode:
type
  TMyClass = class managed(Txyz)
  end;
genauso wie ja auch sowas gehn:
Delphi-Quellcode:
type
  TMyClass = class sealed(Txyz)
  end;

  TMyClass = class abstract(Txyz)
  end;

Geändert von himitsu (12. Jan 2012 um 12:51 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von JamesTKirk
JamesTKirk

 
FreePascal / Lazarus
 
#23
  Alt 12. Jan 2012, 15:20
So... es wird Zeit, dass ich mich auch mal in diese Diskussion einmische.

  • 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.
Diese Reihenfolge ist einerseits der Tatsache geschuldet, dass Pascal auf Single-Pass-Kompilierung ausgelegt ist (das heißt keine Nutzung darf vor der Deklaration erfolgen (mit wenigen Ausnahmen ala forward oder Pointer auf Records)), anderseits arbeiten "Unit basierte" Compiler wie FPC und Delphi so, dass sie sich beim Kompilieren einer weiteren Unit erst nur den Interface Teil der Unit anschauen müssen, um festzustellen, ob sich was geändert hat und demnach die erste Unit neukompiliert werden muss. Wenn du nun Teile des Implementationbereichs in den Interfacebereich schiebst, so muss der Compiler auch über diese Teile hinweg parsen, selbst wenn er sie eventuell gar nicht benötigt, weil sich nichts geändert hat.

Ganz davon abgesehen ist das mit Interface und Implementation Anfängern einfacher zu erklären als "also wenn du da jetzt noch auf eine private Variable der Unit zugreifen möchtest, dann musst du vor diesem Public Abschnitt noch einen Private Abschnitt einfügen"

Zitat von implementation:
  • 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
Kann es sein, dass du hier eher (a), (b) und (c) brauchst? Mit (a) also Hinweis auf Referenzzählung und COM...

Nichtsdestotrotz: Free Pascal unterstützt nicht-referenzgezählte Interfaces (so genannte CORBA Interfaces). Die kannst du (per Unit oder eventuell sogar lokal per Deklaration, das weiß ich grade nicht) ganz einfach per "{$interfaces corba}" aktivieren. Du deklarierst dann ganz einfach dein Interface, diese leiten dann jedoch NICHT von IInterface/IUnknown ab (um genau zu sein haben die dann gar keinen Vorfahrn) und benötigen auch keine Implementierungen für QueryInterface, AddRef und Release. Seit FPC 2.4.0 funktionieren die sogar ähnlich wie COM Interfaces hinsichtlich "as" und so (aber eben ohne Referenzzählung).

Zu deinem a): Dies wäre ein Feature, dem ich eventuell sogar eine gewisse Sinnhaftigkeit zugestehen könnte (ich arbeite nur selten mit Interfaces, deswegen...). Solche Interfaces kannst du dann natürlich nur in Pascal Code einsetzen, da zum Beispiel ein C++ Code, welcher dieses Interface verwendet, nicht wissen kann wie er auf die Property zugreift (außer man streut hier sehr viel Compilermagic ein...)

Zu deinem b): Das Problem hierbei ist die Referenzzählung. Delphi und FPC fügen nur Code zum Ändern der Referenzzählung ein, wenn es sich um eine Interface Referenz handelt. Also rein prinzipiell könntest du sie sogar mischen, wenn du manuell mit AddRef und Release auf der Objektreferenz arbeitest... (nicht dass das unbedingt das sinnvollste ist, aber es würde gehen) Falls du dich jedoch darauf beziehst, dass du einer Objektreferenz keine Interfacereferenz zuweisen kannst, dann hat das den Hintergrund, dass ein Interface ja von unterschiedlichen Klassen implementiert werden kann. Diese Klassen müssen dabei ja nichteinmal verwandt sein. Also eine automatische Konvertierung würde ich da gar nicht wollen. AFAIK unterstützen jedoch modernere Delphi Versionen (XE+?) ein "as", um von Interfaces auf Objekte zu casten und wenn das nicht geht wird eine Exception geworfen (wie von "as" gewohnt). Vielleicht gibt es da auch ein "is", das weiß ich gerade nicht. Das wären auf jeden Fall zwei Features, die zu FPC hinzugefügt werden könnten/sollten.

Zitat von implementation:
  • Methoden und nichtmethodische Routinen sind im implementation-Teil sprachlich nicht gruppiert (höchstens durch Kommentare)
Das hat mich ehrlich gesagt noch nie gestört (und ich finde deinen Vorschlag dazu auch nicht wirklich eine Verbesserung). Dafür hat man ne gute IDE...

[QOUTE][*]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?[/LIST]
Und es funktioniert auch wie es soll. "Free" ist nur eine normale Prozedur deren einziger Sinn es ist zu überprüfen, ob "Self <> Nil" ist und dann den Default-Destruktor "Destroy" aufruft. Nichts hält mich davon ab einen Destruktor mit einem anderen Namen zu definieren und einfach direkt aufzurufen. Es ist nämlich der Aufruf des Destruktors, der die Speicherfreigabe veranlasst, nicht der von Free (sonst bräuchten wir ja kein spezielles Keyword für den Destruktor).

Delphi-Quellcode:
  type
    // Schema-Typ, wie in GPC:
    TCharArray(start, length: Integer) = array [start..start+length] of char;
    TSample = TCharArray(0,6);
Schematypen stehen bei mindestens einem FPC-Entwickler auf der Wunschliste.

Weil's grad zum Kontext passt noch der Einwurf Himitsus dazu:

Delphi-Quellcode:
TCharArray(start, length: Integer) = array [start..start+length] of char;
TSample = TCharArray(0,6);
Sieht einfach nur häßlich aus und paßt nicht zur Pascal/Delphi-Syntax.
Im Gegensatz zu vielen der Features die uns lieb sind wie Klassen, Generics, etc. sind Schematypen sogar Teil des ISO-Standards.

Zitat von himitsu:
- die Generics so erweitern, daß man statt typen auch Konstanten verwenden kann.
(würde dann teilweise ähnliche Möglichkeiten bieten, wie die Makros in C)
Ich weiß nicht, ob das wirklich so gut wäre... es wäre schon schwierig sowas zu parsen:

Delphi-Quellcode:
type
  TTest<const c> = class

  end;

var
  TTest: Integer; // was ja erlaubt ist in Delphi! (in FPC funktioniert das noch nicht...)

begin
  if TTest<5>.Irgendwas then
    ...
end.
Der Compiler muss den Punkt "TTest<5" nun irgendwie intelligent behandeln. Es kann vielleicht schaffbar sein, aber wenn ich mir allein den Code anschau, den ich geschrieben habe, um die Inlinespezialisierung "TTest<SomeType>" zu erlauben, dann möchte ich nicht wissen, was ich da alles verbrechen muss (und dabei hab ich es noch nichteinmal geschafft die Überladung mit einer Variable zu implementieren, das steht noch auf meiner ToDo Liste, weil's (hoffentlich) ein extremes Randbeispiel ist).

Zitat von himitsu:
- ein mehrstufiger Compiler, bzw. ein intelligenterer, so daß man besseren Zugriff auf die Typen hat, welche im denerischen Type enthalten sind.
Kannst du das bitte genauer erklären?

Zitat:
- generische Prozeduren, Interfaces und Class Helper (nicht nur Klassen.Methoden)
Generische Prozeduren werde ich auf jeden Fall mitimplementieren, wenn ich generische Methoden implementiere. Aber Interfaces kann man doch bereits generisch deklarieren, oder verpeile ich da was? Generische Class Helper könntest du übrigens nur in der folgenden Form nutzen, da du beim Aufruf einer Class Helper Methode ja keinen Typen angeben kannst:

Delphi-Quellcode:
type
  TSomeClassHelper<T> = class helper for TObject
    function ReturnDefault: T; // mir fällt grad nichts besseres ein
  end;

function TSomeClassHelper.ReturnDefault;
begin
  Result := Default(T);
end;

type
  TSomeClassHelperInteger = TSomeClassHelper<Integer>;

var
  i: Integer;
...
  i := SomeObject.ReturnDefault;
...
Zitat von himitsu:
- Class Helper Record Helper für einfache Basistypen, wie t.B. den Integer oder den String

- Interface Helper
Du wirst lachen... seitdem ich record und class helper in FPC implementiert habe, denke ich immer wieder darüber nach die auf interfaces, objects und eventuell auch primitive Typen zu erweitern (als FPC-Entwickler darf man die objects nicht vernachlässigen ). Die ersteren beiden sollten vergleichsweise einfach zu implementieren sein (nur bei Interfaces müsste ich aufpassen, dass mir die Referenzzählung keinen Strich durch die Rechnung macht). Primitive Typen würde wohl einige Anpassungen des Parsers nach sich ziehen...

Zitat von himitsu:
- Operatoren für Interfaces
In FPC kannst du diese bereits deklarieren (zwar nicht innerhalb von Interfaces, aber es sollte gehen ).

Zitat von himitsu:
- Operatoren für Copy, Create und Destroy von Records
(technisch leicht möglich, da alle Struckturen schon existieren ... siehe Behandlung der Interfaces, dyn. Arrays und der Strings innerhalb von Records)
Was möchtest du da genau? Hättest du da vielleicht ein Beispiel?

Zitat von himitsu:
- endlich mal ein Versesserung einiger Grenzen in der OTA
(jbg bekommt auch immer wieder mit, daß Vieles einfach nur fehlt oder schecklich implementiert ist)

- und ein OTA-Interface für einen eigenen Precompiler
Was heißt OTA?

Zitat von himitsu:
- daß man bei dyn. Arrays das CopyOnWrite aktivieren kann, so wie es bei den Strings auch vorhanden ist
AFAIK unterstützt FPC dies auch bereits.

Zitat von himitsu:
- Delphi-Referenz durchsuchenabsolute mit einer Typsicherheits- und Größenprüfung (Compilerwarnung)
Solange diese Compilerwarung ein Opt-In ist...

Zitat von himitsu:
- string aus den reservierten Wörtern rausnehmen
Es sieht zwar nicht so schön aus, aber ein &String sollte es doch tun, oder nicht?

Zitat von himitsu:
- ein "caseend" für die varianten Recordteile ("end" geht ja nicht mehr ... das hätte man gleich zu Beginn nicht vergessen dürfen )
Ich glaub "vergessen" ist das falsche Wort. Das wurde damals wahrscheinlich absichtlich so gemacht. Die Begründung könnte vielleicht sein, dass man sich nicht mit einem Case inmitten eines Records herumschlagen wollte (hinsichtlich Memory-Layout).

Zitat von himitsu:
- das Strg+Linksklick auf einen generischen Teil (Methode,Feld,...) nicht bei "implementation" landet, sondern beim generischen Typen
Ehm... was hat das mit der Sprachsyntax zu tun? Das ist ein Problem der IDE...

  • Ich finde, man sollte Variablen immer bei der Deklaration initialisieren können, also nicht nur globale Variablen, sondern auch Felder und lokale Variablen. var x: integer = 0
Zumindest das mit lokalen Variablen kann Free Pascal zum Beispiel. Für Felder geht das nicht.

Zitat von NamenLozer:
  • Oft nervt mich die Operatoren-Priorität bei Konditionalen – dass man um Vergleiche immer eine Klammer setzen muss, wenn man sie per AND oder OR verknüpfen will. Ich kenne keine andere Sprache, wo das so ist.if a<b and b<c then ... statt if (a<b) and (b<c) then ... . Wann will man schon mal tatsächlich zwei Werte in einer Abfrage binär verknüpfen? Außerdem wäre das ja immer noch möglich, eben mit Klammerung. Ich wünschte mir hier einfach ein anderes Default.
Das große Problem bei solchen Änderungen ist die Abwärtskompatibilität. Sowas sollte als nur per Compilerschalter möglich sein. Ansonsten schließe ich mich hier im Sinne von "in" an:

Delphi-Quellcode:
if not (SomeEnum in SomeSet) then
// vs
if not SomeEnum in SomeSet then
Dass ich da Klammern setzen muss, hat mich schon immer aufgeregt...
Zitat von NamenLozer:
  • Ich fände es außerdem cool, wenn sowas ginge: if a < b < c then ... . Ich glaube Prism/Oxygene kann das.
Waaahhhh!!! Bloß nicht! Meine ganze Logik für if TSomeGeneric<SomeType>.BlaBla fusst darauf, dass genau das eben nicht geht!

Zitat von NamenLozer:
  • Hin und wieder nervt mich, dass man im Interface-Bereich Felder immer vor Methoden deklarieren muss.
FPC konnte das früher mal, das wurde jedoch abgeschafft. Begründung siehe hier

Zitat von NamenLozer:
  • try ... except ... finally ... end statt zwei try-Blöcke schachteln zu müssen.
Ja, manchmal wäre das durchaus schön (vor allem, wenn man ein paar mehr von den Viechern geschachtelt hat...)

Mein Wunsch geht zwar über Syntax hinaus, und dafür würden mich sicher hier gerne einige vermöbeln, aber ein Delphi mit GC wäre schon sexy. Ich weiss, es gibt da diverse Fummelein mit Interfaces und Hacks, aber ein richtiger "ab Werk" GC ist einfach eine riesen Komfortsteigerung (wenn er vernünftig umgesetzt ist). Was ich in C# ab und an gern mache, und in Delphi ab und an wünschte, ist sowas wielokaleVarMitRückgabewert := TMyFooClass.Create(aParameter).SomeMethod(aNotherParameter); , und die Instanz dann einfach verpuffen lassen. (Ja, das sieht nach einem Designfehler aus, man meint die Methode hätte statisch sein sollen - aber so schlau sind leider nicht alle Fremdkomponentenhersteller.) Oder auch so Späße, bei denen Instanzen über mehrere Threads eher "locker umher geworfen" werden würden mit einem GC etwas weniger Kopfschmerzlastig.

Vielleicht sogar als alternativer Konstruktor, ggf. mit Einführung des new-Operators!
Delphi-Quellcode:
  bar := TMyFooClass.Create(); // <- normal ohne GC
  bar := new TMyFooClass(); // <- GC'ed
Mit etwas Unterstützung in der IDE (anderes Highlighting für GC'ed Instanzvariablen) wäre so ein Hybrid glaube ich sogar einigermaßen handlich.
Vielleicht weniger über einen neuen Konstruktor gehen, als die Variablendeklaration zu ändern:

Delphi-Quellcode:
var
  bar: TMyFooClass autoref;
begin
  bar := TMyFooClass.Create;
  ...
  // bar wird automatisch freigegeben, falls keine Referenz darauf mehr existiert (die Überprüfung hierzu ist jedoch schwierig)
end;
Wie gut das funktionieren würde, wenn man Objekte über Prozeduren hinweg reicht, weiß ich noch nicht, aber es wäre vielleicht eine Idee...

Zitat von himitsu:
Wenn man Klassen direkt als Interface markieren könnte, bei deren Deklaration, ohne vorher einen extra Interface-Typen manuell deklarieren zu müssen (der Compiler würde dann aus den Public/Published-Dingen dass Interface automatisch generieren), dann hätte man quasi auch einen GC für diese Objekte.
(über die Technik der Generics eventuell machbar, also wenn Emba das implementiert)
Hmm... vielleicht sowas:

Delphi-Quellcode:
type
  TSomeRefCountedObject = class refcounted (TParentClass) // in dieser Reihenfolge, um analog zu "sealed" und "abstract" zu sein

  end;
Wäre es nicht schön, einfach ein Helperkonstrukt für alle Typen zu haben, statt zwischen Class-, Record und Interface-Helpern zu unterscheiden?
Im Prinzip hast du ja Recht, denn über den Zieltüben ließe es sich ja unterscheiden.
Aber dann wäre es nicht mehr ganz kompatibel zum alten Code.
Wieso? "class helper" und "record helper" könnte für alten Code ja bestehen bleiben. Ansonsten (auch für Klassen und Records) ist einfach nur "helper for" möglich.

Und was ich mir wünsche (und vielleicht auch mal implementieren werde):
  • Mehrere Class/Record Helper können für einen Typen gleichzeitig verfügbar sein (müsste vergleichsweise einfach für mich umzusetzen sein, da der Code bereits entsprechend ausgelegt ist )

So... Ende der langen Liste

Gruß,
Sven
Sven

Geändert von JamesTKirk (12. Jan 2012 um 15:22 Uhr) Grund: Eigenen Wunsch ein wenig korrigiert
  Mit Zitat antworten Zitat
Benutzerbild von implementation
implementation

 
FreePascal / Lazarus
 
#24
  Alt 12. Jan 2012, 15:45
Diese Reihenfolge ist einerseits der Tatsache geschuldet, dass Pascal auf Single-Pass-Kompilierung ausgelegt ist (das heißt keine Nutzung darf vor der Deklaration erfolgen (mit wenigen Ausnahmen ala forward oder Pointer auf Records)), anderseits arbeiten "Unit basierte" Compiler wie FPC und Delphi so, dass sie sich beim Kompilieren einer weiteren Unit erst nur den Interface Teil der Unit anschauen müssen, um festzustellen, ob sich was geändert hat und demnach die erste Unit neukompiliert werden muss. Wenn du nun Teile des Implementationbereichs in den Interfacebereich schiebst, so muss der Compiler auch über diese Teile hinweg parsen, selbst wenn er sie eventuell gar nicht benötigt, weil sich nichts geändert hat.
Am Interface-Teil will ich ja an sich auch nichts ändern, sondern fände es schön, den implementation-Teil aufzusplitten in Deklarationen und die tatsächliche Implementierung. Und wenn der public-Teil am Anfang der Unit steht, muss der Compiler ja auch über nichts überflüssiges hinwegparsen.

Zitat:
Ganz davon abgesehen ist das mit Interface und Implementation Anfängern einfacher zu erklären als "also wenn du da jetzt noch auf eine private Variable der Unit zugreifen möchtest, dann musst du vor diesem Public Abschnitt noch einen Private Abschnitt einfügen"
Das mag ich bezweifeln, denn so kann man jetzt sagen: "Das machst du dann wie bei Klassen, du schreibst öffentliches in den public- und privates in den private-Teil"

Zitat:
Nichtsdestotrotz: Free Pascal unterstützt nicht-referenzgezählte Interfaces (so genannte CORBA Interfaces). Die kannst du (per Unit oder eventuell sogar lokal per Deklaration, das weiß ich grade nicht) ganz einfach per "{$interfaces corba}" aktivieren.
Wenn dies tatsächlich per Deklaration geht, wäre das sehr praktisch. Dennoch fände ich es deutlich schöner, diese mit einem Schlüsselwort zu unterscheiden, da sie von ganz anderer Natur sind.

Zitat:
Zu deinem b): Das Problem hierbei ist die Referenzzählung. Delphi und FPC fügen nur Code zum Ändern der Referenzzählung ein, wenn es sich um eine Interface Referenz handelt. Also rein prinzipiell könntest du sie sogar mischen, wenn du manuell mit AddRef und Release auf der Objektreferenz arbeitest... (nicht dass das unbedingt das sinnvollste ist, aber es würde gehen)
Wo das Problem liegt, ist mir durchaus bewusst, deshalb möchte ich an der Stelle ja Interfaces ohne Zählung, die ich dann genauso anwenden kann wie in C#. Jedesmal AddRef und Release ist mir dann doch zu nervig. Die Idee der Interfaces ist eine tolle Sache, aber wir können sie so einfach nicht voll nutzen.

Zitat:
Das hat mich ehrlich gesagt noch nie gestört
Mich auch nicht, das war eher ein Spontaneinfall während des Entwurfsschreibens

Zitat:
(und ich finde deinen Vorschlag dazu auch nicht wirklich eine Verbesserung)
Ich auch nicht.

Zitat:
Und es funktioniert auch wie es soll. "Free" ist nur eine normale Prozedur deren einziger Sinn es ist zu überprüfen, ob "Self <> Nil" ist und dann den Default-Destruktor "Destroy" aufruft. Nichts hält mich davon ab einen Destruktor mit einem anderen Namen zu definieren und einfach direkt aufzurufen. Es ist nämlich der Aufruf des Destruktors, der die Speicherfreigabe veranlasst, nicht der von Free (sonst bräuchten wir ja kein spezielles Keyword für den Destruktor).
Schöner wäre es aber, wenn der Destruktor das selbst überprüfen würde, dann bräuchten wir eben diese Methode Free nicht.

Zitat:
Zitat von himitsu:
- die Generics so erweitern, daß man statt typen auch Konstanten verwenden kann.
(würde dann teilweise ähnliche Möglichkeiten bieten, wie die Makros in C)
Ich weiß nicht, ob das wirklich so gut wäre... es wäre schon schwierig sowas zu parsen:
Letztendlich wäre das ja nichts groß anderes, als die Schemata. Man müsste das nur syntaktisch ein bisschen austüfteln.
Marvin
  Mit Zitat antworten Zitat
Benutzerbild von JamesTKirk
JamesTKirk

 
FreePascal / Lazarus
 
#25
  Alt 12. Jan 2012, 16:10
Diese Reihenfolge ist einerseits der Tatsache geschuldet, dass Pascal auf Single-Pass-Kompilierung ausgelegt ist (das heißt keine Nutzung darf vor der Deklaration erfolgen (mit wenigen Ausnahmen ala forward oder Pointer auf Records)), anderseits arbeiten "Unit basierte" Compiler wie FPC und Delphi so, dass sie sich beim Kompilieren einer weiteren Unit erst nur den Interface Teil der Unit anschauen müssen, um festzustellen, ob sich was geändert hat und demnach die erste Unit neukompiliert werden muss. Wenn du nun Teile des Implementationbereichs in den Interfacebereich schiebst, so muss der Compiler auch über diese Teile hinweg parsen, selbst wenn er sie eventuell gar nicht benötigt, weil sich nichts geändert hat.
Am Interface-Teil will ich ja an sich auch nichts ändern, sondern fände es schön, den implementation-Teil aufzusplitten in Deklarationen und die tatsächliche Implementierung. Und wenn der public-Teil am Anfang der Unit steht, muss der Compiler ja auch über nichts überflüssiges hinwegparsen.
Wenn man sich aber deine Anmerkung bzgl. globalen Properties ansieht (welche, @restliche DP in FPC übrigens verfügbar sind), dann müsste dort mindestens ein "private" Abschnitt vor einem "public" Abschnitt kommen und du hast den Salat wieder.

Zitat von implementation:
Zitat:
Nichtsdestotrotz: Free Pascal unterstützt nicht-referenzgezählte Interfaces (so genannte CORBA Interfaces). Die kannst du (per Unit oder eventuell sogar lokal per Deklaration, das weiß ich grade nicht) ganz einfach per "{$interfaces corba}" aktivieren.
Wenn dies tatsächlich per Deklaration geht, wäre das sehr praktisch. Dennoch fände ich es deutlich schöner, diese mit einem Schlüsselwort zu unterscheiden, da sie von ganz anderer Natur sind.
Ich hab mal schnell getestet: es ist wirklich eine lokale Option (wie {$M+/-}).

Zitat von implementation:
Zitat:
Und es funktioniert auch wie es soll. "Free" ist nur eine normale Prozedur deren einziger Sinn es ist zu überprüfen, ob "Self <> Nil" ist und dann den Default-Destruktor "Destroy" aufruft. Nichts hält mich davon ab einen Destruktor mit einem anderen Namen zu definieren und einfach direkt aufzurufen. Es ist nämlich der Aufruf des Destruktors, der die Speicherfreigabe veranlasst, nicht der von Free (sonst bräuchten wir ja kein spezielles Keyword für den Destruktor).
Schöner wäre es aber, wenn der Destruktor das selbst überprüfen würde, dann bräuchten wir eben diese Methode Free nicht.
Es wäre interessant die Begründung von Borland zu hören, warum sie sich damals dafür entschieden haben, dass "Destroy" das nicht überprüft...

Zitat von implementation:
Zitat:
Zitat von himitsu:
- die Generics so erweitern, daß man statt typen auch Konstanten verwenden kann.
(würde dann teilweise ähnliche Möglichkeiten bieten, wie die Makros in C)
Ich weiß nicht, ob das wirklich so gut wäre... es wäre schon schwierig sowas zu parsen:
Letztendlich wäre das ja nichts groß anderes, als die Schemata. Man müsste das nur syntaktisch ein bisschen austüfteln.
Die Einführung der Schemata wäre wahrscheinlich einfacher als sowas. "<" ist einfach zu sehr belastet...

Gruß,
Sven
Sven
  Mit Zitat antworten Zitat
12. Jan 2012, 17:07
Dieses Thema wurde am "12. Jan 2012, 17:07 Uhr" von "TBx" aus dem Forum "Programmieren allgemein" in das Forum "Software-Projekte der Mitglieder" verschoben.
Benutzerbild von himitsu
himitsu

 
Delphi 12 Athens
 
#27
  Alt 13. Jan 2012, 00:09
Delphi-Quellcode:
if not (SomeEnum in SomeSet) then
// vs
if not SomeEnum in SomeSet then
NOT ist nunmal höherrangig, als IN, da führt kein drumrum.

Auch wenn man jetzt das IN vorrangig behandeln würde, wäre das keine Lösung, da sich dann Andere wieder beschweren würden, weil plötzlich was Anderes nicht mehr ginge.

Es sieht zwar nicht so schön aus, aber ein &String sollte es doch tun, oder nicht
genau, voll häßlich.

Ich weiß nichtmal, warum man STRING so behandeln mußte?
Und wenn, warum ist dann Integer, Boolean und Co. nicht auch fett?

Was heißt OTA?
Open Tools API ... die Schnittstelle zur IDE

Was möchtest du da genau? Hättest du da vielleicht ein Beispiel?
(angenommen dort sind bestimmte Typen im Record, wie z.B. Strings, dyn. Array oder Interfaces)
Delphi-Quellcode:
var
  X, Y: TMyRecord;
begin << X und Y werden initialisiert (wenn dort bestimmte Typen drauf sind)

Y := X; << es wird eine Kopierfunktion aufgerufen, welche den Record kopiert

end; << es wird eine Funktion aufgerufen, welche den Record freigibt
In diesen schon vorhandenen Funktionen muß man nur noch schauen, ob in der RTTI des Records die neuen Operatoren stehen und ruft sie dann auf.
Es gibt schon seit langem einen EDN.Eintrag von mir, aber auf mich hört ja keiner. (vorallem da es keine großen Änderungen mit sich zieht)

Geändert von himitsu (13. Jan 2012 um 10:43 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von BUG
BUG
 
#28
  Alt 13. Jan 2012, 01:06
Auch wenn man jetzt das IN vorrangig behandeln würde, wäre das keine Lösung, da sich dann Andere wieder beschweren würden, weil plötzlich was Anderes nicht mehr ginge.
Das ganze Problem kommt daher, das die booleschen und die bitweisen Operatoren gleich heißen.
Die Bitweisen möchte man halt gerne stark binden und die Booleschen schwach.

Intuitiv würde ich aber auch eher immer annehmen, das ein boolescher Operator gemeint ist.
Wer mit bitweisen Operatoren werkelt, kann auch ein paar Klammern mehr vertragen

Oder wie wäre es mit lnot, land, lor
  Mit Zitat antworten Zitat
Benutzerbild von JamesTKirk
JamesTKirk

 
FreePascal / Lazarus
 
#29
  Alt 13. Jan 2012, 14:54
Delphi-Quellcode:
if not (SomeEnum in SomeSet) then
// vs
if not SomeEnum in SomeSet then
NOT ist nunmal höherrangig, als IN, da führt kein drumrum.

Auch wenn man jetzt das IN vorrangig behandeln würde, wäre das keine Lösung, da sich dann Andere wieder beschweren würden, weil plötzlich was Anderes nicht mehr ginge.
Darum gings doch gerade. NamenLozer hatte geschrieben, dass er gerne sehen würde, dass z.B. ">" stärker bindet als z.B. "and". Und wenn wir da schon dabei sind, dann hätte ich gerne, dass "in" stärker bindet als "not", weil ich mir echt keine wirkliche Situation vorstellen kann, in der "(not SomeEnum) in SomeSet" Sinn hätte... aus Compilersicht ist das was wir aktuell haben vielleicht sogar die einfachere Lösung (also das "not" stärker bindet).

Zitat von himitsu:
Es sieht zwar nicht so schön aus, aber ein &String sollte es doch tun, oder nicht
genau, voll häßlich.

Ich weiß nichtmal, warum man STRING so behandeln mußte?
Und wenn, warum ist dann Integer, Boolean und Co. nicht auch fett?
Weil Integer, Boolean und Co. keine Schlüsselwörter sind. Der Compiler würde dich nicht davon abhalten eine eigene Funktion "Integer" zu definieren. String ist wahrscheinlich ein wegen ShortString ein Schlüsselwort:

Delphi-Quellcode:
type
  String42 = String[42];
Zitat von himitsu:
Was heißt OTA?
Open Tools API ... die Schnittstelle zur IDE
Danke.

Zitat von himitsu:
Was möchtest du da genau? Hättest du da vielleicht ein Beispiel?
(angenommen dort sind bestimmte Typen im Record, wie z.B. Strings, dyn. Array oder Interfaces)
Delphi-Quellcode:
var
  X, Y: TMyRecord;
begin << X und Y werden initialisiert (wenn dort bestimmte Typen drauf sind)

Y := X; << es wird eine Kopierfunktion aufgerufen, welche den Record kopiert

end; << es wird eine Funktion aufgerufen, welche den Record freigibt
In diesen schon vorhandenen Funktionen muß man nur noch schauen, ob in der RTTI des Records die neuen Operatoren stehen und ruft sie dann auf.
Es gibt schon seit langem einen EDN.Eintrag von mir, aber auf mich hört ja keiner. (vorallem da es keine großen Änderungen mit sich zieht)
Die Kopierfunktion könnte aber von überladenen Zuweisungsoperatoren beeinflusst werden...
Diese Ereignisse wären aber durchaus interessant, das müsste ich mir mal im FPC anschauen, was man da machen könnte.

Gruß,
Sven
Sven
  Mit Zitat antworten Zitat
Namenloser

 
FreePascal / Lazarus
 
#30
  Alt 13. Jan 2012, 15:08
Zitat von himitsu:
Was möchtest du da genau? Hättest du da vielleicht ein Beispiel?
(angenommen dort sind bestimmte Typen im Record, wie z.B. Strings, dyn. Array oder Interfaces)
Delphi-Quellcode:
var
  X, Y: TMyRecord;
begin << X und Y werden initialisiert (wenn dort bestimmte Typen drauf sind)

Y := X; << es wird eine Kopierfunktion aufgerufen, welche den Record kopiert

end; << es wird eine Funktion aufgerufen, welche den Record freigibt
In diesen schon vorhandenen Funktionen muß man nur noch schauen, ob in der RTTI des Records die neuen Operatoren stehen und ruft sie dann auf.
Es gibt schon seit langem einen EDN.Eintrag von mir, aber auf mich hört ja keiner. (vorallem da es keine großen Änderungen mit sich zieht)
Das hab ich mir auch schon gewünscht. Ich habe mich schonmal mit einem Interface beholfen, das in einem Record verpackt ist. Ist aber ein ziemlicher Hack.

Das traurige ist ja, dass entsprechende Funktionen zum Finalisieren von Records und Arrays ja bereits vorhanden sind – sieht man auch im Assembler-Code. Nur leider gibt es keine Möglichkeit, sich dort einzuklinken.

Geändert von Namenloser (13. Jan 2012 um 15:11 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 3 von 5     123 45      


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 00:48 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