Reflection "effektiv nutzen"

Übersicht BlitzMax, BlitzMax NG Beginners-Corner

Neue Antwort erstellen

 

PhillipK

Betreff: Reflection "effektiv nutzen"

BeitragDo, Dez 27, 2012 15:45
Antworten mit Zitat
Benutzer-Profile anzeigen
Huhu!

Durch ZEVS code habe ich ein wenig was über das Thema reflection gelernt.
Nun dachte ich mir, machste mal nen simplen test.

Dieser Test soll die Object methode "SendMessage" überladen, das ich Methoden per string ansprechen kann.

Hintergrund:
Ich habe einmal Type TGuiCore und Type TGuiPanel extends TGuielement.

TGuiElement und TGuiCore sind 2 verschiedene grundklassen, aber beide haben eine methode "addChild(ele:TguiElement)"

Da ich es leid bin, ständig abzufragen, ob mein übergebenes Core objekt nun ein Panel oder GuiCore ist, dachte ich: Hey. Reflection. Schaffst.

Gesagt, getan:
BlitzMax: [AUSKLAPPEN]
	Method SendMessage:Object(message:Object, context:Object)

If String(message) = Null Then Return context


Local tip:TTypeId = TTypeId.ForObject(Self)

Local meth:TMethod = tip.FindMethod(String(message))

If meth Then
meth.invoke(Self, [context])
End If
End Method


Schaut soweit ganz ordentlich aus.
Nun wurmt mich allerdings eine frage:
Wie zum henker kann ich integer übergeben? Ich brauch es zwar nicht, aber als hintergrund wissen wäre es doch klasse Smile

Das die methode SendMessage niemals ein integer akzeptieren wird, da sie mit 2 objects als parameter definiert wurde, ist mir klar.
Aber meth.invoke() aktepziert als 2ten parameter nur Object[]. Dennoch kann ich auch funktionen aufrufen, die zb einen integer erwarten. Auch wenn kein defaultwert angegeben ist, wird dieser integer mit 0 initialisiert. Heißt für mich um umkehrschluß: Mit TMethod.Invoke( object, Object[] ) kann ich die Grundlegende syntax von blitzmax und die statischen rahmenbedingungen austricksen. Aber wie ich ein Integer als objekt übergebe, ist mir immernoch unklar.

Das einzige wa sich weiß, ist das es zb IntegerTypeID oder so ähnlich gibt: Kann ich hier eventuell eine instanz von erschaffen und irgendwo den "wert" setzen?

BladeRunner

Moderator

BeitragDo, Dez 27, 2012 15:55
Antworten mit Zitat
Benutzer-Profile anzeigen
Nope, da zeigen sich die Schwächen des BMax-Konzeptes. Du musst leider die Integer in ein Objekt verpacken um das so nutzen zu können- BMax hat die Primitive nicht als Objekte parat.

Zudem muss dir bewusst sein, das reflection recht langsam ist.
Zu Diensten, Bürger.
Intel T2300, 2.5GB DDR 533, Mobility Radeon X1600 Win XP Home SP3
Intel T8400, 4GB DDR3, Nvidia GF9700M GTS Win 7/64
B3D BMax MaxGUI

Stolzer Gewinner des BAC#48, #52 & #92
 

PhillipK

BeitragDo, Dez 27, 2012 16:20
Antworten mit Zitat
Benutzer-Profile anzeigen
Jap, das es langsam ist, weiß ich.
Aber auch nur bei 12323423 aufrufen. Getestet mit etwa 100.000 aufrufen (forschleife) und nodebug, wars noch annehmbar schnell.

Da ich es nur für grundlegende sachen nehme, geht ein aufruf alle 100 frames Smile
Und wer ernsthaft der meinung ist, es müsse pro frame über 1000 gui elemente erzeugen, muss halt die 2 ms in kauf nehmen. Bringt keinen um.
Und auch so, ein ziemlicher luxus: Man denke an die möglichkeiten, mal auf die schnelle einen if bzw select baum mit 100+ möglichkeiten einzusparen, wenns ein simples SendMessage tut Smile

