Discussion:
eigene Klasse (doppelt) zerstören
(zu alt für eine Antwort)
Stefan Koschke
2011-04-01 06:19:32 UTC
Permalink
Hallo zusammen,

schlechter Betreff, ich weiß ;-)
Folgendes Problem:
Ich habe eigene Klassen für den Zugriff auf Datenbanktabellen
geschaffen, die sehen skizziert etwa so aus:

unit class_tabports;
interface
uses DB, ADODB, Forms, SysUtils, Variants;
type
TTabports = class(TObject)
private
{ private-Deklarationen }
query: TAdoQuery;

protected
{ protected-Deklarationen }
public
{ public-Deklarationen }
constructor Create;
destructor Destroy; override;
procedure Update;
...
// published
{ published-Deklarationen }
end;
implementation

constructor TTabports.Create;
var
dbn: string;
begin
inherited Create;
query := TAdoQuery.Create(Nil);
... query verbinden
end;

destructor TTabports.Destroy;
begin
if query.Active = true then
query.Close;
if query <> Nil then
query.Free;
inherited;
end;

procedure TTabports.Update;
begin
query.requery;
end;
...

Diese Klasse wird im Programm irgendwomit .Create erzeugt und nach
Benutzungsende wieder mit .Free zerstört.
Unter bestimmten Umständen kann es aber vorkommen, daß das .Free doppelt
aufgerufen wird, daher hatte ich eine Abfrage vorgeschaltet
if meineKlasse <> Nil then
meineKlasse.free;

Leider funktioniert das nicht, weil die Klasse trotz .Free nicht Nil ist
und der nächste Zerstörungsversuch einen Laufzeitfehler erzeugt.

Ich könnte nun überall FreeAndNil(meineKlasse) verwenden, richtig?
Oder mach ich da generell was falsch?

Ciao
Stefan
Torge Ismer
2011-04-01 06:46:03 UTC
Permalink
Post by Stefan Koschke
Ich könnte nun überall FreeAndNil(meineKlasse) verwenden, richtig?
Oder mach ich da generell was falsch?
FreeAndNil(...) ist der richtige Ansatz. Das von dir beobachtete Verhalten
ist normal. Free gibt das Objekt frei. Der Zeiger deiner Objektvariablen
zeigt danach aber immer noch auf den entsprechenden Speicher. Die Variable
mußt du nach dem Löschen selber auf NIL setzen. Also entweder:

aObject.free;
aObject := nil;

oder eben

FreeAndNil(aObject)

was genau das gleiche tut.

Grüße
Torge
Stefan Koschke
2011-04-01 07:31:20 UTC
Permalink
Post by Torge Ismer
Post by Stefan Koschke
Ich könnte nun überall FreeAndNil(meineKlasse) verwenden, richtig?
Oder mach ich da generell was falsch?
FreeAndNil(...) ist der richtige Ansatz. Das von dir beobachtete Verhalten
ist normal. Free gibt das Objekt frei. Der Zeiger deiner Objektvariablen
zeigt danach aber immer noch auf den entsprechenden Speicher. Die Variable
aObject.free;
aObject := nil;
oder eben
FreeAndNil(aObject)
was genau das gleiche tut.
Hallo Torge,

dann liege ich ja doch richtig, danke!

Ciao
Stefan
Rudy Velthuis
2011-04-01 17:31:24 UTC
Permalink
Post by Torge Ismer
Post by Stefan Koschke
Ich könnte nun überall FreeAndNil(meineKlasse) verwenden, richtig?
Oder mach ich da generell was falsch?
FreeAndNil(...) ist der richtige Ansatz.
IMO, FreeAndNil ist nie der richtige Ansatz für irgendein Problem. Wenn
FreeAndNil notwendig ist, damit etwas funktioniert, sollte man sein
Design gründlich überdenken.
--
"The instinct of nearly all societies is to lock up anybody who
is truly free. First, society begins by trying to beat you up.
If this fails, they try to poison you. If this fails too, the
finish by loading honors on your head."
-- Jean Cocteau (1889-1963)
Peter
2011-04-02 08:59:00 UTC
Permalink
Post by Rudy Velthuis
Post by Torge Ismer
Post by Stefan Koschke
Ich könnte nun überall FreeAndNil(meineKlasse) verwenden, richtig?
Oder mach ich da generell was falsch?
FreeAndNil(...) ist der richtige Ansatz.
IMO, FreeAndNil ist nie der richtige Ansatz für irgendein Problem.
Wenn FreeAndNil notwendig ist, damit etwas funktioniert, sollte man
sein Design gründlich überdenken.
Oh bitte Rudy, NICHT SCHON WIEDER!
--
Peter Below
Rudy Velthuis
2011-04-02 14:41:40 UTC
Permalink
Post by Peter
Post by Rudy Velthuis
Post by Torge Ismer
Post by Stefan Koschke
Ich könnte nun überall FreeAndNil(meineKlasse) verwenden,
richtig? Oder mach ich da generell was falsch?
FreeAndNil(...) ist der richtige Ansatz.
IMO, FreeAndNil ist nie der richtige Ansatz für irgendein Problem.
Wenn FreeAndNil notwendig ist, damit etwas funktioniert, sollte man
sein Design gründlich überdenken.
Oh bitte Rudy, NICHT SCHON WIEDER!
Ich wollte das nur sagen. Ich werde der Diskussion aus dem Weg gehen.
<g>
--
"The most overlooked advantage of owning a computer is that if
they foul up there's no law against whacking them around a bit."
-- Eric Porterfield.
Arno Garrels
2011-04-01 07:47:18 UTC
Permalink
Post by Stefan Koschke
destructor TTabports.Destroy;
begin
if query.Active = true then
query.Close;
if query <> Nil then
query.Free;
inherited;
end;
Die Prüfung auf nil im Destruktor oben ist Blödsinn.
Falls das Feld query nil sein sollte, knallt es schon bei query.Active
Die Methode Free prüft selbst, ob die Objektreferenz (Self) nil ist.

destructor TTabports.Destroy;
begin
if (query <> Nil) and query.Active then
query.Close;
query.Free;
inherited;
end;

Tip: Benenne die Felder einer Klasse anständig, indem du ihnen
ein "F" voranstellst, also z.b. FQuery.
Post by Stefan Koschke
Diese Klasse wird im Programm irgendwomit .Create erzeugt und nach
Benutzungsende wieder mit .Free zerstört.
Unter bestimmten Umständen kann es aber vorkommen, daß das .Free
doppelt aufgerufen wird, daher hatte ich eine Abfrage vorgeschaltet
if meineKlasse <> Nil then
meineKlasse.free;
Leider funktioniert das nicht, weil die Klasse trotz .Free nicht Nil
ist und der nächste Zerstörungsversuch einen Laufzeitfehler erzeugt.
Ich könnte nun überall FreeAndNil(meineKlasse) verwenden, richtig?
Ja, das funktioniert. Wahrscheinlich macht es aber keinen Sinn das
Objekt ständig neu zu erzeugen und freizugeben, es wird doch im
Destruktor sicher abgeräumt.
Post by Stefan Koschke
Oder mach ich da generell was falsch?
Rudy würde das mit einem klaren Ja beantworten.
--
Arno Garrels
Stefan Koschke
2011-04-01 07:55:30 UTC
Permalink
Hallo Arno,
Post by Arno Garrels
Post by Stefan Koschke
destructor TTabports.Destroy;
begin
if query.Active = true then
query.Close;
if query<> Nil then
query.Free;
inherited;
end;
Die Prüfung auf nil im Destruktor oben ist Blödsinn.
Falls das Feld query nil sein sollte, knallt es schon bei query.Active
Die Methode Free prüft selbst, ob die Objektreferenz (Self) nil ist.
OK, Du hast vollkommen Recht!
Post by Arno Garrels
Tip: Benenne die Felder einer Klasse anständig, indem du ihnen
ein "F" voranstellst, also z.b. FQuery.
Stimmt, wird geändert...
Post by Arno Garrels
Post by Stefan Koschke
Ich könnte nun überall FreeAndNil(meineKlasse) verwenden, richtig?
Ja, das funktioniert. Wahrscheinlich macht es aber keinen Sinn das
Objekt ständig neu zu erzeugen und freizugeben, es wird doch im
Destruktor sicher abgeräumt.
Nach dem Erzeugen wird eine Tabelle der Datenbank eingestellt, benutzt,
die Klasse zerstört.
Irgendwann später wird die Klasse wieder neu erzeugt für eine andere
Tabelle usw...
Post by Arno Garrels
Post by Stefan Koschke
Oder mach ich da generell was falsch?
Rudy würde das mit einem klaren Ja beantworten.
;-)))

Ciao
Stefan
Arno Garrels
2011-04-01 09:00:06 UTC
Permalink
Post by Stefan Koschke
Post by Arno Garrels
Post by Stefan Koschke
Ich könnte nun überall FreeAndNil(meineKlasse) verwenden, richtig?
Ja, das funktioniert. Wahrscheinlich macht es aber keinen Sinn das
Objekt ständig neu zu erzeugen und freizugeben, es wird doch im
Destruktor sicher abgeräumt.
Nach dem Erzeugen wird eine Tabelle der Datenbank eingestellt, benutzt,
die Klasse zerstört.
Irgendwann später wird die Klasse wieder neu erzeugt für eine andere
Tabelle usw...
Dafür reicht ein Close und Open mit anderer SQL und ggf. anderen
Eigenschaften völlig aus. Das Query-Objekt wird ja ohnehin immer im
Konstruktor erzeugt, um eine "faule" Instanzierung geht es dir also
offenbar nicht.
--
Arno Garrels
Rudy Velthuis
2011-04-01 17:38:23 UTC
Permalink
Post by Stefan Koschke
Nach dem Erzeugen wird eine Tabelle der Datenbank eingestellt,
benutzt, die Klasse zerstört.
Vom wem wird das Objekt zerstört?

Kannst du das Objekt nicht einfach wiederverwenden (neue Daten
übergeben und danach reaktivieren), und letztendlich im Destruktor
(also nur einmal) zerstören?
--
"I admire the Pope. I have a lot of respect for anyone who can
tour without an album." -- Rita Rudner.
Andrej Kluge
2011-04-01 17:47:07 UTC
Permalink
Hi,
Post by Rudy Velthuis
Kannst du das Objekt nicht einfach wiederverwenden (neue Daten
übergeben und danach reaktivieren), und letztendlich im Destruktor
(also nur einmal) zerstören?
Interessant, daß du das aufbringst, sowas mache ich auch in diversen
Projekten.

Ciao
AK
Rudy Velthuis
2011-04-01 20:48:56 UTC
Permalink
Post by Andrej Kluge
Hi,
Post by Rudy Velthuis
Kannst du das Objekt nicht einfach wiederverwenden (neue Daten
übergeben und danach reaktivieren), und letztendlich im Destruktor
(also nur einmal) zerstören?
Interessant, daß du das aufbringst, sowas mache ich auch in diversen
Projekten.
Sehr gut! Damit hast du die Kontrolle üer die Lebenszeit deiner Objekte
und brauchst keine Krücken wie FreeAndNil.
--
The "abort()" function is now called "choice()."
-- from the "Politically Correct UNIX System VI Release notes"
Nicole Wagner
2011-04-01 10:59:17 UTC
Permalink
Post by Stefan Koschke
destructor TTabports.Destroy;
begin
if query.Active = true then
query.Close;
if query <> Nil then
query.Free;
inherited;
end;
if
was <> nil then was.free;
funktioniert bei mir eigentlich immer zufriedenstellend.


