Autor Beitrag
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Mo 28.02.05 12:29 
Aktivier mal in den Projektoptionen unter Compiler "Use Debug DCUs" oder eben das deutsche Äquivalent, erstell das Projekt neu, dann mach nen Breakpoint und geh alles mit F7 durch...

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
IngoD7
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 629


D7
BeitragVerfasst: Mo 28.02.05 12:45 
Motzi hat folgendes geschrieben:
Aktivier mal in den Projektoptionen unter Compiler "Use Debug DCUs" oder eben das deutsche Äquivalent, erstell das Projekt neu, dann mach nen Breakpoint und geh alles mit F7 durch...

Habe ich gemacht. Er springt auch bei mir in den ASM-Teil, kommt aber nicht weit:
ausblenden Quelltext
1:
2:
        TEST    EAX,EAX
        JE      @@exit
Den Sprung führt er schon aus und macht dann in anderen (ASM-)Routinen weiter. Eine Exception wirft er später trotzdem. Mein Wissen reicht allerdings nicht aus, um nun zu verfolgen, wo und weshalb genau.

Bleibt festzustellen, dass as sich durch die Delphiversionen hindurch unterschiedlich verhält. :( Oder aber andere Einstellungen in den Optionen bewirken das ...?
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Mo 28.02.05 12:58 
Genau dieser ASM Code den du gepostet hast ist dafür verantwortlich, dass der erste Parameter auf nil getestet wird und in diesem Fall die Funktion vorzeitig verlassen wird (Result ist dann auch nil). Eine Mögliche Ursache für deine Exception ist, dass das Ergebnis von AsClass eben nil ist und die Methode des Objekts dann eben fehlschlägt und eine Exception auslöst (was für eine Exception bekommst du denn)? Ich bin nämlich davon ausgegangen, dass du eine "Invalid typecast"-Exception bekommst, diese wird aber nur von der PurePascal-Version ausgelöst...

Ich hab das ganze mit folgendem Code getestet:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
procedure TForm1.Button2Click(Sender: TObject);
begin
  Sender := nil;
  (Sender as TButton).Caption := 'xxx';
end;

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mo 28.02.05 13:02 
Da das in meinen Augen hier noch keiner komplett richtig erklärt hat, möchte ich das mal tun:

TButton(X) castet X unabhängg von seinem Typ (Also auch Integer und ähnliches) O=HNE Typprüfung.

Bei as TButton wird eine Typprüfung zur Laufzeit durchgeführt, was zwar sicherer ist, aber auch um einiges Langsamer.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
IngoD7
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 629


D7
BeitragVerfasst: Mo 28.02.05 13:28 
Motzi hat folgendes geschrieben:
Eine Mögliche Ursache für deine Exception ist, dass das Ergebnis von AsClass eben nil ist und die Methode des Objekts dann eben fehlschlägt und eine Exception auslöst (was für eine Exception bekommst du denn)?
Ich bekomme eine EAccessViolation. Das tut aber nichts zur Sache, da ich grundsätzlich von Exceptions gesprochen hatte, die "irgendwie" dadurch ausgelöst werden, dass das Objekt nil ist. Eine is-Abfrage verhindert deren Auftreten. Eine as-Nutzung tut das nicht.
Dass es hier ursächlich eine Methode ist, die fehlschlägt (mit besagter EAV), während das Setzen einer Eigenschaft zu keinem Fehler führt, ist mir dabei eigentlich egal. :)

Motzi hat folgendes geschrieben:
Ich hab das ganze mit folgendem Code getestet:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
procedure TForm1.Button2Click(Sender: TObject);
begin
  Sender := nil;
  (Sender as TButton).Caption := 'xxx';
end;

Moooooment! Jetzt muss ich aber schimpfen mit dir! :evil: :wink:
Explizit gefragt hatte ich dich:
IngoD7 hat folgendes geschrieben:
Folgendes führt bei dir also nicht zur Exception???
ausblenden Delphi-Quelltext
1:
2:
3:
4:
var Komp : TComponent;
...
Komp := nil;
(Komp as TEdit).Clear;


Deine Antwort war:
Motzi hat folgendes geschrieben:
Genau so schauts aus..! ;)

Das war dann wohl leicht gelogen, oder? 8)