Schade. ein objekt, was einen integer hält, zu erzeugen, wäre ja noch drinne. Aber auch nur, solange man wirklich jede methode überarbeitet, die integer oder floats oder sonstwas erarbeitet. Sprich im großen ganzen nicht nutzbar.
(also cih hätte kein bock, ständig TInt.create(1) zu schreiben, wenns ne simple 1 auch tut *grins*)

BladeRunner

Moderator

BeitragDo, Dez 27, 2012 16:26
Antworten mit Zitat
Benutzer-Profile anzeigen
Nunja, du musst ja nicht alles überarbeiten. Du erschaffst Dir eine Schnittstelle. Das Objekt wird nur Temporär für den Aufruf erzeugt.
Blubmethode.invoke(geilesObjekt,[New TInt(meineVar)])
Schön ist anders, aber es funktioniert.
Zu Diensten, Bürger.
Intel T2300, 2.5GB DDR 533, Mobility Radeon X1600 Win XP Home SP3
Intel T8400, 4GB DDR3, Nvidia GF9700M GTS Win 7/64
B3D BMax MaxGUI

Stolzer Gewinner des BAC#48, #52 & #92

ZEVS

BeitragDo, Dez 27, 2012 17:32
Antworten mit Zitat
Benutzer-Profile anzeigen
Soweit ich weiß, ist die bevorzugte Vorgehensweise, den Int einfach nach String zu casten. Damit hat man zwar einen ziemlichen Overhead, was die ganzen Umwandlungen betrifft, dafür kann man den String direkt übergeben, Reflection kriegt dann irgendwie raus, dass es ein Int sein muss und ruft die Methode richtig mit Int auf.

ZEVS
 

PhillipK

BeitragDo, Dez 27, 2012 21:16
Antworten mit Zitat
Benutzer-Profile anzeigen
Das verstehe ich nicht ganz.
Also, laut zevs kann ich invoke mit einem string aufrufen und intern wird quasie "100".toInt() übergeben?
Und bei BR's methode.. üäh?
Übernimmt er das erste feld, was er findet und gibt es weiter? Oder wie läuft das? Very Happy
*gleich mal austest*

d-bug

BeitragDo, Dez 27, 2012 23:12
Antworten mit Zitat
Benutzer-Profile anzeigen
Schon mal vorweg:

Wenn du irgendwann die sinnvolle Fehlermeldung namens "ERROR" bekommst, dann hast du zu via Reflections zu wenig parameter an die Methode übergeben.

Möchte dir hiermit nur die stundenlange Suche nach dem Fehler ersparen, die ich soeben hinter mich brachte. Allerdings ist das bei mir auch ungleich komplexer als bei deinem Beispiel aus dem ersten post, da ich noch immer an dem Wrapper für Cocoa arbeite und alle Events, Delegate-Methoden und Notifications via Reflections durch den sumpfigen BlitzMax Morast jage. Da verliert man schon mal den Überblick bei der Bug-Suche...
 

PhillipK

BeitragFr, Dez 28, 2012 0:30
Antworten mit Zitat
Benutzer-Profile anzeigen
Danke für den tipp, D-Bug

Die methode von ZEV funktioniert tatsächlich. ich kann einen array mit strings übergeben, jedes element wird dann in den entsprechenden type umgewandelt.
Das von BR krieg ich leider nicht hin, da wird scheinbar ein pointer odersonstwas als integer verwendet.

Ich versuche weiter Very Happy

d-bug

BeitragFr, Dez 28, 2012 1:08
Antworten mit Zitat
Benutzer-Profile anzeigen
Na so schwer ist Blades Weg nun auch nicht. In Ausführlich siehts eben so aus:

BlitzMax: [AUSKLAPPEN]
Type TInt
Field value:Int
End Type

Local intWrap:TInt = New TInt
intWrap.value = 123456789

deineTolleTMethod.invoke(deinTollesObject, [Object(intWrap)])


That's it!

Das mit dem Pointer ist ja nun irgendwie seltsam. Sollte eigentlich nicht sein, wenn man ein Klasse übergibt... Irgend ein Strict Modus aktiv?

Übrigens gibt deine Methode aus dem Beispiel nichts zurück! Wenn es da schon keinen Fehler gab, dann benutzt du wirklich keinen Strict Modus... Sehr Verachtenswert! Wink
 