Aus der Huefte heraus wuerde ich 2 Dinge pruefen:

1)
"query."; Zeigt das sicher auf die richtige Instanz?

2)
"inherited;"
Ruft das vielleicht die ererbte Methode ein zweites mal auf?
Was passiert, wenn Du die Zeile weg laesst oder ebenfalls unter die <>
nil Bedingung schreibst?


Nicole
Joe Galinke
2011-04-01 13:07:20 UTC
Permalink
Hallo Nicole,
Post by Nicole Wagner
if
was <> nil then was.free;
funktioniert bei mir eigentlich immer zufriedenstellend.
Klar tut es das, beim ersten Mal. Da "was" aber danach noch immer nicht nil
ist, wird ein erneutes Durchlaufen des Codes nur per Zufall keinen Fehler
werfen.

Da Abfrage auf nil ist darüber hinaus überflüssig, da .Free sicher ist, das
prüft schon nil. Was hier lediglich fehlt ist "was := nil" im Anschluss
daran oder eben FreeAndNil(was).

Das wurde aber schon alles festgestellt, Problem gelöst.


Gruß, Joe
--
Rudy Velthuis
2011-04-01 17:34:59 UTC
Permalink
Post by Stefan Koschke
Unter bestimmten Umständen
kann es aber vorkommen, daß das .Free doppelt aufgerufen wird
Dann stimmt was nicht mit deinem Design. Das sollte nie vorkommen, und
kann auch sehr gut vermieden werden. Man sollte zu jeder Zeit wissen,
ob ein Objekt noch benutzt wird und wann es nicht mehr gültig ist.
--
"Do not seek to follow in the footsteps of the wise. Seek what
they sought."
-- Basho
Markus Springweiler
2011-04-06 08:49:16 UTC
Permalink
Hallo Rudy,
Post by Rudy Velthuis
Man sollte zu jeder Zeit wissen,
ob ein Objekt noch benutzt wird und wann es nicht mehr gültig ist.
Wäre das nicht so, hätte bestimmt längst jemand einen GarbageCollector
erfunden ;-)
--
/\/\arkus.
Soeren Muehlbauer
2011-04-06 09:49:23 UTC
Permalink
Hallo,
Post by Rudy Velthuis
Dann stimmt was nicht mit deinem Design. Das sollte nie vorkommen, und
kann auch sehr gut vermieden werden. Man sollte zu jeder Zeit wissen,
ob ein Objekt noch benutzt wird und wann es nicht mehr gültig ist.
Wenn dem so wäre, müsste das auch anders herum gelten. Wozu
initialisiert Delphi alle Instanzen? Das ist doch ganz und gar unnötig,
schließlich sollte man zu jeder Zeit wissen, in welchem Zustand die
Felder sind. Eine nicht mehr verwendete Instanzvariable explizit auf nil
zu setzen ist imho kein Indikator für schlechtes Design. Bei der
Bundeswehr sagt man nicht umsonst: "Im Zweifel schießt auch ein Besenstiel."

Sören
Heiko Nocon
2011-04-06 13:48:26 UTC
Permalink
Post by Soeren Muehlbauer
Post by Rudy Velthuis
Dann stimmt was nicht mit deinem Design. Das sollte nie vorkommen, und
kann auch sehr gut vermieden werden. Man sollte zu jeder Zeit wissen,
ob ein Objekt noch benutzt wird und wann es nicht mehr gültig ist.
Eine nicht mehr verwendete Instanzvariable explizit auf nil
zu setzen ist imho kein Indikator für schlechtes Design.
So ist es. Sobald Objekte dynamisch erzeugt werden und auch außerhalb
von Prozeduren verfügbar sein müssen, kommt man ja garnicht drum herum,
sich irgendwie zu merken, ob das Objekt nun schon existiert oder nicht
und falls es existiert, muß man sich ohnehin die Referenz merken. Es ist
also sogar guter Programmierstil, beide Informationen in einem Feld zu
vereinen, weil sie logisch zusammengehören und mutual exclusive sind.

Eben weil das so sinnvoll ist, gibt es Standardprozeduren wie FreeAndNil
und Assigned, die das unterstützen.

Zwar gibt es auch ein Standardverfahren, mit dem man theoretisch ohne
dieses Vorgehen auskommen könnte (nämlich das Owner-Konzept von
TComponent), aber dieses ist eben auf TComponent-Erben beschränkt. Und
es ist keinesfalls sinnvoll, jedes Objekt von TComponent abzuleiten,
dazu führt das viel zuviel Zeug ein, das für viele Objekte schlicht
überflüssig ist. Außerdem ist auch die Suche in den Komponentenlisten
ziemlich zeitaufwendig, insbesondere wenn jeder noch so kleine Scheiß in
solche gepackt wird.
--
Wer Komponenten ohne Quelltext oder richtig miese Komponenten
oder gute Komponenten mit Quelltext, ohne die Source zu verstehen, sich verschafft,
um sie in Form "eigener" Programme in Verkehr zu bringen,
der wird mit Gefängnis nicht unter 5 Jahren bestraft.
Rudy Velthuis
2011-04-06 21:18:57 UTC
Permalink
Post by Soeren Muehlbauer
Hallo,
Post by Rudy Velthuis
Dann stimmt was nicht mit deinem Design. Das sollte nie vorkommen,
und kann auch sehr gut vermieden werden. Man sollte zu jeder Zeit
wissen, ob ein Objekt noch benutzt wird und wann es nicht mehr
gültig ist.
Wenn dem so wäre, müsste das auch anders herum gelten. Wozu
initialisiert Delphi alle Instanzen?
Was hat Objekt-Initialisierung damit zu tun?

Übrigens, und das weißt du wahrscheinlich schon, das macht Delphi,
damit, wenn ein Constructor eine Exception schmeißt, im Destructor noch
nicht initialisierte Felder nil sind, und man getrost Free benutzen
kann. Auch macht es die Initialisierung von Typen wie String, dynamic
Array, Interface, usw einfacher.
--
"Cholesterol is your natural defence against excessive
circulation of blood, which can carry venoms, poisons and other
toxins around your body." -- Michael Warner, in bpot
Rudy Velthuis
2011-04-06 21:31:17 UTC
Permalink
Post by Soeren Muehlbauer
Eine nicht mehr verwendete Instanzvariable
explizit auf nil zu setzen ist imho kein Indikator für schlechtes
Design.
IMO schon. Du verlangst von anderen, die das Objekt, das du
bereitstellst, benutzen wollen, dass sie überprüfen ob es nil ist. Wenn
es bereitgestellt wird, sollte es einfach verfügbar sein.

Oder überprüfst du immer, wenn du z.B. ein Font-Objekt oder ein
TStrings-Objekt von einem VCL-Control benutzt, ob es nil ist? Wenn das
notwendig wäre, würde es mich nicht wundern, wenn gerade du dich
darüber lauthals beschweren würdest. <g>
--
"I don't want to achieve immortality through my work; I want to
achieve immortality through not dying."
-- Woody Allen (1935-)
Hans-Peter Diettrich
2011-04-07 00:57:53 UTC
Permalink
Post by Rudy Velthuis
Post by Soeren Muehlbauer
Eine nicht mehr verwendete Instanzvariable
explizit auf nil zu setzen ist imho kein Indikator für schlechtes
Design.
IMO schon. Du verlangst von anderen, die das Objekt, das du
bereitstellst, benutzen wollen, dass sie überprüfen ob es nil ist. Wenn
es bereitgestellt wird, sollte es einfach verfügbar sein.
Nicht alle Objekte müssen immer verfügbar sein. Nimm eine TStringList,
die erzeugt die interne Liste erst wenn etwas eingefügt wird. Ähnlich
für Caches, die erst angelegt werden, wenn sie einmal benutzt wurden.
Und entsprechend kann ein Cache gelöscht werden, wenn z.B. Speicher für
andere Zwecke benötigt wird, und dafür muß ja irgendwie festgestellt
werden, ob er jemals erzeugt wurde.
Post by Rudy Velthuis
Oder überprüfst du immer, wenn du z.B. ein Font-Objekt oder ein
TStrings-Objekt von einem VCL-Control benutzt, ob es nil ist?
Kommt drauf an, ob es als Parameter übergeben wurde, oder irgendwo
anders liegt.

TStrings ist ein Wrapper, der dem Benutzer die Aufgabe abnimmt, die
Existenz der eigentlichen Liste zu überprüfen. Ähnlich kann ein globales
Datenbank-Objekt kapseln, ob die DB bereits geöffnet wurde. Der aktuelle
Zustand kann dann ganz einfach daraus ermittelt werden, ob eine
(interne) Referenz Nil ist.
Post by Rudy Velthuis
Wenn das
notwendig wäre, würde es mich nicht wundern, wenn gerade du dich
darüber lauthals beschweren würdest. <g>
Ein Unterprogramm kann in einem unterschiedlichen Kontext aufgerufen
werden. Da kann es durchaus vorkommen, daß ein Objekt in einem Kontext
immer benötigt wird, und dann auch als existent vorausgesetzt werden
kann, während es in anderen Kontexten nie oder fast nie benutzt wird,
und dann ggf. erst bei Bedarf erzeugt wird, oder der Ablauf entsprechend
modifiziert wird.

Gerade in interaktiven (GUI) Programmen kann der Benutzer
unterschiedliche Aktionen in beliebiger Reihenfolge ausführen (Menü...).
Jede dieser Aktionen kann dann Objekte erzeugen (Datei öffnen...), die
in weiteren Aktionen verwendet werden können (Datei laden,
speichern...). Dann müssen alle Aktionen prüfen, ob die Objekte bereits
existieren, die zur Durchführung notwendig sind; falls noch was fehlt,
muß der Benutzer einen entsprechenden Hinweis erhalten, oder ein
Default-Objekt erzeugt werden.

Nach Deiner Philosophie dürfte es zur Laufzeit nie Objekt-Variablen
geben, die Nil sind. Du müßtest also für eine Datei, die der Benutzer
öffnen kann, ein TNoFile Objekt erzeugen, das erst beim Öffnen durch ein
TFileStream Objekt ersetzt wird, und beim Schließen der Datei ein neues
TNoFile Objekt erzeugen, damit die (globale) Referenz nie Nil ist.
Natürlich kann man das so machen, das schützt aber nicht vor
Folgefehlern, wenn in ein TNoFile geschrieben oder ein TNoFont für eine
Ausgabe verwendet werden soll. Man kommt also auch mit
Stellvertreter-Objekten nicht um Prüfungen herum, auch wenn die dann
ggf. anders aussehen.

