TStrings verbundene Objekte. geht nicht oder bin ich zu blöd
Re: TStrings verbundene Objekte. geht nicht oder bin ich zu
Ok, jetzt weiß ich wenigstens, dass das in TMemo nicht implementiert ist, und dasss nicht ich irgeneinen Mist bau.
Für mich bleibt das aber ein Bug, und zwar aus folgenden Überlegungen heraus:
ein Bug liegt vor, wenn ein Stück Software sich anders verhält, als vernünftigerweise angenommen werden kann, d.h. z.B von relevanter Doku abweicht oder grob gegen den gesunden Menschenverstand verstößt (also z.B. abstürzt jedesmal wenn Nachbar's Katze miaut).
relevante Doku: Die Doku von TMemo sagt nichts über die Eigenschaften von TMemo.Lines, es deklariert lediglich die Eigenschaft Lines als TStrings. Damit wird die Seite über TStrings zur relevanten Doku von TMemo.Lines. Dort steht:
An instance of TStrings is never created directly, instead a descendent class such as TStringList should be created. This is because TStrings is an abstract class which does not implement all methods; TStrings also doesn't store any strings, this is the functionality introduced in descendents such as TStringList.
Zu deutsch: einige Methoden sind implementiert, andere nicht. Eine ganze Reihe von Methoden ist als abstract deklariert, eine größere Anzahl lediglich als virtual. Ich (und vielleicht bin ich da zu gutgläubig) schließe daraus, dass die nicht abstrakt deklarierten eine Funktionalität haben.
Und wenn ich dann ausprobiere, wie sich eine engegen der Warnung doch kreirte Instanz von TStrings verhält, und diese sowohl den String als auch das assoziierte Objekt speichert, dann ist ein davon abweichendes Verhalten in einer Komponente, die eine Eigenschaft vom Typ TStrings hat, ein Bug.
Dass Delphi7 sich genauso verhält ist m.E. ein lahmes Argument. Niemand hat die Entwickler von FPC geheißen, auch die Bugs von Delphi zu implementieren.
Es mag gute Gründe geben, die Funktionalität "Objekte" nicht in TMemo zu implementieren. Wer irgendwas auf einer abstrakten Basisklasse aufbaut, hat selbstverständlich jedes Recht der Welt, davon das zu implementieren, was er für nötig hält, und für den Rest nur Stubs, damit nichts passiert. Der Anwender erwartet aber zunächst einmal, dass die Basisklasse vollständig implementiert wird, und soweit dies nicht der Fall ist, sollte das aber in der Doku (hier zu TMemo) aufgeführt sein: "The Lines property of TMemo does not implement TStrings' associated objects. TMemo.Lines.Object[] will always return NIL." oder sowas ähnliches. Dann hätte man auf meinen Post schlichtweg mit "RTFM" antworten können.
Ich werde einen entsprechenden Kommentar in den zitierten Bug einstellen.
Für mich bleibt das aber ein Bug, und zwar aus folgenden Überlegungen heraus:
ein Bug liegt vor, wenn ein Stück Software sich anders verhält, als vernünftigerweise angenommen werden kann, d.h. z.B von relevanter Doku abweicht oder grob gegen den gesunden Menschenverstand verstößt (also z.B. abstürzt jedesmal wenn Nachbar's Katze miaut).
relevante Doku: Die Doku von TMemo sagt nichts über die Eigenschaften von TMemo.Lines, es deklariert lediglich die Eigenschaft Lines als TStrings. Damit wird die Seite über TStrings zur relevanten Doku von TMemo.Lines. Dort steht:
An instance of TStrings is never created directly, instead a descendent class such as TStringList should be created. This is because TStrings is an abstract class which does not implement all methods; TStrings also doesn't store any strings, this is the functionality introduced in descendents such as TStringList.
Zu deutsch: einige Methoden sind implementiert, andere nicht. Eine ganze Reihe von Methoden ist als abstract deklariert, eine größere Anzahl lediglich als virtual. Ich (und vielleicht bin ich da zu gutgläubig) schließe daraus, dass die nicht abstrakt deklarierten eine Funktionalität haben.
Und wenn ich dann ausprobiere, wie sich eine engegen der Warnung doch kreirte Instanz von TStrings verhält, und diese sowohl den String als auch das assoziierte Objekt speichert, dann ist ein davon abweichendes Verhalten in einer Komponente, die eine Eigenschaft vom Typ TStrings hat, ein Bug.
Dass Delphi7 sich genauso verhält ist m.E. ein lahmes Argument. Niemand hat die Entwickler von FPC geheißen, auch die Bugs von Delphi zu implementieren.
Es mag gute Gründe geben, die Funktionalität "Objekte" nicht in TMemo zu implementieren. Wer irgendwas auf einer abstrakten Basisklasse aufbaut, hat selbstverständlich jedes Recht der Welt, davon das zu implementieren, was er für nötig hält, und für den Rest nur Stubs, damit nichts passiert. Der Anwender erwartet aber zunächst einmal, dass die Basisklasse vollständig implementiert wird, und soweit dies nicht der Fall ist, sollte das aber in der Doku (hier zu TMemo) aufgeführt sein: "The Lines property of TMemo does not implement TStrings' associated objects. TMemo.Lines.Object[] will always return NIL." oder sowas ähnliches. Dann hätte man auf meinen Post schlichtweg mit "RTFM" antworten können.
Ich werde einen entsprechenden Kommentar in den zitierten Bug einstellen.
-
- Beiträge: 3444
- Registriert: Mo 11. Sep 2006, 10:24
- OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
- CPU-Target: X32 / X64 / ARMv5
- Wohnort: Krefeld
Re: TStrings verbundene Objekte. geht nicht oder bin ich zu
Richtiger Weise müsste die Funktionalität "Objekte" in TStrings abstrakt sein. Hier wird schließlich etwas gespeichert und TStrings selbst speichert nicht, sondern seine Nachfolger müssen das Speichermedium implementieren. Es könnte ja schließlich auch z.B. eine Datei sein. Das Kann TStrings nicht voraussehen. Auch im String selbst irgendetwas zusätzlich speichern geht nicht. Dann würde man das bei z.B. bei TMemo sehen.ghieber hat geschrieben:Ich (und vielleicht bin ich da zu gutgläubig) schließe daraus, dass die nicht abstrakt deklarierten eine Funktionalität haben.
Meiner Ansicht nach wäre es also ein Bug in TStrings, wenn die Objekte - Funktionalität nicht abstrakt ist.
-Michael
Re: TStrings verbundene Objekte. geht nicht oder bin ich zu
Das ist eine gute Idee. Das Embarcadero Wording lautet:ghieber hat geschrieben: Ich werde einen entsprechenden Kommentar in den zitierten Bug einstellen.
http://docs.embarcadero.com/products/ra ... Lines.htmlNote: Although Lines is implemented as a TStrings descendant, it does not implement the support for associating objects with the strings in the list.
Re: TStrings verbundene Objekte. geht nicht oder bin ich zu
TMemo erzeugt die Strings als "TTextStrings". Hier gibt es protected Methoden "SetObject", "PutObject" und "HasObject". Die überschriebene öffentliche Methode "AddObject" hängt das übergebene Object in ein Array von "TLineRange" Records ein. Allerdings ist kein lesender Zugriff auf das Objekt implementiert. Daher meine ich, dass man mit einem
das Problem zumindest für TMemo fixen könnte.
Code: Alles auswählen
type
TTextStrings = class (TStrings)
// ...
public
property Objects[AIndex: Integer]: TObject read GetObject write PutObject;
end;
-
- Beiträge: 3444
- Registriert: Mo 11. Sep 2006, 10:24
- OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
- CPU-Target: X32 / X64 / ARMv5
- Wohnort: Krefeld
Re: TStrings verbundene Objekte. geht nicht oder bin ich zu
Darf Lazarus besser als Delphi sein ???
-Michael

-Michael
Re: TStrings verbundene Objekte. geht nicht oder bin ich zu
Ich denke man sollte die Dokumentation ändern und nicht versuchen, das in TMemo zu implementieren.
TMemo ist ein Editor, in den man hineinschreibt, löscht, Copy&Pasted, Zeilenumbrüche einfügt etc.
Das alles passt nicht zu einem "unsichtbaren" Objekt, das an einer (flüchtigen) Zeile hängt.
Ich würde da auf TListbox verweisen, welche eher programmgesteuert funktioniert.
TMemo ist ein Editor, in den man hineinschreibt, löscht, Copy&Pasted, Zeilenumbrüche einfügt etc.
Das alles passt nicht zu einem "unsichtbaren" Objekt, das an einer (flüchtigen) Zeile hängt.
Ich würde da auf TListbox verweisen, welche eher programmgesteuert funktioniert.
Re: TStrings verbundene Objekte. geht nicht oder bin ich zu
Theo: Ich hab kein Problem damit, dass TMemo keine Objekte unterstützt - solange ich ne Chance habe das zu erfahren, bevor ich nen Tag damit verplempere, Fehler zu suchen, zunächst mal in meinem eigenen Code, dem ich als Gelegenheitsprogrammierer erst mal deutlich weniger trau als den Libraries. In der Zeit hätte ich die von mit benötigte Funktionalität nämlich dreimal anders implementiert.
Michael: Ja, Lazarus darf besser als Delphi sein. Lazarus ist in erster Linie mal anders, durch die Plattformunabhängigkeit. Dadurch ist es zwangsläufig in einigen Punkten "schlechter", in dem Sinne dass es manche (Windows - spezifische) Delphi - Funktionalitäten nicht implementiert. Wer seinen Code von Delphi nach Lazarus portieren will, weiß das und kann entscheiden, ob sich der Aufwand lohnt. Wer umgekehrt in Lazarus programmiert, weil er die Multiplattform - Fähigkeit braucht, oder weil ihm einfach Open Source sympathischer ist, oder warum auch immer, wird eher nicht nach Delphi zurückportieren wollen, und sich über zusätzliche Features freuen.
Eine Ausnahme ist vielleicht die Entwicklung universeller Komponenten, libraries etc. So was sollte idealerweise natürlich unter beiden Plattformen laufen.
Den Bug Kommentar hab ich gemacht, und gebeten, den Status wieder von feature request höher zu setzte, und das entweder gelegentlich zu implementieren, oder die Dokumentation zu ändern. Und ich konnte mir die Bemerkung nicht verkneifen, dass das Argument "Delphi kann das auch nicht" eben nur bedeutet, dass Delphi dann halt auch nen Bug hat...
Michael: Ja, Lazarus darf besser als Delphi sein. Lazarus ist in erster Linie mal anders, durch die Plattformunabhängigkeit. Dadurch ist es zwangsläufig in einigen Punkten "schlechter", in dem Sinne dass es manche (Windows - spezifische) Delphi - Funktionalitäten nicht implementiert. Wer seinen Code von Delphi nach Lazarus portieren will, weiß das und kann entscheiden, ob sich der Aufwand lohnt. Wer umgekehrt in Lazarus programmiert, weil er die Multiplattform - Fähigkeit braucht, oder weil ihm einfach Open Source sympathischer ist, oder warum auch immer, wird eher nicht nach Delphi zurückportieren wollen, und sich über zusätzliche Features freuen.
Eine Ausnahme ist vielleicht die Entwicklung universeller Komponenten, libraries etc. So was sollte idealerweise natürlich unter beiden Plattformen laufen.
Den Bug Kommentar hab ich gemacht, und gebeten, den Status wieder von feature request höher zu setzte, und das entweder gelegentlich zu implementieren, oder die Dokumentation zu ändern. Und ich konnte mir die Bemerkung nicht verkneifen, dass das Argument "Delphi kann das auch nicht" eben nur bedeutet, dass Delphi dann halt auch nen Bug hat...
Re: TStrings verbundene Objekte. geht nicht oder bin ich zu
Ist jetzt aber auch nicht so ein grosses Ding, oder? Komm mal ein bisschen runter.ghieber hat geschrieben: Und ich konnte mir die Bemerkung nicht verkneifen, dass das Argument "Delphi kann das auch nicht" eben nur bedeutet, dass Delphi dann halt auch nen Bug hat...

Das ist alles von Freiwilligen in der Freizeit gemacht, da sind "scharfe Worte" eher kontraproduktiv.
Und wenn man ein Feature dringend haben will, dann implementiert man es und schickt es ein.
http://wiki.freepascal.org/Creating_A_Patch/de
Locker bleiben.

Re: TStrings verbundene Objekte. geht nicht oder bin ich zu
Theo: wenn ich jemandem auf die Füße getreten sein sollte - war keine böse Absicht, und ich bitte in aller Form um Entschuldigung.
Die sachlichen Argumente, die hier hier für oder gegen die Implementierung einer Funktionalität angeführt wurden sind alle nachvollziehbar und m.E. völlig ausreichend - da braucht's kein "und Delphi kann das auch nicht" mehr. Das klingt für mich so ein wenig nach Totschlagargument. Vermutlich berühren wir hier aber - wie Michael mit seinem rhetorischen "Darf Lazarus besser als Delphi sein???" andeutet - die Grundsatzdiskussion in wie weit Lazarus / FPC ein Delphi - Clone (incl der Schwächen) sein soll oder ein eigenständiges Produkt. Ebenso vermutlich wurde diese Diskussion im Lazarus/FPC - Team bis zum Abwinken geführt, und mancher von Euch kann's nicht mehr hören. Ich bin also evtl. auf einen Fuß getreten, der vom letzen mal noch weh tut. In dem Fall ein doppeltes "tut mir leid".
Die sachlichen Argumente, die hier hier für oder gegen die Implementierung einer Funktionalität angeführt wurden sind alle nachvollziehbar und m.E. völlig ausreichend - da braucht's kein "und Delphi kann das auch nicht" mehr. Das klingt für mich so ein wenig nach Totschlagargument. Vermutlich berühren wir hier aber - wie Michael mit seinem rhetorischen "Darf Lazarus besser als Delphi sein???" andeutet - die Grundsatzdiskussion in wie weit Lazarus / FPC ein Delphi - Clone (incl der Schwächen) sein soll oder ein eigenständiges Produkt. Ebenso vermutlich wurde diese Diskussion im Lazarus/FPC - Team bis zum Abwinken geführt, und mancher von Euch kann's nicht mehr hören. Ich bin also evtl. auf einen Fuß getreten, der vom letzen mal noch weh tut. In dem Fall ein doppeltes "tut mir leid".
Re: TStrings verbundene Objekte. geht nicht oder bin ich zu
Ist schon OK, war nicht so ernst gemeint.ghieber hat geschrieben:Theo: wenn ich jemandem auf die Füße getreten sein sollte - war keine böse Absicht, und ich bitte in aller Form um Entschuldigung.
Für mich hat dieses Thema hier (Objects an TMemo Lines) nur ein bisschen zu viel Raum bekommen.
Es ist nach meiner Einschätzung nicht so weltbewegend bzw. hält einen nicht wirklich auf.
Re: TStrings verbundene Objekte. geht nicht oder bin ich zu
Und ich hab mir inzwischen den Quelltest von textstrings.pas angesehen, und damit ist klar, warum das nicht implementiert ist und auch ohne großen Umbau nicht geht.
Meinen Bug - Kommentar habe ich geändert, die Spitze ist raus und dafür die Empfehlung konkretisiert, die Doku zu ergänzen.
Ich schlage vor, den Thread zu schließen.
Meinen Bug - Kommentar habe ich geändert, die Spitze ist raus und dafür die Empfehlung konkretisiert, die Doku zu ergänzen.
Ich schlage vor, den Thread zu schließen.
-
- Beiträge: 3444
- Registriert: Mo 11. Sep 2006, 10:24
- OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
- CPU-Target: X32 / X64 / ARMv5
- Wohnort: Krefeld
Re: TStrings verbundene Objekte. geht nicht oder bin ich zu
Finde ich nicht.theo hat geschrieben: Für mich hat dieses Thema hier (Objects an TMemo Lines) nur ein bisschen zu viel Raum bekommen.
Es ist nach meiner Einschätzung nicht so weltbewegend bzw. hält einen nicht wirklich auf.
Es wär meiner Ansicht nach sinnvoll (wenn auch nicht Delphi-Kompatibel) wenn TMemo.Lines tatsächlich eine funktionsfähige "Objects" Property hätte. Ist vermutlich auch nicht schwierig zu implementieren.
Und wenn die Obtects Property absichtlich nicht implementiert ist, sollte es eine Exception geben, wenn man sie anspricht.
-Michael
Re: TStrings verbundene Objekte. geht nicht oder bin ich zu
Aha, das ist nicht schwierig?mschnell hat geschrieben: Es wär meiner Ansicht nach sinnvoll (wenn auch nicht Delphi-Kompatibel) wenn TMemo.Lines tatsächlich eine funktionsfähige "Objects" Property hätte.
Ist vermutlich auch nicht schwierig zu implementieren.
Dann mach es doch! Das wäre doch mal eine echte Alternative zum rumlabern und Halbwissen verbreiten.
Und nein, nicht seitenweise diskutieren sondern machen!
Re: TStrings verbundene Objekte. geht nicht oder bin ich zu
Sicher wäre es sinnvoll, wenn TMemo.Lines eine funktionierende Objects - Komponente hätte. Leider ist es in die bestehende Implementierung schwer einzubauen.
die Lines sind als TTextStrings deklariert, TTextstrings ist von TStrings abgeleitet. TextStrings speichert primär den gesamten Text in einem (langen...) String FText. die Eigenschaft Strings[] wird durch ein dynamisches Array von Records:
dargestellt. Soweit sieht das ja gut aus. Den Records werden sogar z.B. in der Prozedur AddObject die Objekte Zugewiesen.
Das Problem kommt dann, wenn der String FText geändert wird, wozu TTextstrings Methoden hat, die in TStrings (und auch TStringList) nicht exisitieren, und der zeichenweisen editiererei von TMemo, auch über Zeilengrenzen hinweg, dienen. Jede Methode, die das tut (FText ändern), setzt ein Flag TArraysValid auf False, und wenn dann das Array gebraucht wird, wird das alte array freigegeben und ein neues erzeugt, indem der Text nach Zeilenende - Markierungen ($10, $13) durchsucht wird und die ZeilenAnfangs- und Ende - Marker im TextLineRange - record entsprechend gesetzt werden. Der String des Records wird nur bei Bedarf aus FText rauskopiert, und die Objektzeiger gehen beim Neubau des Arrays unwiderruflich flöten, das array wird nach der Speicherreservierung erstmal mit 0-Bytes initialisiert.
Um die Objekte zu erhalten, müsste entweder diese ganze Logik umgebaut werden, oder ein zweites Array für die Objekte aufgebaut werden, das dann mit dem anderen synchronisiert wird - nicht einfach, aber sicherlich machbar. Ein anderes Problem ist konzeptueller Natur, es muß festgelegt werden, was mit einem Objekt passiert, das zu einer Zeile (oder besser, Absatz) gehört, die verschwindet - in dem z.B. der Benutzer beim Editieren den Zeilenumbruch löscht, den Text aber stehen lässt. Wird das Objekt einfach freigegeben? mach ich ne Property Objektwaisen? Und die letzte Frage dabei ist, wieviel Performance kostet das?
Der Quelltext sieht für mich ganz danach aus, als hätte der Autor von TTextString zunächst vorgehabt, die Objektfunktionalität zu implementieren, dies dann aber irgendwann aufgegeben - entweder wegen der besagten konzeptuellen Probleme, oder weil der Aufwand in keinem Verhältnis zum Nutzen stand, nach dem Motto, das braucht eh keiner, und weil, als die LCL geschrieben wurde, sicherlich 150 andere, wichtigere Baustellen offen waren.
Allerdings gibt es ein Verhalten, das TTextStrings und damit TMemo zeigt, und das evtl. als Bug zu qualifizieren ist: TTextLines akzeptiert, dass Objekte zugewiesen werden. Beim Neubau des Arrays gehen die Objektreferenzen verloren. Damit hat die Aufräumroutine im Destruktor von TMemo keine Chance, diese Objekte wieder vom Heap zu fegen --> Speicherleck. Vermutlich ist dies nie aufgefallen, weil niemand die Objekte eines Memo benutzt, weil sie ja doch nicht gehen. Vielleicht ist dies aber auch Grund für unerkärliche Abstürze "irgendwo da drausen", weil Codeleichen doch noch Objekte zuweisen, Codeleichen, die der Anwendungsprogrammierer vergessen hat zu entfernen, nachdem er die mit den TMemo-Objekten gewünschte Funktion anderweitig realisiert hat.
die Lines sind als TTextStrings deklariert, TTextstrings ist von TStrings abgeleitet. TextStrings speichert primär den gesamten Text in einem (langen...) String FText. die Eigenschaft Strings[] wird durch ein dynamisches Array von Records:
Code: Alles auswählen
TTextLineRange = record
StartPos: integer; // start of line in Text
EndPos: integer; // end of line in Text (= start of newline character(s))
Line: string; // cached line as string
TheObject: TObject; // user data
end;
Das Problem kommt dann, wenn der String FText geändert wird, wozu TTextstrings Methoden hat, die in TStrings (und auch TStringList) nicht exisitieren, und der zeichenweisen editiererei von TMemo, auch über Zeilengrenzen hinweg, dienen. Jede Methode, die das tut (FText ändern), setzt ein Flag TArraysValid auf False, und wenn dann das Array gebraucht wird, wird das alte array freigegeben und ein neues erzeugt, indem der Text nach Zeilenende - Markierungen ($10, $13) durchsucht wird und die ZeilenAnfangs- und Ende - Marker im TextLineRange - record entsprechend gesetzt werden. Der String des Records wird nur bei Bedarf aus FText rauskopiert, und die Objektzeiger gehen beim Neubau des Arrays unwiderruflich flöten, das array wird nach der Speicherreservierung erstmal mit 0-Bytes initialisiert.
Um die Objekte zu erhalten, müsste entweder diese ganze Logik umgebaut werden, oder ein zweites Array für die Objekte aufgebaut werden, das dann mit dem anderen synchronisiert wird - nicht einfach, aber sicherlich machbar. Ein anderes Problem ist konzeptueller Natur, es muß festgelegt werden, was mit einem Objekt passiert, das zu einer Zeile (oder besser, Absatz) gehört, die verschwindet - in dem z.B. der Benutzer beim Editieren den Zeilenumbruch löscht, den Text aber stehen lässt. Wird das Objekt einfach freigegeben? mach ich ne Property Objektwaisen? Und die letzte Frage dabei ist, wieviel Performance kostet das?
Der Quelltext sieht für mich ganz danach aus, als hätte der Autor von TTextString zunächst vorgehabt, die Objektfunktionalität zu implementieren, dies dann aber irgendwann aufgegeben - entweder wegen der besagten konzeptuellen Probleme, oder weil der Aufwand in keinem Verhältnis zum Nutzen stand, nach dem Motto, das braucht eh keiner, und weil, als die LCL geschrieben wurde, sicherlich 150 andere, wichtigere Baustellen offen waren.
Allerdings gibt es ein Verhalten, das TTextStrings und damit TMemo zeigt, und das evtl. als Bug zu qualifizieren ist: TTextLines akzeptiert, dass Objekte zugewiesen werden. Beim Neubau des Arrays gehen die Objektreferenzen verloren. Damit hat die Aufräumroutine im Destruktor von TMemo keine Chance, diese Objekte wieder vom Heap zu fegen --> Speicherleck. Vermutlich ist dies nie aufgefallen, weil niemand die Objekte eines Memo benutzt, weil sie ja doch nicht gehen. Vielleicht ist dies aber auch Grund für unerkärliche Abstürze "irgendwo da drausen", weil Codeleichen doch noch Objekte zuweisen, Codeleichen, die der Anwendungsprogrammierer vergessen hat zu entfernen, nachdem er die mit den TMemo-Objekten gewünschte Funktion anderweitig realisiert hat.
Re: TStrings verbundene Objekte. geht nicht oder bin ich zu
Im Prinzip müsste man eine Exception erzeugen, wenn TMemo Objects verwendet. Dazu müsste man
Auch wenn diese Diskussion einige nervt, ich habe dabei viel gelernt.
- TTextStrings.AddObject überschreiben und eine Exception erzeugen, wenn Objects <> nil; andernfalls TTextLines.Add aufrufen
- TTextStrings.PutObject genauso überschreiben
- Property TTextStrings.Objects[] als public deklarieren mit GetObject und OutObject als Getter/Setter
Auch wenn diese Diskussion einige nervt, ich habe dabei viel gelernt.