PhillipK

BeitragFr, Dez 28, 2012 1:15
Antworten mit Zitat
Benutzer-Profile anzeigen
BlitzMax: [AUSKLAPPEN]
Type TTest
Method printInt:Int(zahl:Int)
Print("PrintInt ist aufgerufen worden. Zahl: " + zahl)
End Method
End Type

Type Tint
Field p:Int
Method New()

End Method
Function Create:Tint(p:Int)
Local i:Tint = New Tint
i.p = p
Return i
EndFunction

End Type


Local t:TTest = New TTest
Local tip:TTypeId = TTypeId.ForObject(t)

Local meth:TMethod = tip.FindMethod("printInt")
If meth Then
meth.Invoke(t, [New Tint.Create(100)])
End If

Der Test hier gibt zufällige zahlen aus, manchmal 0, manchmal 31212 oder sonstigen käse. 100 gabs nie geprintet. Smile
Aktiv ist, seit ich mit bmax angefangen habe, wie immer Superstrict.

Meine methode aus dem beispiel?
Das war mein erster versuch, mit reflection zu arbeiten, ich hab keine ahnung, was und ob und überhuapt da zurückgegeben werden sollte / könnte.
SendMessage pack ich heut auch das erste mal an Very Happy

d-bug

BeitragFr, Dez 28, 2012 1:49
Antworten mit Zitat
Benutzer-Profile anzeigen
WTF? Ändere mal dringend deine printInt Methode!

BlitzMax: [AUSKLAPPEN]
Type TTest
Method printInt:Int(zahl:TInt)
Print("PrintInt ist aufgerufen worden. Zahl: " + zahl.p)
End Method
End Type


Wenn du ein TInt Objekt übergibst, solltest du auch ein TInt Object als Parameter einsetzen. Kein Wunder das da nur Quark raus kommt!

Du würdest doch auch auf normalem Weg, also ohne Reflection, kein TInt Object an einen Int Parameter übergeben, stimmts?
 

PhillipK

BeitragFr, Dez 28, 2012 2:10
Antworten mit Zitat
Benutzer-Profile anzeigen
aber das war doch der plan *grins*
Anscheinend wurde meine ursprungsfrage etwas falsch interpretiert.

Ich hab überlegt, ob es einen weg gibt, über IntegerTypeId oder sonstwas einen int an eine methode zu übergeben Very Happy
Da die invoke methode zwar "nur" object[] akzeptiert, aber sonst anscheinend alles umgeht, hatte ich gehofft, da was zu finden *grins*
Deswegen hats anscheinend nicht geklappt Razz

Ich habe übrigends aufgrund eines fehler rausgefunden, wie das funktioniert, einen String zu übergeben. intern wird tatsächlich ganz stupide .toInt() und .toFloat() undsoweiter angewendet, um die objekte richtig zu übergeben.
Zu finden in reflection.bmx, beispiel:
BlitzMax: [AUSKLAPPEN]
Function _Push:Byte Ptr( sp:Byte Ptr,typeId:TTypeId,value:Object )
Select typeId
Case ByteTypeId,ShortTypeId,IntTypeId
(Int Ptr sp)[0]=value.ToString().ToInt()
Return sp+4
Case LongTypeId
(Long Ptr sp)[0]=value.ToString().ToLong()
Return sp+8
Case FloatTypeId
(Float Ptr sp)[0]=value.ToString().ToFloat()
Return sp+4
Case DoubleTypeId
(Double Ptr sp)[0]=value.ToString().ToDouble()
Return sp+8
Case StringTypeId
If Not value value=""
bbRefPushObject sp,value
Return sp+4
Default
If value
Local c=typeId._class
Local t=bbRefGetObjectClass( value )
While t And t<>c
t=bbRefGetSuperClass( t )
Wend
If Not t Throw "ERROR"
EndIf
bbRefPushObject sp,value
Return sp+4
End Select
End Function