DoDi
Rudy Velthuis
2011-04-07 17:27:42 UTC
Permalink
Post by Hans-Peter Diettrich
Post by Rudy Velthuis
Post by Soeren Muehlbauer
Eine nicht mehr verwendete Instanzvariable
explizit auf nil zu setzen ist imho kein Indikator für schlechtes
Design.
IMO schon. Du verlangst von anderen, die das Objekt, das du
bereitstellst, benutzen wollen, dass sie überprüfen ob es nil ist.
Wenn es bereitgestellt wird, sollte es einfach verfügbar sein.
Nicht alle Objekte müssen immer verfügbar sein.
Wenn du sie zur Verfügung an anderen stellst, dann schon, IMO.
--
"If toast always lands butter-side down, and cats always land on
their feet, what happens if you strap toast on the back of a cat
and drop it?" -- Steven Wright.
Arno Garrels
2011-04-07 17:43:40 UTC
Permalink
Post by Rudy Velthuis
Post by Hans-Peter Diettrich
Post by Rudy Velthuis
Post by Soeren Muehlbauer
Eine nicht mehr verwendete Instanzvariable
explizit auf nil zu setzen ist imho kein Indikator für schlechtes
Design.
IMO schon. Du verlangst von anderen, die das Objekt, das du
bereitstellst, benutzen wollen, dass sie überprüfen ob es nil ist.
Wenn es bereitgestellt wird, sollte es einfach verfügbar sein.
Nicht alle Objekte müssen immer verfügbar sein.
Wenn du sie zur Verfügung an anderen stellst, dann schon, IMO.
Dann könnte das Objekt auf Anfrage erzeugt werden. Guck dir z.B. mal
TEncoding an, ist das etwa schlechtes Design?
--
Arno Garrels
Soeren Muehlbauer
2011-04-07 08:17:48 UTC
Permalink
Hallo,
Post by Rudy Velthuis
IMO schon. Du verlangst von anderen, die das Objekt, das du
bereitstellst, benutzen wollen, dass sie überprüfen ob es nil ist. Wenn
es bereitgestellt wird, sollte es einfach verfügbar sein.
Kommt darauf an. Beispielsweise kann es Funktionen geben, welche Objekte
zurückliefern. An dieser Stelle ist es durchaus angebracht zu prüfen, ob
da was valides zurückkommt. Das Beispiel von Hans-Peter ist da ganz gut
geeignet. Du befragst einen Cache nach einem Objekt. Wenn es noch nicht
im Cache ist, wird dieser Dir ein nil liefern.
Post by Rudy Velthuis
Oder überprüfst du immer, wenn du z.B. ein Font-Objekt oder ein
TStrings-Objekt von einem VCL-Control benutzt, ob es nil ist?
[BlaBla gesnippt]

Das kommt auf den Vertrag an. Steht im Vertrag (Doku), dass das Objekt
in jedem Fall so ein Objekt bereitstellt, ist die Prüfung nicht
notwendig. Steht im Vertrag, dass nur dann ein TStrings-Objekt
zurückkommt, wenn auch Daten vorliegen, muss die Prüfung erfolgen.

Aber wie immer: Du kommst vom Thema ab.

Sören
Rudy Velthuis
2011-04-07 17:29:40 UTC
Permalink
Post by Soeren Muehlbauer
Hallo,
Post by Rudy Velthuis
IMO schon. Du verlangst von anderen, die das Objekt, das du
bereitstellst, benutzen wollen, dass sie überprüfen ob es nil ist.
Wenn es bereitgestellt wird, sollte es einfach verfügbar sein.
Kommt darauf an. Beispielsweise kann es Funktionen geben, welche
Objekte zurückliefern.
Sehr oft schlechtes Design, IMO.
--
"There's a fine line between being on the leading edge and being
in the lunatic fringe." -- Frank Armstrong
Soeren Muehlbauer
2011-04-07 17:59:35 UTC
Permalink
Hallo,
Post by Rudy Velthuis
Post by Soeren Muehlbauer
Kommt darauf an. Beispielsweise kann es Funktionen geben, welche
Objekte zurückliefern.
Sehr oft schlechtes Design, IMO.
Funktionen, welche Objekte zurückgeben stehen für schlechtes Design?
Aha, ist klar, Fabriken -> schlechtes Design, Caches -> schlechtes
Design. Was für ein Schwachsinn...

Sören
Rudy Velthuis
2011-04-07 22:39:44 UTC
Permalink
Post by Soeren Muehlbauer
Hallo,
Post by Rudy Velthuis
Post by Soeren Muehlbauer
Kommt darauf an. Beispielsweise kann es Funktionen geben, welche
Objekte zurückliefern.
Sehr oft schlechtes Design, IMO.
Funktionen, welche Objekte zurückgeben stehen für schlechtes Design?
Ja, oft (nicht immer). Die Funktionen generieren die Objekte, aber
überlassen den Benutzer die Aufgabe, sie wieder freizugeben. Das ist,
IMO, schlechtes Design.

(Wenn diese Funktionen sich dann auch noch in einem externen Modul
befinden, hast du den Salat).
--
"A bird in the hand makes it hard to blow your nose."
Soeren Muehlbauer
2011-04-08 07:26:05 UTC
Permalink
Hi,
Post by Rudy Velthuis
Ja, oft (nicht immer). Die Funktionen generieren die Objekte, aber
überlassen den Benutzer die Aufgabe, sie wieder freizugeben. Das ist,
IMO, schlechtes Design.
Das ist kein schlechtes Design. Es ist oft gar nicht anders möglich.
Gerade die schon beschriebenen Fabriken und Caches können das gar nicht
anders realisieren. Wieso muss ein Objekt, welches andere Objekte
erzeugt auch automatisch deren Eigentümer sein. Du hast ein eigenartiges
Verständnis von OOP.
Post by Rudy Velthuis
(Wenn diese Funktionen sich dann auch noch in einem externen Modul
befinden, hast du den Salat).
Wie ist das zu verstehen? Wie bekomme ich Objekte aus einem externen
Modul? Meinst Du Packages? Dort sehe ich kein Problem. Meinst Du Dlls?
Funktionen in Dlls sollten eh nie Objektinstanzen liefern. Es sei denn
es werden Schnittstellen zurückgegeben. Meinst Du mit Modul eine
Pascal-Datei?

Sören
Heiko Nocon
2011-04-08 10:33:49 UTC
Permalink
Post by Rudy Velthuis
Ja, oft (nicht immer). Die Funktionen generieren die Objekte, aber
überlassen den Benutzer die Aufgabe, sie wieder freizugeben. Das ist,
IMO, schlechtes Design.
Dann sind also Konstruktoren deiner Meinung nach schlechtes Design?

Denn, genau betrachtet, sind das auch nix anderes als Funktionen, die
Objekte generieren und dem Benutzer die Aufgabe überlassen, diese später
wieder freizugeben.

Wenn dich diese selbst diese Betrachtung immer noch nicht in die Lage
versetzt, die Fragwürdigkeit deiner Ansichten zu erkennen, dann bist du
eindeutig vollständig merkbefreit.
--
Wer Komponenten ohne Quelltext oder richtig miese Komponenten
oder gute Komponenten mit Quelltext, ohne die Source zu verstehen, sich verschafft,
um sie in Form "eigener" Programme in Verkehr zu bringen,
der wird mit Gefängnis nicht unter 5 Jahren bestraft.
Rudy Velthuis
2011-04-08 15:09:12 UTC
Permalink
Post by Heiko Nocon
Post by Rudy Velthuis
Ja, oft (nicht immer). Die Funktionen generieren die Objekte, aber
überlassen den Benutzer die Aufgabe, sie wieder freizugeben. Das
ist, IMO, schlechtes Design.
Dann sind also Konstruktoren deiner Meinung nach schlechtes Design?
Haha. Konstruktoren sind keine Funktionen die Objekte generieren, auch
wenn es syntaktisch so aussieht. Konstruktoren haben z.B. keine
Result-Variable und können auch nichts zurückgeben.
--
"There is more stupidity than hydrogen in the universe, and it
has a longer shelf life." -- Frank Zappa
Soeren Muehlbauer
2011-04-08 15:38:22 UTC
Permalink
Hallo,
Post by Rudy Velthuis
Post by Heiko Nocon
Dann sind also Konstruktoren deiner Meinung nach schlechtes Design?
Haha. Konstruktoren sind keine Funktionen die Objekte generieren, auch
wenn es syntaktisch so aussieht. Konstruktoren haben z.B. keine
Result-Variable und können auch nichts zurückgeben.
Doch haben sie. Zumindest aus Nutzersicht.

MyObject := TObject.Create;

Sieht sehr nach einem Funktionsaufruf aus...

Sören
Rudy Velthuis
2011-04-08 17:58:22 UTC
Permalink
Post by Soeren Muehlbauer
Hallo,
Post by Rudy Velthuis
Post by Heiko Nocon
Dann sind also Konstruktoren deiner Meinung nach schlechtes Design?
Haha. Konstruktoren sind keine Funktionen die Objekte generieren,
auch wenn es syntaktisch so aussieht. Konstruktoren haben z.B. keine
Result-Variable und können auch nichts zurückgeben.
Doch haben sie. Zumindest aus Nutzersicht.
MyObject := TObject.Create;
Das ist ein syntaktisches Konstrukt das aussieht wie ein
Funktionsaufruf. Ein Konstruktor ist aber keine Klassen-Funktion, weil
- Ein Konstruktor "Instanz"daten ändern kann (und das können
Klassenfunktionen nicht)
- Ein Konstruktor kein Result hat, und Exit(Rückgabewert) oder gar
Exit(nil) auch nicht funktioniert. Funktionen können entscheiden, was
sie zurückgeben.
- Es ist auch keine Instanz-Funktion, da man die nicht auf einer Klasse
aufrufen kann.

IOW, Konstruktoren sind keine Funktionen, weder Klassen-Funktionen noch
"Instanz"-Funktionen. Die Syntax sind nur so aus wie ein
Funktionsaufruf.
--
"Good teaching is one-fourth preparation and three-fourths
theater." -- Gail Godwin
Arno Garrels
2011-04-08 18:34:36 UTC
Permalink
Post by Rudy Velthuis
Post by Soeren Muehlbauer
Hallo,
Post by Rudy Velthuis
Post by Heiko Nocon
Dann sind also Konstruktoren deiner Meinung nach schlechtes
Design?
Haha. Konstruktoren sind keine Funktionen die Objekte generieren,
auch wenn es syntaktisch so aussieht. Konstruktoren haben z.B. keine
Result-Variable und können auch nichts zurückgeben.
Doch haben sie. Zumindest aus Nutzersicht.
MyObject := TObject.Create;
Das ist ein syntaktisches Konstrukt das aussieht wie ein
Funktionsaufruf.
Das wesentliche Merkmal einer Funktion ist, dass sie ein Ergebnis
liefert. Ein Konstruktor liefert einen Verweis auf das Objekt zurück,
entweder wird das Objekt zunächst erzeugt und initialisiert oder es
wird der Verweis auf die bestehende Instanz zurückgeliefert.

Du lenkst mal wieder vom Thema ab.
--
Arno Garrels
Rudy Velthuis
2011-04-08 21:37:28 UTC
Permalink
Post by Rudy Velthuis
Post by Soeren Muehlbauer
Hallo,
Post by Rudy Velthuis
Post by Heiko Nocon
Dann sind also Konstruktoren deiner Meinung nach schlechtes Design?
Haha. Konstruktoren sind keine Funktionen die Objekte generieren,
auch wenn es syntaktisch so aussieht. Konstruktoren haben z.B.
keine >>> Result-Variable und können auch nichts zurückgeben.
Post by Rudy Velthuis
Post by Soeren Muehlbauer
Doch haben sie. Zumindest aus Nutzersicht.
MyObject := TObject.Create;
Das ist ein syntaktisches Konstrukt das aussieht wie ein
Funktionsaufruf.
Das wesentliche Merkmal einer Funktion ist, dass sie ein Ergebnis
liefert.
Nicht nur. Sie muss auch entscheiden können, was das Ergebnis ist.
Dafür muss es mindestens etwas geben, womit sie ein Resultat
zurückgeben kann, e.g.

FunktionsName := Resultat;
// oder
Result := Resultat;
// oder
Exit(Resultat);

wobei Resultat auch z.B. nil sein können müsste.

Das gibt es nicht. Es hilft auch nicht, self auf nil zu setzen. Der
Konstruktor kann nichts zurückgeben. Das Konstrukt sieht einen
Funktionsaufrur nur ähnlich.

