|
![]() |
|
Registriert seit: 9. Sep 2004 Ort: München 604 Beiträge FreePascal / Lazarus |
#1
So... es wird Zeit, dass ich mich auch mal in diese Diskussion einmische.
![]()
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" ![]()
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. ![]()
[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:
Schematypen stehen bei mindestens einem FPC-Entwickler auf der Wunschliste.
type
// Schema-Typ, wie in GPC: TCharArray(start, length: Integer) = array [start..start+length] of char; TSample = TCharArray(0,6); Weil's grad zum Kontext passt noch der Einwurf Himitsus dazu:
Delphi-Quellcode:
Sieht einfach nur häßlich aus und paßt nicht zur Pascal/Delphi-Syntax.
TCharArray(start, length: Integer) = array [start..start+length] of char;
TSample = TCharArray(0,6); ![]() - 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)
Delphi-Quellcode:
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).
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. ![]() - ein mehrstufiger Compiler, bzw. ein intelligenterer, so daß man besseren Zugriff auf die Typen hat, welche im denerischen Type enthalten sind.
![]() - generische Prozeduren, Interfaces und Class Helper (nicht nur Klassen.Methoden)
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; ... ![]() - Class Helper Record Helper für einfache Basistypen, wie t.B. den Integer oder den String
- Interface Helper ![]() ![]() - Operatoren für Interfaces
![]() ![]() - 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) ![]() - 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 ![]() - daß man bei dyn. Arrays das CopyOnWrite aktivieren kann, so wie es bei den Strings auch vorhanden ist
![]() -
![]() ![]() - string aus den reservierten Wörtern rausnehmen
![]() - ein "caseend" für die varianten Recordteile ("end" geht ja nicht mehr ... das hätte man gleich zu Beginn nicht vergessen dürfen
![]() ![]() - das Strg+Linksklick auf einen generischen Teil (Methode,Feld,...) nicht bei "implementation" landet, sondern beim generischen Typen
![]()
![]()
Delphi-Quellcode:
Dass ich da Klammern setzen muss, hat mich schon immer aufgeregt...
if not (SomeEnum in SomeSet) then
// vs if not SomeEnum in SomeSet then ![]()
![]()
![]() ![]()
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:
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.
bar := TMyFooClass.Create(); // <- normal ohne GC
bar := new TMyFooClass(); // <- GC'ed
Delphi-Quellcode:
Wie gut das funktionieren würde, wenn man Objekte über Prozeduren hinweg reicht, weiß ich noch nicht, aber es wäre vielleicht eine Idee...
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; ![]() 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)
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?
Aber dann wäre es nicht mehr ganz kompatibel zum alten Code. Und was ich mir wünsche (und vielleicht auch mal implementieren werde):
So... Ende der langen Liste ![]() Gruß, Sven
Sven
[Free Pascal Compiler Entwickler] this post is printed on 100% recycled electrons Geändert von JamesTKirk (12. Jan 2012 um 15:22 Uhr) Grund: Eigenen Wunsch ein wenig korrigiert |
![]() |
Registriert seit: 5. Mai 2008 940 Beiträge FreePascal / Lazarus |
#2
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"
![]() 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.
![]() 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)
![]() Das hat mich ehrlich gesagt noch nie gestört
![]() ![]() (und ich finde deinen Vorschlag dazu auch nicht wirklich eine Verbesserung)
![]() ![]() 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).
![]() ![]() - 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)
GNU/Linux- und FreeBSD-User |
![]() ![]() ![]() ![]() ![]() ![]() |
![]() |
Registriert seit: 9. Sep 2004 Ort: München 604 Beiträge FreePascal / Lazarus |
#3
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.
![]() ![]() 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.
![]() ![]() 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).
![]() ![]() ![]() - 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) ![]() Gruß, Sven
Sven
[Free Pascal Compiler Entwickler] this post is printed on 100% recycled electrons |
![]() |
Registriert seit: 11. Okt 2003 Ort: Elbflorenz 44.336 Beiträge Delphi 12 Athens |
#4
Delphi-Quellcode:
if not (SomeEnum in SomeSet) then
// vs if not SomeEnum in SomeSet then 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
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?
Was möchtest du da genau? Hättest du da vielleicht ein Beispiel?
Delphi-Quellcode:
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.
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 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)
Ein Therapeut entspricht 1024 Gigapeut.
Geändert von himitsu (13. Jan 2012 um 10:43 Uhr) |
![]() |
Registriert seit: 4. Dez 2003 Ort: Cottbus 2.094 Beiträge |
#5
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.
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 ![]() |
![]() |
Registriert seit: 9. Sep 2004 Ort: München 604 Beiträge FreePascal / Lazarus |
#6
Delphi-Quellcode:
if not (SomeEnum in SomeSet) then
// vs if not SomeEnum in SomeSet then 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
Ich weiß nichtmal, warum man STRING so behandeln mußte? Und wenn, warum ist dann Integer, Boolean und Co. nicht auch fett? ![]()
Delphi-Quellcode:
type
String42 = String[42]; ![]() Was heißt OTA?
![]() Was möchtest du da genau? Hättest du da vielleicht ein Beispiel?
Delphi-Quellcode:
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.
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 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) 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
[Free Pascal Compiler Entwickler] this post is printed on 100% recycled electrons |
![]() |
Registriert seit: 7. Jun 2006 Ort: Karlsruhe 3.724 Beiträge FreePascal / Lazarus |
#7
![]() Was möchtest du da genau? Hättest du da vielleicht ein Beispiel?
Delphi-Quellcode:
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.
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 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 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) |
![]() |
Registriert seit: 11. Okt 2003 Ort: Elbflorenz 44.336 Beiträge Delphi 12 Athens |
#8
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.
Ein Therapeut entspricht 1024 Gigapeut.
|
![]() |
Registriert seit: 5. Mai 2008 940 Beiträge FreePascal / Lazarus |
#9
Die System.pas verändern, neu kompilieren und dann auch noch alle BPLs neu kompilieren.
GNU/Linux- und FreeBSD-User |
![]() ![]() ![]() ![]() ![]() ![]() |
![]() |
Registriert seit: 11. Okt 2003 Ort: Elbflorenz 44.336 Beiträge Delphi 12 Athens |
#10
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.
Ein Therapeut entspricht 1024 Gigapeut.
|
![]() |
Ansicht |
![]() |
![]() |
![]() |
ForumregelnEs 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
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
![]() |
![]() |