Um das ganze nochmal weiter aufzufassen:
Ich wollte methoden, die int,float, etc (also primtive) akzeptieren, EVENTUELL mit TMethod.invoke() aufrufen. Nicht das ichs brauchen würde, es war eine rein technische frage fürs verständnis.
Bladerunner hat hier eine andeutung in die richtung gemacht:
Zitat:
Nunja, du musst ja nicht alles überarbeiten. Du erschaffst Dir eine Schnittstelle. Das Objekt wird nur Temporär für den Aufruf erzeugt.
Blubmethode.invoke(geilesObjekt,[New TInt(meineVar)])

Weshalb ich annahm, das es intern auch eine coole methode gibt, das erste field eines objektes zu übergeben, wenn der typ passt.
Rein von dem was ich im reflection modul so finde, wäre das sogar ganz theortisch möglich. Mal ransetzen, ob man da nicht nen hack machen kann:
TTypeID vom value holen. Fieldlist.First(), wenn Type = geforderter typ, dann den übergeben. sonst das objekt zu nem int wandeln.
Warum nicht? Reflection ist eh langsam, also wird ne abfrage mehr auch nicht schaden. :>

BladeRunner

Moderator

BeitragFr, Dez 28, 2012 15:41
Antworten mit Zitat
Benutzer-Profile anzeigen
Oh, da wurde ich wohl ein wenig mißverstanden und auch das Beispiel meinerseits war nicht 100% korrekt:
Code: [AUSKLAPPEN]
Blubmethode.invoke(geilesObjekt,[TInt.Create(meineVar)])


Und selbstredend ist es so dass Du die Methode auf den Empfang eines Objektes vom Typt TInt eichen musst, was aber ja kein Problem darstellen sollte, denn Du weisst ja dass Du die Methode per Reflection verwenden wirst.
Rein theoretisch kann man die im Speicher befindlichen Ints auch direkt auslesen aber da kommen wir in den Bereich von echt dreckigen Hacks.
Zu Diensten, Bürger.
Intel T2300, 2.5GB DDR 533, Mobility Radeon X1600 Win XP Home SP3
Intel T8400, 4GB DDR3, Nvidia GF9700M GTS Win 7/64
B3D BMax MaxGUI

Stolzer Gewinner des BAC#48, #52 & #92
 

PhillipK

BeitragFr, Dez 28, 2012 16:56
Antworten mit Zitat
Benutzer-Profile anzeigen
Zum glück sind wir ja menschen, die Kommunikation beherrschen Very Happy

Okay, mir würde da ein schönes workarround einfallen. Jede methode kriegt eine kopie mit "__RFL" vornan. Diese methoden leiten nur weiter und übergeben die parameter richtig.
Nun wird noch sendMessage überladen, welches vor den normalen methodennamen dieses __RLF ranschreibt und die passende methode holt.

Bleibt nurnoch die frage, wie man SendMessage() mit nem int als parameter aufruft. Nämlich garnicht ohne dreckigen hack Smile

Methode 1: Object im modul überarbeiten und SendMessageI und SendMessageIArr und so käse anfügen. Doof,weil jeder potentielle nutzer seinen Mod ordner hacken müsste.

Methode 2: Eine art eigenes core-objekt erstellen, zb PK_Object, was nix weiter tut als von Object zu extenden und die grundklasse für alle eigenen types zu sein. Diese bietet die möglichkeit, diverse parameter zu übergeben (SendMessageI(obj:Object, i:Int) etc). Brauchbar, aber umständlich.

Methode 3: Einfach wie gehabt fortfahren und die Reflection sache und die Faulheit nur ganz bedingt einsetzen, nicht zuletzt um die performance zu schonen.

Ich muss sagen, das ist die einzige sache, die ich wirklich an java mag. Funktions und methodenüberladung einfach durch andere Parameter. Aber egal, blitzmax bleibt mein kleiner favorit *grins*


Mal ne frage am rande, an euch profis:
Wann macht reflection sinn?
Mir fallen spontan folgende dinge ein:
1) SendMessage überladen, um diverse methoden anzusprechen, nur wenn sie existieren.
2) ZEVs genialer ansatz, Objekte zu speichern
3) Eigene Debugger, wenn man sich in seinen Extends verläuft und wissen möchte, was grade abgeht (allein die tatsache, das man an einen Name:String rankommt, wie das objekt heißt, ist gold wert!)
4) Allein vom code sieht es so aus, als könnte man objekte speziell zusammenschustern. Ob ich damit richtig liege, weiß ich nicht. Aber es sieht halt aus, als wäre es möglich, diverse Methoden in ein objekt zu schreiben, welche es eigentlich nicht hat.