Übrigens, man kann Konstruktoren auch mit einer Instanz aufrufen
(MyInstance.Create) aber dann ist die Zuweisungsynatx erst recht nicht
zulässig.

Ein Konstruktor ist ein Konstruktor. Es ist keine Klassenfunktion und
keine Instanz-Methode, es ist keins von beiden.
--
"When you philosophically oppose an entire power elite, you
cannot help but sound like a conspiracy theorist. Social power
is by nature a conspiracy."
-- Tom N
Soeren Muehlbauer
2011-04-08 18:55:42 UTC
Permalink
Hallo,
Post by Rudy Velthuis
Das ist ein syntaktisches Konstrukt das aussieht wie ein
Funktionsaufruf. Ein Konstruktor ist aber keine Klassen-Funktion, weil
- Ein Konstruktor "Instanz"daten ändern kann (und das können
Klassenfunktionen nicht)
Klassenfunktionen, welche Instanzen erzeugen dürfen sehr wohl
Instanzdaten, über welche Art und Weise, ändern.
Post by Rudy Velthuis
- Ein Konstruktor kein Result hat, und Exit(Rückgabewert) oder gar
Exit(nil) auch nicht funktioniert. Funktionen können entscheiden, was
sie zurückgeben.
Das ist für mich als Anwender völlig egal. Es wirkt und funktioniert wie
eine Funktion.
Post by Rudy Velthuis
IOW, Konstruktoren sind keine Funktionen, weder Klassen-Funktionen noch
"Instanz"-Funktionen. Die Syntax sind nur so aus wie ein
Funktionsaufruf.
Nochmal: Aus Anwendersicht sind es welche. Das Wesen einer Funktion ist
es, dass sie ein Ergebnis zurückgibt. Konstruktoren tun genau das.

Sören
Rudy Velthuis
2011-04-08 21:38:45 UTC
Permalink
Post by Soeren Muehlbauer
Post by Rudy Velthuis
- Ein Konstruktor kein Result hat, und Exit(Rückgabewert) oder gar
Exit(nil) auch nicht funktioniert. Funktionen können entscheiden,
was sie zurückgeben.
Das ist für mich als Anwender völlig egal. Es wirkt und funktioniert
wie eine Funktion.
Ist dür dich als OO Programmier aber nicht egal. Oder benutzt du nur
Klassen und schreibst selbst keine?
--
"I'd stop eating chocolate, but I'm no quitter." -- Unknown
Heiko Nocon
2011-04-08 21:53:03 UTC
Permalink
Post by Soeren Muehlbauer
Nochmal: Aus Anwendersicht sind es welche.
Nicht nur aus Anwendersicht, sondern tatsächlich auch. Implizit werden
nämlich die Klassenmethoden TObject.NewInstance und TObject.InitInstance
aufgerufen. Die erzeugen und initialisieren die Instanz und geben als
Ergebnis tatsächlich die Referenz zurück.
--
Wer Komponenten ohne Quelltext oder richtig miese Komponenten
oder gute Komponenten mit Quelltext, ohne die Source zu verstehen, sich verschafft,
um sie in Form "eigener" Programme in Verkehr zu bringen,
der wird mit Gefängnis nicht unter 5 Jahren bestraft.
Rudy Velthuis
2011-04-08 22:12:05 UTC
Permalink
Post by Heiko Nocon
Post by Soeren Muehlbauer
Nochmal: Aus Anwendersicht sind es welche.
Nicht nur aus Anwendersicht, sondern tatsächlich auch. Implizit werden
nämlich die Klassenmethoden TObject.NewInstance und
TObject.InitInstance aufgerufen. Die erzeugen und initialisieren die
Instanz und geben als Ergebnis tatsächlich die Referenz zurück.
Aber der Konstruktor eben nicht.
--
"> > > Goodbye to all! Thanks for years of great fun and good
Post by Heiko Nocon
Post by Soeren Muehlbauer
business!
Suicide or MS C++?
Is there a difference?
Suicide hurts only once..."
-- Conversation on borland.public.delphi.non-technical
Hans-Peter Diettrich
2011-04-08 21:50:24 UTC
Permalink
Post by Rudy Velthuis
IOW, Konstruktoren sind keine Funktionen, weder Klassen-Funktionen noch
"Instanz"-Funktionen. Die Syntax sind nur so aus wie ein
Funktionsaufruf.
Oder umgekehrt: Konstruktoren sind Klassen-Funktionen, mit einer
unüblichen Syntax und Semantik. Z.B. haben sie Self als Rückgabewert
fest eingebaut...


Lieber Rudy, Du kannst eine Sprache so sehen und verwenden, wie Du das
willst. Jeder darf das. Du solltest aber nicht versuchen, andere
Programmierer von Deiner Sichtweise als der allein-seeligmachenden zu
überzeugen, ohne den Nachweis, daß Dein Modell auch alle in der Praxis
vorkommenden Fälle abdeckt. So ein Beweis (o.B.d.A.) ist kaum zu führen.

Wir haben zur Kenntnis genommen, daß Du (auch) über FreeAndNil eine
eigene Meinung hast, die von der Meinung anderer Leute abweicht. Laß es
damit gut sein, und sammle nicht schon wieder Troll-Punkte.

DoDi
Michael Fuchs
2011-04-10 20:25:09 UTC
Permalink
Post by Rudy Velthuis
- Ein Konstruktor "Instanz"daten ändern kann (und das können
Klassenfunktionen nicht)
Warum sollten sie das nicht können?


mfg
Micha
--
Meine Wanderungen durch Realität und Cyberspace

auf --> http://www.michael-fuchs.net <--
Rudy Velthuis
2011-04-10 20:45:25 UTC
Permalink
Post by Michael Fuchs
Post by Rudy Velthuis
- Ein Konstruktor "Instanz"daten ändern kann (und das können
Klassenfunktionen nicht)
Warum sollten sie das nicht können?
Das ist aber nun echt Basiswissen.

http://docwiki.embarcadero.com/RADStudio/XE/de/Methoden#Klassenmethoden

MAW, weil Klassenfunktionen zwar einen Self-Parameter haben, aber der
zeigt nicht auf eine Instanz. Self zeigt auf die Klasse.

In einem Konstruktor ist, logischerweise, Self eine Referenz auf die
Instanz, sonst wäre der Konstruktor ja ziemlich wertlos.
--
"Our children are not born to hate, they are raised to hate."
-- Thomas della Peruta
Michael Fuchs
2011-04-10 21:35:37 UTC
Permalink
Post by Rudy Velthuis
Post by Michael Fuchs
Post by Rudy Velthuis
- Ein Konstruktor "Instanz"daten ändern kann (und das können
Klassenfunktionen nicht)
Warum sollten sie das nicht können?
Das ist aber nun echt Basiswissen.
Seltsam.

Was macht dann das folgende:

type
TMyClass = class(TObject)
private
FBlafasel: String;
public
property Blafasel: String read FBlafasel write FBlafasel;
class function MyCreate: TMyClass;
end;

class function TMyClass.MyCreate: TMyClass;
begin
Result := TMyClass.Create;
Result.FBlafasel := 'Hallo';
end;

var
My: TMyClass;
begin
My := TMyClass.MyCreate;
WriteLn(My.Blafasel);
ReadLn;
end.


Irgendwie kommt da zum Schluss "Hallo" raus.
Ist zwar jetzt mit FPC gemacht, aber ich bezweifele dass das in Delphi
nicht geht.

mfg
Micha
--
Meine Wanderungen durch Realität und Cyberspace

auf --> http://www.michael-fuchs.net <--
Rudy Velthuis
2011-04-10 22:11:03 UTC
Permalink
Post by Michael Fuchs
class function TMyClass.MyCreate: TMyClass;
begin
Result := TMyClass.Create;
Result.FBlafasel := 'Hallo';
end;
Irgendwie kommt da zum Schluss "Hallo" raus.
<Seufz> Du verstehts mich wohl mit Absicht falsch. Ein Konstruktor
braucht die Konstruktion Result.FBlafasel nicht. Da kann man

FBlafasel := 'Hallo';

benutzen. Das meinte ich. Deshalb ist ein Konstruktor keine
Klassenfunktion.
--
"Deliver yesterday, code today, think tomorrow." -- unknown
Soeren Muehlbauer
2011-04-11 06:03:47 UTC
Permalink
Hi,
Post by Michael Fuchs
Post by Rudy Velthuis
Post by Michael Fuchs
Post by Rudy Velthuis
- Ein Konstruktor "Instanz"daten ändern kann (und das können
Klassenfunktionen nicht)
Warum sollten sie das nicht können?
Das ist aber nun echt Basiswissen.
Seltsam.
type
TMyClass = class(TObject)
private
FBlafasel: String;
public
property Blafasel: String read FBlafasel write FBlafasel;
class function MyCreate: TMyClass;
end;
class function TMyClass.MyCreate: TMyClass;
begin
Result := TMyClass.Create;
Result.FBlafasel := 'Hallo';
end;
Irgendwie kommt da zum Schluss "Hallo" raus.
Ist zwar jetzt mit FPC gemacht, aber ich bezweifele dass das in Delphi
nicht geht.
Genauso ist das. Bei einem Konstruktor hat man nur etwas mehr
syntaktischen Zucker dabei, nämlich das man das "Result." nicht explizit
hinschreiben muss. Eigentlich ist ein Konstruktor eine Instanzmethode.
Nur der äußerste Aufruf fungiert als Klassenmethode. Aber es bleibt
dabei. Klassenmethoden können sehr wohl Instanzdaten ändern.

Sören
Hans-Peter Diettrich
2011-04-11 07:20:47 UTC
Permalink
Post by Soeren Muehlbauer
Eigentlich ist ein Konstruktor eine Instanzmethode.
Nur der äußerste Aufruf fungiert als Klassenmethode.
Je nach dem - man kann einen Konstruktor jederzeit auch als Methode
einer Instanz aufrufen.
Post by Soeren Muehlbauer
Aber es bleibt
dabei. Klassenmethoden können sehr wohl Instanzdaten ändern.
Nicht mehr oder weniger als jede andere Prozedur oder Funktion, im
Rahmen der äußeren Sichtbarkeit der Elemente. Zur Abgrenzung ist so eine
Aussage völlig ungeeignet, um nicht zu sagen falsch.

DoDi
Soeren Muehlbauer
2011-04-11 06:54:00 UTC
Permalink
Hallo,
Post by Hans-Peter Diettrich
Aber es bleibt dabei. Klassenmethoden können sehr wohl Instanzdaten
ändern.
Nicht mehr oder weniger als jede andere Prozedur oder Funktion, im
Rahmen der äußeren Sichtbarkeit der Elemente. Zur Abgrenzung ist so eine
Aussage völlig ungeeignet, um nicht zu sagen falsch.
Das stimmt so nicht. Nehmen wir folgendes Beispiel:

type
TFoo = class
private
FPrivateField: Integer;
protected
FProtectedField: Integer;
public
constructor Create;
class procedure FooStatic(Instance: TFoo);
end;

implementation

{ TFoo }

constructor TFoo.Create;
begin
inherited;
FPrivateField := 0;
FProtectedField := 1;
end;

class procedure TFoo.FooStatic(Instance: TFoo);
begin
Instance.FPrivateField := 100;
Instance.FProtectedField := 100;
end;



type
TBar = class(TFoo)
public
constructor Create;
class procedure BarStatic(Instance: TBar);
end;


implementation

{ TBar }

class procedure TBar.BarStatic(Instance: TBar);
begin
Instance.FProtectedField := 300;
end;