Abgesehen davon: Ein(Sender as TButton).Caption := 'xxx';löst bei mir ebensowenig einen Fehler aus wieTButton(Sender).Caption := 'xxx';.
Beides geht glatt. Dafür braucht man kein as.
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Mo 28.02.05 13:58 
So.. dann lösen wir hier mal ein Missverständnis auf.. ;)
Ich bin davon ausgegangen, dass du eine "Invalid typecast"-Exception meinst, welche in der PurePascal-Version ausgelöst wird, wenn das Objekt entweder nil ist oder kein Nachfahre der angegebenen Klasse. In der ASM-Version wird diese Exception nur ausgelöst, wenn das Objekt kein Nachfahre der Klasse ist, aber _nicht_ wenn das Objekt nil ist.

Ich bin also wie gesagt von einer Exception ausgegangen, die innerhalb des as-Castings ausgelöst wird. Deine EAV ist ja eher ein Nachfolgefehler... da ich diese Möglichkeit nicht in Betracht gezogen habe, hab ich es auch nicht mit deinem Code so genau genommen und statt deinem Code eben einen anderen Code genommen, bei dem auch ein nil-Objekt per as gecastet wird. Dass dabei bei der Zuweisung der Caption kein EAV auftritt war wohl ein "Glücksgriff".. ;) Du mögest mir bitte verzeihen..! :flehan: ;)

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
IngoD7
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 629


D7
BeitragVerfasst: Mo 28.02.05 14:25 
Und somit hier mal einen kleinen Zwischenstand:

    X as Tyz prüft Typenkompatibilität und wirft ggf. eine Exception (EInvalidCast), wenn die Typen nicht passen.

    Tyz(X) prüft gar nichts, sondern wandelt, was zu wandeln ist und fällt ggf. unkontrolliert auf die Nase, wenn die Typen nicht zueinander passen.

    Auch X as Tyz kann keine Folgefehler verhindern, falls X gleich nil sein sollte.

    Ein if X is Tyz then dagegen erschlägt alle diese Probleme, weil es sowohl unpassende Typen als auch ein nil als X nicht durchlässt.

    Hinter if X is Tyz then kann man sich X as Tyz sparen und gleich Tyz(X) benutzen.


Zur Verdeutlichung:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
//Code A:
var xyObject : TEdit;
...
  (xyObject as TButton).hide;  //<--- EInvalidCast !

//Code B:
var xyObject : TEdit;
...
  TButton(xyObject).hide;  //Macht kalt lächelnd das Edit unsichtbar.
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Mo 28.02.05 16:26 
Sehr schön zusammengefasst! *thumbsup* Damit sollten hoffentlich alle Klarheiten beseitigt sein.. :mrgreen: ;)

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
IngoD7
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 629


D7
BeitragVerfasst: Mo 28.02.05 17:30 
Motzi hat folgendes geschrieben:
Sehr schön zusammengefasst! *thumbsup*

Danke, danke. *verbeug nach links, verbeug nach rechts*
:mrgreen:
FD-83 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 49



BeitragVerfasst: Mi 02.03.05 03:21 
Wunderschön!

Ich danke euch ;)

Gruß
Frederik
wdbee
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 628
Erhaltene Danke: 1



BeitragVerfasst: Mi 02.03.05 19:15 
Beide Formen der Typumwandlung (Cast) haben ihre Daseinsberechtigung! :!:

Der wesentliche Unterschied zwischen

ausblenden Delphi-Quelltext
1:
2:
  DerSender := TMeinTyp(Sender);
  ...


und

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
  if Sender <> nil then
  begin
    DerSender := Sender As TMeinTyp;
    ...
  end;


ist der, dass in der ersten Form der Compiler schon beim Übersetzen unterstellt, dass es sich bei Sender um ein Objekt der Klasse TMeinTyp handelt. Er wendet also "blind" alles an, was er über die Klasse TMeinTyp weiß. Hier können ganz gemeine Fehler entstehen, weil die Zugriffe auf Daten formal zulässig sind, also keine Exception auslösen, wenn das "falsche" Objekt nicht kleiner ist als das angenommene "richtige" Objekt (bzw. Typ). Die Probleme treten dann an ganz anderen Stellen zu Tage und sind schwer auf die tatsächliche Ursache zurückzuführen, denn selbst der Debugger geht ja vom falschen Typ aus und zeigt alle so an, wir ihr es an dieser Stelle erwartet.

In der zweiten Form wird erst zur Laufzeit geprüft, ob es sich tatsächlich um ein Objekt der angegebenen Klasse handelt (was nur geht, wenn der Zeiger Sender gültig ist!). Die zweite Form ist damit sicher aber langsam.

Wann also darf ich die unsichere schnelle Variante einsezten? :?:

Wenn ihr hier zwischen öffentlichen (public) und nichtöffentlichen (protected, private) Prozeduren oder Funktionen sauber unterscheidet, dann gilt:

In öffentlichen Funktionen müsst ihr mit allem rechnen (Ungültige Zeiger, falsche Typen) und müsst deshalb immer die langsamere aber sichere Variante wählen.

Funktionen, die nur aus der Klasse selbst heraus aufgerufen werden können, dürfen unterstellen, das der Aufrufer weiß was ihr erwartet! Hier könnt ihr deshalb entscheiden, ob ihr die schnellere Variante wählen könnt. Wird eine Funktion also z.B. immer nur von ein und der selben Funktion aufgerufen und hat der Parameter (hier Sender) deshalb immer den gleichen Typ, dann merkt ihr einen eventuellen Denkfehler in eurem Programm beim Testen.

Das Prinzip ist also, dass der Erste, der ein Objekt von außen bekommt alles prüft, und alle anderen sich darauf verlassen können müssen! :idea:

Ein Beispiel für einen gefährlichen Trugschluss haben wir hier:

IngoD7 hat folgendes geschrieben:
Und somit hier mal einen kleinen Zwischenstand:
...

Zur Verdeutlichung:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
//Code A:
var xyObject : TEdit;
...
  (xyObject as TButton).hide;  //<--- EInvalidCast !

//Code B:
var xyObject : TEdit;
...
  TButton(xyObject).hide;  //Macht kalt lächelnd das Edit unsichtbar.


xyObject ist als TEdit deklariert und wird als TButton verwendet. Das geht hier, weil die Verwendung im Aufruf Hide besteht. Diese Methode wird aber weder in TEdit noch in TButton deklariert, sondern in TControl, also einer gemeinsamen Basisklasse! Deshalb führt der Aufruf zum "erwarteten" Ergebnis.

Im allgemeinen gilt das so nicht und die Ergebnisse sind unberechenbar!!!

Moderiert von user profile iconraziel: Code- durch Delphi-Tags ersetzt.
Moderiert von user profile iconraziel: Beiträge zusammengefasst.
retnyg
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2754

SNES, GB, GBA, CPC, A500, 486/66, P4/3.0HT: NintendOS, AmigaOS, DoS
Delphi 5, Delphi 7
BeitragVerfasst: Do 03.03.05 02:43 
respect @ wdbee
hoffentlich gibts hier in zukunft noch öfter was von dir zu lesen.
IngoD7
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 629


D7
BeitragVerfasst: Di 08.03.05 01:29 
user profile iconwdbee hat folgendes geschrieben:

Ein Beispiel für einen gefährlichen Trugschluss haben wir hier:

IngoD7 hat folgendes geschrieben:
Und somit hier mal einen kleinen Zwischenstand:
...

Zur Verdeutlichung:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
//Code A:
var xyObject : TEdit;
...
  (xyObject as TButton).hide;  //<--- EInvalidCast !

//Code B:
var xyObject : TEdit;
...
  TButton(xyObject).hide;  //Macht kalt lächelnd das Edit unsichtbar.


xyObject ist als TEdit deklariert und wird als TButton verwendet. Das geht hier, weil die Verwendung im Aufruf Hide besteht. Diese Methode wird aber weder in TEdit noch in TButton deklariert, sondern in TControl, also einer gemeinsamen Basisklasse! Deshalb führt der Aufruf zum "erwarteten" Ergebnis.

Im allgemeinen gilt das so nicht und die Ergebnisse sind unberechenbar!!!

Das Beispiel sollte nicht belegen, dass es zum "erwarteten" Ergebnis führt, sondern dass - im Gegensatz zur Verwendung von as - überhaupt (irgend)ein Ergebnis herauskommen kann, obwohl beide Typen ungleich sind. Es stellt somit keinen Trugschluss dar, sondern vielmehr einen Beleg für die auch von dir angemahnte Unberechenbarkeit. Letztere geht aus dem Kontext der vorherigen Postings m.E. auch schon hervor und sollte ganz bestimmt nicht durch das Beispiel widerlegt werden.
wdbee
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 628
Erhaltene Danke: 1



BeitragVerfasst: Di 08.03.05 06:56 
@IngoD7: Du hast Recht. :)

Was mir da wichtig war, ist die Tatsache, dass hier eine gemeine Fehlerquelle lauert. Leite von TObject zwei Klassen ab. Die erste bekommt eine Variable oder Methode die A heißt und dann eine die B heißt. Die zweite bekommt erst eine Variable oder Methode die B heißt und dann eine die A heißt.

Was dann passiert ist: Keine Fehlermeldung, aber A und B werden verwechselt, wenn mit direkter Typumwandlung gearbeitet wird. Also gilt nicht immer A=A und B=B oder wie oben dargestellt, Hide=Hide. Das war es was ich ergänzen wollte.