ZEVS

BeitragFr, Dez 28, 2012 17:17
Antworten mit Zitat
Benutzer-Profile anzeigen
5) Wenn man Skriptsprachen entwickelt, hat man sehr schnell viel Spaß mit Reflection.
Zu 4): Du willst dir also ein Objekt nehmen (sagen wir, x:TList) und eine Methode "reinschieben", die es gar nicht hat (z.B. concat). Dir ist aber hoffentlich klar, dass du diese Methode dann (wenn überhaupt) nur über Reflection aufrufen kannst, da diese Information erst zur Laufzeit bekannt ist. Du würdest, nach dem, was ich aus den C-Grundlagen von BMax gesehen habe, wohl die BBClass-Struktur manipulieren, indem du instance_size erhöhst, um deine neue Methode unterzubringen. Das wäre wohl der perfekte Mordanschlag auf GC: Sage ihm, die Objekte seien größer als er meint.

ZEVS

BladeRunner

Moderator

BeitragSa, Dez 29, 2012 13:29
Antworten mit Zitat
Benutzer-Profile anzeigen
Zu 2) schau mal im Portal nach ChaosClone, da hab ich schon eine Lib die dir (nahezu)beliebige Objekte speichern und laden kann.
Zu Diensten, Bürger.
Intel T2300, 2.5GB DDR 533, Mobility Radeon X1600 Win XP Home SP3
Intel T8400, 4GB DDR3, Nvidia GF9700M GTS Win 7/64
B3D BMax MaxGUI

Stolzer Gewinner des BAC#48, #52 & #92
 

PhillipK

BeitragSa, Dez 29, 2012 14:02
Antworten mit Zitat
Benutzer-Profile anzeigen
haha, so habe ich den 4ten punkt garnicht betrachtet Zevs.
Ja, nur über reflection hat sich mit schon ergeben, aber das ich den GC damit verwirre war mir nicht klar Smile
Ging ja nur um theorie... "warum reflection" - denn: ICh habe schon das ein oder andere mit bmx programmiert und immer mein ziel erreicht. Reflection war nie notwendig und schaut bisher einfach nur nach ner faulheit aus =)

BladeRunner

Moderator

BeitragSa, Dez 29, 2012 14:15
Antworten mit Zitat
Benutzer-Profile anzeigen
Im Prinzip ist es das auch, denn auch ohne Reflection lassen sich ja alle Aufgaben lösen. Es ist halt eine lustige und teils nützliche Spielerei.
Zu Diensten, Bürger.
Intel T2300, 2.5GB DDR 533, Mobility Radeon X1600 Win XP Home SP3
Intel T8400, 4GB DDR3, Nvidia GF9700M GTS Win 7/64
B3D BMax MaxGUI

Stolzer Gewinner des BAC#48, #52 & #92
 

PhillipK

BeitragSa, Dez 29, 2012 14:19
Antworten mit Zitat
Benutzer-Profile anzeigen
Okay und, ohne google gefragt zu haben, gibt es sowas wie die Blitzmax reflection auch in anderen programmiersprachen? :3

BladeRunner

Moderator

BeitragSa, Dez 29, 2012 14:34
Antworten mit Zitat
Benutzer-Profile anzeigen
Gibt es, durchaus, auch wenn es andere Namen hat.
Bei interpretierten Sprachen zB ist es idR kein größeres Problem zur Laufzeit neue Variablen einzuführen.
Siehe auch:
http://en.wikipedia.org/wiki/R...science%29
Zu Diensten, Bürger.
Intel T2300, 2.5GB DDR 533, Mobility Radeon X1600 Win XP Home SP3
Intel T8400, 4GB DDR3, Nvidia GF9700M GTS Win 7/64
B3D BMax MaxGUI

Stolzer Gewinner des BAC#48, #52 & #92

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Beginners-Corner

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group