constructor TBar.Create;
begin
inherited;
FProtectedField := 200;
end;

Die Klassenfunktion BarStatic hat Zugriff auf genau die gleichen Felder
wie der Konstruktor von TBar. Beide haben aber keinen Zugriff auf die
privaten Felder von TFoo. Eine Externe Funktion hat diesen Zugriff
nicht. Vielleicht meintest Du auch was ganz anderes:-)

Sören
Michael Fuchs
2011-04-11 07:50:26 UTC
Permalink
Post by Soeren Muehlbauer
Post by Hans-Peter Diettrich
Aber es bleibt dabei. Klassenmethoden können sehr wohl Instanzdaten
ändern.
Nicht mehr oder weniger als jede andere Prozedur oder Funktion, im
Rahmen der äußeren Sichtbarkeit der Elemente. Zur Abgrenzung ist so eine
Aussage völlig ungeeignet, um nicht zu sagen falsch.
[...]
Die Klassenfunktion BarStatic hat Zugriff auf genau die gleichen Felder
wie der Konstruktor von TBar. Beide haben aber keinen Zugriff auf die
privaten Felder von TFoo. Eine Externe Funktion hat diesen Zugriff
nicht. Vielleicht meintest Du auch was ganz anderes:-)
Im Rahmen ihrer Sichtbarkeit, das hat er doch korrekt eingeschränkt.
Befinden sich TBar und TFoo zum Beispiel in der gleichen Unit, würden
alle Zugriffe funktionieren.


mfg
Micha
Soeren Muehlbauer
2011-04-11 09:49:39 UTC
Permalink
Hallo,
Post by Michael Fuchs
Post by Soeren Muehlbauer
Post by Hans-Peter Diettrich
Aber es bleibt dabei. Klassenmethoden können sehr wohl Instanzdaten
ändern.
Nicht mehr oder weniger als jede andere Prozedur oder Funktion, im
Rahmen der äußeren Sichtbarkeit der Elemente. Zur Abgrenzung ist so eine
Aussage völlig ungeeignet, um nicht zu sagen falsch.
[...]
Die Klassenfunktion BarStatic hat Zugriff auf genau die gleichen Felder
wie der Konstruktor von TBar. Beide haben aber keinen Zugriff auf die
privaten Felder von TFoo. Eine Externe Funktion hat diesen Zugriff
nicht. Vielleicht meintest Du auch was ganz anderes:-)
Im Rahmen ihrer Sichtbarkeit, das hat er doch korrekt eingeschränkt.
Ist richtig, ich bezog mich mehr darauf, dass die Aussage falsch wäre.
Ist sie aber nicht. Gerade die Unitsichtbarkeit und damit eine indirekte
Freundbeziehung ist ein sehr eigenartiges Sprachfeature. Sicher wird es
sehr of verwendet. Es erschwert dabei die Pflege und Erweiterung von
Software sehr. Eine bessere Art und Weise diese Beziehungen zu
definieren ist der C++ Weg, indem Freundschaftsbeziehungen zwischen
Klassen definiert werden können.
Post by Michael Fuchs
Befinden sich TBar und TFoo zum Beispiel in der gleichen Unit, würden
alle Zugriffe funktionieren.
Nur so lange nicht jemand auf die Idee kommt das FPrivateField mittels
strict private zu veröffentlichen.

Sören
Hans-Peter Diettrich
2011-04-11 12:03:47 UTC
Permalink
Post by Soeren Muehlbauer
Post by Michael Fuchs
Post by Soeren Muehlbauer
Post by Hans-Peter Diettrich
Aber es bleibt dabei. Klassenmethoden können sehr wohl Instanzdaten
ändern.
Nicht mehr oder weniger als jede andere Prozedur oder Funktion, im
Rahmen der äußeren Sichtbarkeit der Elemente. Zur Abgrenzung ist so eine
Aussage völlig ungeeignet, um nicht zu sagen falsch.
[...]
Die Klassenfunktion BarStatic hat Zugriff auf genau die gleichen Felder
wie der Konstruktor von TBar. Beide haben aber keinen Zugriff auf die
privaten Felder von TFoo. Eine Externe Funktion hat diesen Zugriff
nicht. Vielleicht meintest Du auch was ganz anderes:-)
Im Rahmen ihrer Sichtbarkeit, das hat er doch korrekt eingeschränkt.
Ist richtig, ich bezog mich mehr darauf, dass die Aussage falsch wäre.
Stimmt, diesen Halbsatz ziehe ich zurück.
Post by Soeren Muehlbauer
Ist sie aber nicht. Gerade die Unitsichtbarkeit und damit eine indirekte
Freundbeziehung ist ein sehr eigenartiges Sprachfeature. Sicher wird es
sehr of verwendet. Es erschwert dabei die Pflege und Erweiterung von
Software sehr. Eine bessere Art und Weise diese Beziehungen zu
definieren ist der C++ Weg, indem Freundschaftsbeziehungen zwischen
Klassen definiert werden können.
Auch da bin ich anderer Meinung, basierend auf meiner Erfahrung mit C++.

Zumindest haben beide Modelle ihre Nachteile, wie Delphi durch
Nachschieben von "strict" quasi schon zugegeben hat. Eine aufgeweichte
Sichtbarkeit im Rahmen derselben Unit halte ich für eine völlig
überflüssige Aufweichung der Kapselung von Klassen.

Zusätzlich halte ich das Design der VCL-Klassen und Properties für
weitgehend unsinnig, wie die vielen Hacks zum Zugriff auf private
Elemente zeigen, die bei ordentlicher Sichtbarkeit (protected) garnicht
notwendig wären. Vielleicht sind das ja Auswirkungen von "class
completion", die nicht immer sinnvollen Code erzeugt.

DoDi
Soeren Muehlbauer
2011-04-11 11:55:40 UTC
Permalink
Hallo,
Post by Hans-Peter Diettrich
Erweiterung von Software sehr. Eine bessere Art und Weise diese
Beziehungen zu definieren ist der C++ Weg, indem
Freundschaftsbeziehungen zwischen Klassen definiert werden können.
Auch da bin ich anderer Meinung, basierend auf meiner Erfahrung mit C++.
Ich sagte ja nicht, dass es die Beste Variante ist. Zumindest habe ich
aber in C++ Einfluß darauf, da ich es als Entwickler festlege. In Delphi
ist das rein bei Enthaltensein in gleicher Unit der Fall. Es gibt
(leider) auch gar keine andere Möglichkeit.
Post by Hans-Peter Diettrich
Zumindest haben beide Modelle ihre Nachteile, wie Delphi durch
Nachschieben von "strict" quasi schon zugegeben hat. Eine aufgeweichte
Sichtbarkeit im Rahmen derselben Unit halte ich für eine völlig
überflüssige Aufweichung der Kapselung von Klassen.
Ack.
Post by Hans-Peter Diettrich
Zusätzlich halte ich das Design der VCL-Klassen und Properties für
weitgehend unsinnig, wie die vielen Hacks zum Zugriff auf private
Elemente zeigen, die bei ordentlicher Sichtbarkeit (protected) garnicht
notwendig wären.
Moment. Die Hacks gehen meist davon aus, dass man in einer Unit auf
protected Member zugreifen will. Also

type
TControlBreaker = class(TControl);

Um dann irgendwo TControlBreaker(Control).ProtectedField nutzen zu
können. Das geht aber nur durch die
In-Einer-Unit-Sind-Alle-Klassen-Freunde Regel von Delphi.

Sören
Hans-Peter Diettrich
2011-04-11 20:14:35 UTC
Permalink
Post by Soeren Muehlbauer
Ich sagte ja nicht, dass es die Beste Variante ist. Zumindest habe ich
aber in C++ Einfluß darauf, da ich es als Entwickler festlege.
Kein Unterschied zu Delphi, auch da legt der Entwickler fest, womit
andere Leute leben müssen.
Post by Soeren Muehlbauer
In Delphi
ist das rein bei Enthaltensein in gleicher Unit der Fall. Es gibt
(leider) auch gar keine andere Möglichkeit.
Inzwischen schon: class helper.

Fällt für mich in die gleiche Kategorie wie "extended RTTI", völlige
Aufhebung vordefinierter Sichtbarkeit. Wieso stattdessen nicht gleich
eine Compiler-Direktive, zur Aufhebung jeglicher
Sichtbarkeits-Beschränkung? Dann kann jeder Benutzer entscheiden, ob er
mit den vordefinierten Klassen leben kann, oder nach eigenem Gutdünken
drin rumfummeln möchte.

Da halte ich die Möglichkeit der Umgestaltung der LCL durch jeden
einzelnen Benutzer für besser. Eigene Erweiterungen dort einbauen, wo
sie Sinn machen (Basisklassen!), und im eigenen Code benutzen. Das
reicht völlig aus, um die Kapselung von Klassen an genau denjenigen
Stellen aufzubrechen, die als Design-Fehler erkannt wurden.

Daneben finde ich die Oberon-Exporte sehr nett, dort werden einfach alle
Bezeichner markiert, die in anderen Units/Modulen zugreifbar sein
sollen. Ob das so tatsächlich praxistauglich ist, kann ich aber nicht
sagen. Zumindest könnte dieses Verfahren die Unit-Abhängigkeiten
reduzieren, wenn ein Klassen-Interface nicht sämtliche intern benutzten
Typen exportieren muß, wie das bei OPL der Fall ist.

DoDi
Markus Springweiler
2011-04-11 14:17:57 UTC
Permalink
Hallo Soeren,
Post by Soeren Muehlbauer
Nur so lange nicht jemand auf die Idee kommt das FPrivateField mittels
strict private zu veröffentlichen.
Was für ein tolles Sprachkonstrukt ;-) (Semantisch natürlich korrekt.)
--
/\/\arkus.
Hans-Peter Diettrich
2011-04-11 20:16:20 UTC
Permalink
Post by Markus Springweiler
Hallo Soeren,
Post by Soeren Muehlbauer
Nur so lange nicht jemand auf die Idee kommt das FPrivateField mittels
strict private zu veröffentlichen.
Was für ein tolles Sprachkonstrukt ;-) (Semantisch natürlich korrekt.)
:-)

DoDi
Rudy Velthuis
2011-04-11 11:20:18 UTC
Permalink
Post by Soeren Muehlbauer
Genauso ist das.
Das macht einen Konstruktor noch keine Klassenfunktion. In Einem
Konstruktor ist Self die Instanz, nicht die Klasse.
--
"Woman was God's second mistake."
-- Friedrich Nietzsche (1844-1900)
Thomas G. Liesner
2011-04-08 14:51:16 UTC
Permalink
Post by Rudy Velthuis
Post by Soeren Muehlbauer
Funktionen, welche Objekte zurückgeben stehen für schlechtes Design?
Ja, oft (nicht immer). Die Funktionen generieren die Objekte, aber
überlassen den Benutzer die Aufgabe, sie wieder freizugeben. Das ist,
IMO, schlechtes Design.
Nur dann, wenn die Benennung bzw. die übliche Verwendung keinen deut-
lichen Hinweis auf die Erzeugung ohne automatische Freigabe gibt.

Im Endeffekt ist die Konstruktion:

begin
With CreateSowiesoliste(...) do try
...
finally
free
end;
end;

IMHO eleganter als

Var Temp: TWieheisstdieserListentypblossnochmal;
begin
Temp := TWieheisstdieserListentypblossnochmal.Create;
try
CreateSowiesoliste(..., temp);
With temp do begin
...
end;
finally
free
end;
end;
Post by Rudy Velthuis
(Wenn diese Funktionen sich dann auch noch in einem externen Modul
befinden, hast du den Salat).
-v

So long,
Thomas G. Liesner
Rudy Velthuis
2011-04-08 15:15:40 UTC
Permalink
Post by Arno Garrels
Post by Rudy Velthuis
Post by Soeren Muehlbauer
Funktionen, welche Objekte zurückgeben stehen für schlechtes
Design?
Post by Rudy Velthuis
Ja, oft (nicht immer). Die Funktionen generieren die Objekte, aber
überlassen den Benutzer die Aufgabe, sie wieder freizugeben. Das
ist, IMO, schlechtes Design.
Nur dann, wenn die Benennung bzw. die übliche Verwendung keinen deut-
lichen Hinweis auf die Erzeugung ohne automatische Freigabe gibt.
begin
With CreateSowiesoliste(...) do try
...
finally
free
end;
end;
IMHO eleganter als
Var Temp: TWieheisstdieserListentypblossnochmal;
begin
Temp := TWieheisstdieserListentypblossnochmal.Create;
try
CreateSowiesoliste(..., temp);
With temp do begin
...
end;
finally
free
end;
end;
Das kann schon sein (dass du das findest). Ich find "with" allerdings
genauso schlechter Stil. Dazu kommt, dass man eine Funktion, die ein
Objekt zurückgibt, nicht unbedingt nur so benutzt.

Wenn man von der Regel ausgeht, das der Eigentümer derjenige ist, der
ein Objekt generiert und auch irgendwann wieder löscht (es sei denn, er
überträgt diese Verantworting jemanden anders), dann ist das erste
Beispiel auch schlecher Stil, denn es überlässt den Benutzer diese
Verantwortung.
--
"Only a free and unrestrained press can effectively expose
deception in government."
-- Hugo Black, Supreme Court Justice
Soeren Muehlbauer
2011-04-08 19:07:38 UTC
Permalink
Hallo,
Post by Rudy Velthuis
Wenn man von der Regel ausgeht, das der Eigentümer derjenige ist, der
ein Objekt generiert und auch irgendwann wieder löscht (es sei denn, er
überträgt diese Verantworting jemanden anders), dann ist das erste
Beispiel auch schlecher Stil, denn es überlässt den Benutzer diese
Verantwortung.
Eine Funktion welche ein Create im Namen trägt sagt eindeutig was
abgeht. Du beauftragst eine Funktion ein Objekt zu erstellen. Damit wird
doch die Funktion niemals Eigentümer. Sie agiert stellvertretend für den
Aufrufer. Der Aufrufer ist der Eigentümer.

Sören
Rudy Velthuis
2011-04-08 21:42:09 UTC
Permalink
Post by Soeren Muehlbauer
Hallo,
Post by Rudy Velthuis
Wenn man von der Regel ausgeht, das der Eigentümer derjenige ist,
der ein Objekt generiert und auch irgendwann wieder löscht (es sei
denn, er überträgt diese Verantworting jemanden anders), dann ist
das erste Beispiel auch schlecher Stil, denn es überlässt den
Benutzer diese Verantwortung.
Eine Funktion welche ein Create im Namen trägt sagt eindeutig was
abgeht.
Oder eben nicht. Es wäre töricht, sich darauf zu verlassen.

Aber ich sage auch, aus Erfahrung mit Code con anderen, dass es OFT ein
schlechtes Desgn ist. Das muss nicht immer so sein, aber
erfahrungsgemäß ist es eben oft so.
--
"Many a man's reputation would not know his character if they
met on the street." -- Elbert Hubbard (1856-1915)
Soeren Muehlbauer
2011-04-07 08:23:29 UTC
Permalink
Hallo,
Post by Rudy Velthuis
Post by Soeren Muehlbauer
Eine nicht mehr verwendete Instanzvariable
explizit auf nil zu setzen ist imho kein Indikator für schlechtes
Design.
IMO schon.
IMHO nicht. Nur weil ich in einem Objekt ein Feld deklariere muss ich es
nicht von Anfang bis zum Ende benutzen. Von daher ist das explizite nil
setzen eines Zeigers kein Indikator für schlechtes Design. Ich sehe es
eher anders herum. Es ist schlechtes Design nicht mehr benötigte
Variablen oder Felder beim Ungültigwerden nicht auf nil zu setzen. Immer
unter der Bedingung, dass die Variable bzw. das Feld später auch noch
verfügbar ist. Rein Prozedur-/Methodenlokale Variablen sind damit außen vor.

Sören
Rudy Velthuis
2011-04-07 17:30:36 UTC
Permalink
Post by Soeren Muehlbauer
Hallo,
Post by Rudy Velthuis
Post by Soeren Muehlbauer
Eine nicht mehr verwendete Instanzvariable
explizit auf nil zu setzen ist imho kein Indikator für schlechtes
Design.
IMO schon.
IMHO nicht.
Pech. Meine Meinung war nicht "humble", also verlierst du. <g>
--
"The Six Phases of a Project:"
o Enthusiasm
o Disillusionment
o Panic
o Search for the Guilty
o Punishment of the Innocent
o Praise for non-participants
Soeren Muehlbauer
2011-04-07 17:58:23 UTC
Permalink
Hallo,
Post by Soeren Muehlbauer
IMHO nicht.
Pech. Meine Meinung war nicht "humble", also verlierst du.<g>
Typischer Rudy, wenn Du merkst, dass Du falsch liegst kommst Du mit
dümmlichen Bemerkungen mit noch dümmlicheren <g>'s hintendran.

Sören
Rudy Velthuis
2011-04-07 22:42:07 UTC
Permalink
Post by Soeren Muehlbauer
Hallo,
Post by Rudy Velthuis
Post by Soeren Muehlbauer
IMHO nicht.
Pech. Meine Meinung war nicht "humble", also verlierst du. <g>
Typischer Rudy, wenn Du merkst, dass Du falsch liegst kommst Du mit
dümmlichen Bemerkungen mit noch dümmlicheren <g>'s hintendran.
Oh je, es tut mir so leid. Hat es dich verletzt?

Aber mal ehrlich, was sollte man auf "IMHO nicht" sinvolles antworten?
--
Brook's Law: Adding manpower to a late software project makes it
later.
Soeren Muehlbauer
2011-04-08 07:21:54 UTC
Permalink
Hallo,
Post by Rudy Velthuis
Aber mal ehrlich, was sollte man auf "IMHO nicht" sinvolles antworten?
Steig einfach von Deinem (Dir viel zu hohen) Roß herunter. Dann fallen
Dir auch Antworten ein.

Sören
Rudy Velthuis
2011-04-08 15:16:56 UTC
Permalink
Post by Soeren Muehlbauer
Hallo,
Post by Rudy Velthuis
Aber mal ehrlich, was sollte man auf "IMHO nicht" sinvolles
antworten?
Steig einfach von Deinem (Dir viel zu hohen) Roß herunter. Dann
fallen Dir auch Antworten ein.
Wenn es mir viel zu hoch ist, wie bin ich denn drauf gekommen?
--
"So I went to the dentist. He said "Say Aaah." I said "Why?"
He said "My dog's died.'" -- Tommy Cooper
Soeren Muehlbauer
2011-04-08 15:36:51 UTC
Permalink
Hallo,
Post by Rudy Velthuis
Post by Soeren Muehlbauer
Steig einfach von Deinem (Dir viel zu hohen) Roß herunter. Dann
fallen Dir auch Antworten ein.
Wenn es mir viel zu hoch ist, wie bin ich denn drauf gekommen?
Es waren Deine zwischenmenschlichen Fähigkeiten gemeint. Deine
fachlichen Fähigkeiten kann man aus der Ferne schlecht Beurteilen. Dazu
müsste man Deine Patienten mal lachen sehen.

Sören
Rudy Velthuis
2011-04-08 18:06:17 UTC
Permalink
Post by Soeren Muehlbauer
Hallo,
Post by Rudy Velthuis
Post by Soeren Muehlbauer
Steig einfach von Deinem (Dir viel zu hohen) Roß herunter. Dann
fallen Dir auch Antworten ein.
Wenn es mir viel zu hoch ist, wie bin ich denn drauf gekommen?
Es waren Deine zwischenmenschlichen Fähigkeiten gemeint.
Und du bist wohl der Experte bezüglich solcher Fähigkeiten? LOL!

Nun ja, ich vermute mal, dass ich schnell ohne Patienten wäre, wenn es
da hapern würde.

Übrigens, anscheinend verfolgst du mich in verschiedenen Newsgruppen,
sogar jetzt in den Embarcadero-Foren, antwortest auf fast jede Aussage
die ich mache und versuchst sogar Diskussionen von hier darüber zu
schleppen. Das ist so armselig.
--
"Because I do it with one small ship, I am called a terrorist.
You do it with a whole fleet and are called an emperor."
-- A pirate, from St. Augustine's "City of God"
Soeren Muehlbauer
2011-04-08 18:51:01 UTC
Permalink
Hallo,
Post by Rudy Velthuis
Übrigens, anscheinend verfolgst du mich in verschiedenen Newsgruppen,
sogar jetzt in den Embarcadero-Foren,
Du leidest an Verfolgungswahn.
Post by Rudy Velthuis
antwortest auf fast jede Aussage
die ich mache und versuchst sogar Diskussionen von hier darüber zu
schleppen. Das ist so armselig.
Ich zeige nur auf, daß Dein Diskussionsstil auch in anderen Gruppen,
abseits von EMBT, ähnlich ist. Was daran armselig sein soll erschließt
sich mir nicht. Aber gut, Du kannst wahrscheinlich nicht anders.

BTW, Deine Patienten bringen Dir Dein Einkommen.

Sören
Rudy Velthuis
2011-04-08 21:25:28 UTC
Permalink
Post by Soeren Muehlbauer
Hallo,
Post by Rudy Velthuis
Übrigens, anscheinend verfolgst du mich in verschiedenen
Newsgruppen, sogar jetzt in den Embarcadero-Foren,
Du leidest an Verfolgungswahn.
Nein, im Gegenteil. Es wird immer klarer, dass du dich auf mich
eingeschossen hast. Das ist armselig.
--
"Would you like to liberate yourself from the lower realms of
life? Would you like to save the world from the degradation and
destruction it seems destined for? Then step away from shallow
mass movements and quietly go to work on your own
self-awareness."
-- Lao tzu
Soeren Muehlbauer
2011-04-08 21:31:25 UTC
Permalink
Hallo,
Post by Rudy Velthuis
Nein, im Gegenteil. Es wird immer klarer, dass du dich auf mich
eingeschossen hast. Das ist armselig.
Eher nicht, nur lesen hier auch andere mit und die würden am Ende
glauben, was Du schreibst. Weshalb Du überhaupt noch das TeamB Kürzel
führen darfst ist echt nicht zu fassen. Du schreibst eigentlich nur noch
non-tech, das ist armselig.

Sören
Rudy Velthuis
2011-04-08 21:44:37 UTC
Permalink
Post by Soeren Muehlbauer
Hallo,
Post by Rudy Velthuis
Nein, im Gegenteil. Es wird immer klarer, dass du dich auf mich
eingeschossen hast. Das ist armselig.
Eher nicht
Dann wundert es mich, warum du in so vielen Threads auf meine
Nachrichten antwortest (und nie im positiven Sinne), sogar jetzt in den
Embarcadero-Foren. Aber verneine es ruhig.
--
"Say what you will about the Ten Commandments, you must always
come back to the pleasant fact that there are only ten of them."
-- H. L. Mencken
Soeren Muehlbauer
2011-04-09 09:24:25 UTC
Permalink
Hallo,
Post by Rudy Velthuis
Post by Soeren Muehlbauer
Post by Rudy Velthuis
Nein, im Gegenteil. Es wird immer klarer, dass du dich auf mich
eingeschossen hast. Das ist armselig.
Eher nicht
Dann wundert es mich, warum du in so vielen Threads auf meine
Nachrichten antwortest (und nie im positiven Sinne), sogar jetzt in den
Embarcadero-Foren. Aber verneine es ruhig.
Weil Du meist derjenige bist, der besonders penetrant an seinen
verschrobenen Meinungen festhält.
Und das Du mich in den EMBT Gruppen als Stalker bezeichnest ist schon
ein starkes Stück.

Sören
Rudy Velthuis
2011-04-09 13:16:20 UTC
Permalink
Post by Soeren Muehlbauer
Post by Rudy Velthuis
Dann wundert es mich, warum du in so vielen Threads auf meine
Nachrichten antwortest (und nie im positiven Sinne), sogar jetzt in
den Embarcadero-Foren. Aber verneine es ruhig.
Weil Du meist derjenige bist, der besonders penetrant an seinen
verschrobenen Meinungen festhält.
Und DU bist dann berufen, das auszugleichen. <g>
Post by Soeren Muehlbauer
Und das Du mich in den EMBT Gruppen als Stalker bezeichnest ist schon
ein starkes Stück.
Dass du mich stalkst auch. <g>
--
"Real punks help little old ladies across the street because
it shocks more people than if they spit on the sidewalk."
-- Unknown
Arno Garrels
2011-04-09 17:52:01 UTC
Permalink
Post by Soeren Muehlbauer
Und das Du mich in den EMBT Gruppen als Stalker bezeichnest ist schon
ein starkes Stück.
+1

Die dort genauso penetrant verteidigte Meinungen, dass die Verwendung
von TComponent.Tag als Container für Pointern ein Hack sei, ist einfach
nur absurd, IMO.
--
Arno Garrels
Soeren Muehlbauer
2011-04-09 19:44:52 UTC
Permalink
Hi Arno,
Post by Arno Garrels
Post by Soeren Muehlbauer
Und das Du mich in den EMBT Gruppen als Stalker bezeichnest ist schon
ein starkes Stück.
+1
Die dort genauso penetrant verteidigte Meinungen, dass die Verwendung
von TComponent.Tag als Container für Pointern ein Hack sei, ist einfach
nur absurd, IMO.
Die Diskussion um die neue RTTI, Attribute und getter/setter mit anderer
Aufrufkonvention als pascal endete abrupt. Wahrscheinlich hat Rudy
eingesehen, dass er falsch lag. BTW, danke für Deinen QC:-).

@Rudy: Ich filtere Deine Antworten inzwischen, sodass Du Dir jegliche
Antwort sparen kannst, auch zuliebe der anderen hier.

Sören
Rudy Velthuis
2011-04-09 22:56:00 UTC
Permalink
Post by Soeren Muehlbauer
Hi Arno,
Post by Arno Garrels
Post by Soeren Muehlbauer
Und das Du mich in den EMBT Gruppen als Stalker bezeichnest ist
schon ein starkes Stück.
+1
Die dort genauso penetrant verteidigte Meinungen, dass die
Verwendung von TComponent.Tag als Container für Pointern ein Hack
sei, ist einfach nur absurd, IMO.
Die Diskussion um die neue RTTI, Attribute und getter/setter mit
anderer Aufrufkonvention als pascal endete abrupt.
Ja, weil ich manchmal auch noch was anderes mache, als vor einem
Computer zu sitzen. Aber jetzt habe ich Notdienst/Rufbereitschaft, also
kann ich nicht weit weg. <g>
--
"The religion of the future will be a cosmic religion, the
religion which based on experience, which refuses dogma."
-- Albert Einstein
Rudy Velthuis
2011-04-09 22:54:49 UTC
Permalink
Post by Arno Garrels
Die dort genauso penetrant verteidigte Meinungen, dass die Verwendung
von TComponent.Tag als Container für Pointern ein Hack sei, ist
einfach nur absurd, IMO.
Tja, dann schau doch mal was Allen darüber schreibt. Und "penetrant"
nur weil alle es anscheinend nicht gerne hören und verschiedene
Ausreden parat zu haben scheinen. Wenn man einen Zeiger in eine Longint
speichert, ist das ein Hack. In jeder anderen Situation würde man mir
wahrscheinlich beipflichten, aber anscheinend war Tag zu bequem, und da
soll es dann eben anders sein. Die Tatsache, dass viele sich Sorgen
machten, dass man das in Win64 nicht mehr machen könne, deutet doch
schon darauf hin, dass man wusste, dass es keine ganz saubere
Vorgehensweise war.

Also nun schleppst du Threads van da nach hier rüber. <g>
--
"A nation is a society united by a delusion about its ancestry
and by common hatred of its neighbors."
-- William R. Inge
Arno Garrels
2011-04-10 10:19:53 UTC
Permalink
Post by Rudy Velthuis
Post by Arno Garrels
Die dort genauso penetrant verteidigte Meinungen, dass die Verwendung
von TComponent.Tag als Container für Pointern ein Hack sei, ist
einfach nur absurd, IMO.
Tja, dann schau doch mal was Allen darüber schreibt. Und "penetrant"
nur weil alle es anscheinend nicht gerne hören und verschiedene
Ausreden parat zu haben scheinen. Wenn man einen Zeiger in eine
Longint speichert, ist das ein Hack.
Nicht solange es keinen sicher dokumentierten polymorphen
Integer-Typ gab (ab D2009) und man sogar annehmen konnte, dass Integer
und Cardinal diese Typen sind oder in Zukunft sein werden:

<Zitat Hilfe>
Es gibt zwei generische Integer-Typen: Integer und Cardinal. Diese
Typen sollten, wenn möglich, immer verwendet werden, da sie die
optimale Ausführungsgeschwindigkeit für die zugrundeliegende CPU
und das Betriebssystem gewährleisten.

Generische Integer-Typen für 32-Bit-Implementationen von Delphi
Typ Bereich Format
Integer -2147483648..2147483647 32 Bit, mit Vorzeichen
Cardinal 0..4294967295 32 Bit, ohne Vorzeichen
</Zitat>
Post by Rudy Velthuis
In jeder anderen Situation würde
man mir wahrscheinlich beipflichten, aber anscheinend war Tag zu
bequem, und da soll es dann eben anders sein.
Klar ist das bequem und wird sogar in der Hilfe beschrieben.
Post by Rudy Velthuis
Die Tatsache, dass
viele sich Sorgen machten, dass man das in Win64 nicht mehr machen
könne, deutet doch schon darauf hin, dass man wusste, dass es keine
ganz saubere Vorgehensweise war.
Etwa genauso unsauber wie Char und PChar bis D2009 in den Win-API
Headern benutzt wurden oder Pointer nach Integer Casts in der RTL.
--
Arno Garrels
Rudy Velthuis
2011-04-10 11:52:54 UTC
Permalink
Post by Rudy Velthuis
Post by Arno Garrels
Die dort genauso penetrant verteidigte Meinungen, dass die
Verwendung >> von TComponent.Tag als Container für Pointern ein Hack
sei, ist >> einfach nur absurd, IMO.
Post by Rudy Velthuis
Tja, dann schau doch mal was Allen darüber schreibt. Und "penetrant"
nur weil alle es anscheinend nicht gerne hören und verschiedene
Ausreden parat zu haben scheinen. Wenn man einen Zeiger in eine
Longint speichert, ist das ein Hack.
Nicht solange es keinen sicher dokumentierten polymorphen
Integer-Typ gab (ab D2009)
Einen Zeiger in eine numerische Variable oder Eigenschaft zu speichern
ist ein Hack.

Das hat man nur aus Bequemlichkeit gemacht, aber das machte es nicht
besser oder weniger zerbrechlich.

Und wie man in den Nachrichten von Allen Bauer und in der Hilfe von
z.B. Delphi 2 noch sehen kann, war das auch nicht, wofür Tag gedacht
war und es wurde auch nicht in der Hilfe empfohlen.

Die Hilfe wurde erst später geändert (Delphi 3 oder 4), weil man
erkannt hatte, dass viele Tag für Zeiger zweckentfremdet hatten und es
nun einmal funktionierte. Man hat zu dem Zeitpunkt wohl auch nicht
daran gedacht, dass viele Jahre später in Win64 Longint und Zeiger
nicht mehr die gleiche Größe haben würden, sonst hätte man
wahrscheinlich schon dagegen gewarnt.

Das erklärt die sog. Empfehlung. Da hat man sich nur an der Realität
orientiert.

Aber man kann nicht behaupten, dass das so geplant war. Das ist mit
Sicherheit nicht so. Es ist ein Hack. Jeder ist natürlich frei so einen
Hack zu benutzen, und ich sehe nicht ein, warum man es abstreiten
sollte. Ich benutze auch Hacks, wenn nichts anderes geht.
--
"Talk sense to a fool and he calls you foolish."
-- Euripides
Arno Garrels
2011-04-10 18:56:44 UTC
Permalink
Post by Rudy Velthuis
Post by Rudy Velthuis
Post by Arno Garrels
Die dort genauso penetrant verteidigte Meinungen, dass die
Verwendung >> von TComponent.Tag als Container für Pointern ein Hack
sei, ist >> einfach nur absurd, IMO.
Post by Rudy Velthuis
Tja, dann schau doch mal was Allen darüber schreibt. Und "penetrant"
nur weil alle es anscheinend nicht gerne hören und verschiedene
Ausreden parat zu haben scheinen. Wenn man einen Zeiger in eine
Longint speichert, ist das ein Hack.
Nicht solange es keinen sicher dokumentierten polymorphen
Integer-Typ gab (ab D2009)
Einen Zeiger in eine numerische Variable oder Eigenschaft zu speichern
ist ein Hack.
Warum? Solange diese Variable die Größe eines Zeigers hat ist das kein
Hack. Warum gibt es denn dann überhaupt die Integer-Typen, die immer
die Größe eines Pointers besitzen.
Post by Rudy Velthuis
Das hat man nur aus Bequemlichkeit gemacht, aber das machte es nicht
besser oder weniger zerbrechlich.
Und wie man in den Nachrichten von Allen Bauer und in der Hilfe von
z.B. Delphi 2 noch sehen kann, war das auch nicht, wofür Tag gedacht
war und es wurde auch nicht in der Hilfe empfohlen.
.Tag ist für den Benutzer einer Komponente gedacht, was der Benutzer
damit anstellt, bleibt allein ihm überlassen. Diese Eigenschaft hat
keinerlei Wirkung auf die Komponente.
Post by Rudy Velthuis
Die Hilfe wurde erst später geändert (Delphi 3 oder 4), weil man
erkannt hatte, dass viele Tag für Zeiger zweckentfremdet hatten
Diesen Bären kannst du hier niemandem aufbinden.
Auch kann man .Tag nicht zweckentfremden weil die Eigenschaft nicht
für einen bestimmten Zweck gedacht ist.
Post by Rudy Velthuis
und es
nun einmal funktionierte. Man hat zu dem Zeitpunkt wohl auch nicht
daran gedacht, dass viele Jahre später in Win64 Longint und Zeiger
nicht mehr die gleiche Größe haben würden, sonst hätte man
wahrscheinlich schon dagegen gewarnt.
Eben, damals haben viele nicht daran gedacht, ist ja auch völlig
normal, aber das macht es nicht plötzlich zum Hack. Und da die
Eigenschaft laut Allen Bauer NativeInt wird, is doch alles in
Butter. Wer dann wirklich die reine Rudy-Lehre bevorzugt, kann
sich dann ja in aller Ruhe eine Alternative ausdenken.
Post by Rudy Velthuis
Aber man kann nicht behaupten, dass das so geplant war. Das ist mit
Sicherheit nicht so. Es ist ein Hack. Jeder ist natürlich frei so
einen Hack zu benutzen, und ich sehe nicht ein, warum man es
abstreiten sollte. Ich benutze auch Hacks, wenn nichts anderes geht.
Ich auch, aber das sind dann wenigstens echte Hacks, native Windows
API und andere schlimmen, undokumentierten Sachen.
--
Arno Garrels
Soeren Muehlbauer
2011-04-10 19:43:24 UTC
Permalink
Hallo,
Post by Arno Garrels
Post by Rudy Velthuis
Einen Zeiger in eine numerische Variable oder Eigenschaft zu speichern
ist ein Hack.
Warum? Solange diese Variable die Größe eines Zeigers hat ist das kein
Hack. Warum gibt es denn dann überhaupt die Integer-Typen, die immer
die Größe eines Pointers besitzen.
Genau, viele Windows API Funktionen liefern Handles oder ähnliches
zurück. Meist sind das eben keine Pointer. Intern werden es sehr wohl
welche sein. Davon abzuleiten, Windows würde auf Hacks aufgebaut ist
doch Unsinn.
Post by Arno Garrels
Post by Rudy Velthuis
Die Hilfe wurde erst später geändert (Delphi 3 oder 4), weil man
erkannt hatte, dass viele Tag für Zeiger zweckentfremdet hatten
Diesen Bären kannst du hier niemandem aufbinden.
Auch kann man .Tag nicht zweckentfremden weil die Eigenschaft nicht
für einen bestimmten Zweck gedacht ist.
;-). Made my day.
Post by Arno Garrels
Post by Rudy Velthuis
Aber man kann nicht behaupten, dass das so geplant war. Das ist mit
Sicherheit nicht so. Es ist ein Hack. Jeder ist natürlich frei so
einen Hack zu benutzen, und ich sehe nicht ein, warum man es
abstreiten sollte. Ich benutze auch Hacks, wenn nichts anderes geht.
Ich auch, aber das sind dann wenigstens echte Hacks, native Windows
API und andere schlimmen, undokumentierten Sachen.
Mein Interesse ist geweckt. Gern auch per pm.

Sören
Rudy Velthuis
2011-04-10 20:38:22 UTC
Permalink
Post by Soeren Muehlbauer
Genau, viele Windows API Funktionen liefern Handles oder ähnliches
zurück. Meist sind das eben keine Pointer.
Sie sind allerdings in Original (C Header) so deklariert.
--
"If you give a man a fish, he will eat for today. If you teach
him to fish, he'll understand why some people think golf is
exciting." -- P.G. Wodehouse
Arno Garrels
2011-04-11 06:01:45 UTC
Permalink
Post by Soeren Muehlbauer
Post by Arno Garrels
Ich auch, aber das sind dann wenigstens echte Hacks, native Windows
API und andere schlimmen, undokumentierten Sachen.
Mein Interesse ist geweckt. Gern auch per pm.
Nicht der Rede wert. Es ist schon länger her, dass ich mich mit
Processes and Threads und Kernel-Mode-API-Hooking beschäftigt habe,
das war damals mehr ein Hobby gewesen.
--
Arno Garrels
Soeren Muehlbauer
2011-04-11 06:07:45 UTC
Permalink
Hallo,
Post by Arno Garrels
Post by Soeren Muehlbauer
Mein Interesse ist geweckt. Gern auch per pm.
Nicht der Rede wert. Es ist schon länger her, dass ich mich mit
Processes and Threads und Kernel-Mode-API-Hooking beschäftigt habe,
das war damals mehr ein Hobby gewesen.
Ok, mir ging es eigentlich auch nur um die Begriffe, welche Du jetzt
erwähnt hast. Wir loggen hier bspw. verschiedene API Funktionen, um
Zustandsinformationen der Anwendung zu ermitteln. Wir fangen unter
anderen CreateFile/CloseHandle, CreateFont, CreateBrush usw. ab damit
wir neben den in FastMM eingebauten Memory-Leak-Detector auch einen
Kernel-Objekt-Leak-Detector benutzen können. AqTime kann das auch, aber
wir bekommen das eben bei jedem Programmende frisch serviert und müssen
nicht erst eine andere Anwendung bemühen. Daher mein Interesse.

Sören
Rudy Velthuis
2011-04-10 20:37:14 UTC
Permalink
Post by Arno Garrels
Post by Rudy Velthuis
Einen Zeiger in eine numerische Variable oder Eigenschaft zu
speichern ist ein Hack.
Warum?
Weil man Zeiger in Zeigervariablen speichert. Warum glaubst du wohl,
dass in Pascal und Delphi soviel Wert auf Typsicherheit gelegt wird?
Und nun ja, Longint ist nicht groß genug für einen 64 bit Zeiger. Nur
wegen dieses Hacks muss das jetzt in NativeInt verändert werden, damit
die, die den Hack benutzen, nicht in Schwulitäten kommen.
--
"I know that there are people in this world who do not love
their fellow human beings, and I hate people like that."
-- Tom Lehrer
Arno Garrels
2011-04-11 17:54:26 UTC
Permalink
Post by Rudy Velthuis
Post by Arno Garrels
Post by Rudy Velthuis
Einen Zeiger in eine numerische Variable oder Eigenschaft zu
speichern ist ein Hack.
Warum?
Weil man Zeiger in Zeigervariablen speichert. Warum glaubst du wohl,
dass in Pascal und Delphi soviel Wert auf Typsicherheit gelegt wird?
.Tag ist sozusagen das eingebaute Schweizer Taschenmesser des
Komponentenbenutzers, so lese ich die OH und so wird die Eigenschaft
auch ursprünglich gedacht gewesen sein.
Post by Rudy Velthuis
Und nun ja, Longint ist nicht groß genug für einen 64 bit Zeiger. Nur
wegen dieses Hacks muss das jetzt in NativeInt verändert werden, damit
die, die den Hack benutzen, nicht in Schwulitäten kommen.
Dass .Tag ein Ordinaltyp ist, hat den einfachen Grund, dass der am
universellsten einsetzbar ist und auch gut als published property taugt.
Ein Longint und demnächst ein NativeInt erfüllt genau diesen Zweck am
Besten. Wenn ich weiß was ich tue und was ich da reinschreibe ist das
kein Hack.
--
Arno Garrels
Rudy Velthuis
2011-04-11 21:00:10 UTC
Permalink
Post by Arno Garrels
Post by Rudy Velthuis
Weil man Zeiger in Zeigervariablen speichert. Warum glaubst du wohl,
dass in Pascal und Delphi soviel Wert auf Typsicherheit gelegt wird?
.Tag ist sozusagen das eingebaute Schweizer Taschenmesser des
Komponentenbenutzers
Das ist es vielleicht geworden, weil immer mehr Cleverle den oder einen
ähnlichen Hack benutzt haben, aus Bequemlichkeit oder weil sie zu doof
waren, das richtig zu machen, aber ursprünglich war das eben nicht so.

Es war gedacht als numerischer Wert, der nur dazu dienen sollte, dass
Komponenten von einander unterscheiden werden konnten. Das sagen die
Original-Hilfedateien (jemand hat D2 gequotet in den Embt-Foren), und
das sagt Allen Bauer. Etst später, als immer mehr Leute daraus ein
"Schweizer Taschenmesser" gemacht hatten, wurde die Hilfe umgeschrieben.
--
Johnson-Laird's Law: Toothache tends to start on Saturday night.
Soeren Muehlbauer
2011-04-10 06:17:37 UTC
Permalink
Hi,
Post by Arno Garrels
Die dort genauso penetrant verteidigte Meinungen, dass die Verwendung
von TComponent.Tag als Container für Pointern ein Hack sei, ist einfach
nur absurd, IMO.
Eine Frage ist, ob es auch anders herum ein "Hack" ist. Also wenn man
einen Integer in einen Pointer steckt. In früheren Zeiten, als es noch
keine Generic gab, habe ich häufiger gesehen, dass Entwickler eine Liste
mit Integer brauchten und eine TList dazu genutzt haben.
Lustig ist, dass in der (deutschen) Wikipedia für Hack zwei
unterschiedliche Bedeutungen hinterlegt sind. Vielleicht meinte Rudy
einfach die erste Erklärung.

PS: Mich würde nicht wundern, wenn der Rudy Dich jetzt als
Threadverschieber beschultigt:-).

Sören
Arno Garrels
2011-04-10 10:19:59 UTC
Permalink
Post by Soeren Muehlbauer
Hi,
Post by Arno Garrels
Die dort genauso penetrant verteidigte Meinungen, dass die Verwendung
von TComponent.Tag als Container für Pointern ein Hack sei, ist
einfach nur absurd, IMO.
Eine Frage ist, ob es auch anders herum ein "Hack" ist. Also wenn man
einen Integer in einen Pointer steckt. In früheren Zeiten, als es noch
keine Generic gab, habe ich häufiger gesehen, dass Entwickler eine
Liste mit Integer brauchten und eine TList dazu genutzt haben.
Möglicherweise, denn dafür ist ein Typecast nötig. Das sollte aber
mit 64-Bit Pointern genauso funktionieren, wird dann nur etwas mehr
Speicher benötigt.
Post by Soeren Muehlbauer
PS: Mich würde nicht wundern, wenn der Rudy Dich jetzt als
Threadverschieber beschultigt:-).
Logisch.
--
Arno Garrels
Vinzent Hoefler
2011-04-10 18:36:37 UTC
Permalink
Post by Soeren Muehlbauer
Eine Frage ist, ob es auch anders herum ein "Hack" ist. Also wenn man
einen Integer in einen Pointer steckt.
Die kanonische Antwort auf diese nicht gestellte Frage lautete: Ja.


Vinzent.
--
A C program is like a fast dance on a newly waxed dance floor by people carrying
razors.
-- Waldi Ravens
Rudy Velthuis
2011-04-08 21:46:14 UTC
Permalink
Post by Soeren Muehlbauer
das ist armselig.
Du bist ja so was von originell. <g>
--
"Men who believe absurdities will commit atrocities."
-- Voltaire
Hans-Peter Diettrich
2011-04-08 21:59:43 UTC
Permalink
Post by Rudy Velthuis
Übrigens, anscheinend verfolgst du mich in verschiedenen Newsgruppen,
sogar jetzt in den Embarcadero-Foren, antwortest auf fast jede Aussage
die ich mache und versuchst sogar Diskussionen von hier darüber zu
schleppen. Das ist so armselig.
Spielen wir jetzt wieder das "Rudy" Spiel?

1. Der Rudy muß auf alle Kommentare zu seinen Kommentaren antworten.

2. Wenn der Rudy nicht antwortet, dann wird derjenige der Rudy, der den
unbeantworteten Kommentar geschrieben hat.

3. Sieger ist derjenige, der es schafft, daß niemand mehr auf seine
Kommentare antwortet.

DoDi
Soeren Muehlbauer
2011-04-09 14:01:49 UTC
Permalink
Hi,
Post by Hans-Peter Diettrich
3. Sieger ist derjenige, der es schafft, daß niemand mehr auf seine
Kommentare antwortet.
Mist, dann verliere ich :-(. Vielleicht kann man ja daraus ein "Rudy's
Law" ableiten :-)?

Sören
Loading...