Field von Type als Pointer

Übersicht BlitzMax, BlitzMax NG Allgemein

Neue Antwort erstellen

UNZ

Betreff: Field von Type als Pointer

BeitragFr, Feb 08, 2013 12:26
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo Leute,

ich versuche gerade ein Type zu erstellen, dass selbstständig eine Variable ändern kann die iwo anders steht.

als Beispiel:
Code: [AUSKLAPPEN]
superstrict

local abc$ = "abc"

local o:Ttest = new Ttest
o.setPtr(abc)
o.modifyVar()

print
print o.txtVar
print abc

Type Ttest
   
   field txtVar:String
   
   method setPtr(txt:String var)
      txtVar= txt
   end method   
   
   method modifyVar()   
      txtVar= "xyz"
   end method   
   
end type


In der Method setPtr wird natürlich die Variable richtig referenziert, allerdings wird in txtVar trotzdem nur eine Kopie davon geschrieben. So weit so klar.
Was ich jetzt bräuchte, ist sowas wie Code: [AUSKLAPPEN]
field txtVar:String var
oder so, damit ich die Variable auch überall sonst im Type referenziere.

Aber ich bekomme dabei einen Fehler.
Vllt. bin ich auch auf dem Holzweg und das geht mit Ptr?
Oder geht das überhaupt nicht (wenn ja warum, geht in der function doch auch...)

thx
Das muss besser als perfekt!

Thunder

BeitragFr, Feb 08, 2013 13:39
Antworten mit Zitat
Benutzer-Profile anzeigen
Schwierige Sache..
Ok, also erst Mal: Für String wird das, glaube ich, schwierig. Habe dein Beispiel so umgeschrieben, dass es für Int funktioniert:
BlitzMax: [AUSKLAPPEN]
SuperStrict 
Framework brl.standardio

Local abc:Int = 50

Local o:Ttest = New Ttest
o.setPtr(Varptr(abc))

Print abc

o.modifyVar(60)

Print abc

Type Ttest
Field dataVar:Int Ptr

Method setPtr(data:Int Ptr)
dataVar = data
End Method

Method modifyVar(data:Int)
dataVar[0] = data
End Method

End Type


Die Sache ist: wenn du versuchst, dass auf String zu übertragen, wirst du merken, dass es nicht möglich ist, Zeiger auf String, Object oder sonstige selbstdefinierte Datentypen zu bekommen. Du kannst für Strings aber den Umweg über Byte Ptr gehen (was aber zwangsläufig Konvertierungen mit sich bringt):

BlitzMax: [AUSKLAPPEN]
SuperStrict 
Framework brl.standardio

Local abc:Byte Ptr = "abc".toCString()

Local o:Ttest = New Ttest
o.setPtr(Varptr(abc))

Print String.FromCString(abc)

o.modifyVar("xyz".toCString())

Print String.FromCString(abc)

Type Ttest
Field dataVar:Byte Ptr Ptr

Method setPtr(data:Byte Ptr Ptr)
dataVar = data
End Method

Method modifyVar(data:Byte Ptr)
dataVar[0] = data
End Method

End Type


Ob das genau so mit Types geht, die man dann halt nach Byte Ptr konvertiert, weiß ich jetzt nicht... ich denke, es hätte funktionieren müssen, aber spontan hab ich es nicht hinbekommen.

Zur Sache mit Var noch: Den habe ich einmal in meine "Asm/C/C++ & BlitzMax"-Tutorial erwähnt. Es ist einfach ein Operator, der dir Arbeit abnimmt. Wieso gibt es ihn nur für Funktionsparameter? Weil er ein Call by Reference einleitet. Normalerweise werden Variablen nämlich Call by Value übergeben.
  • Call by Reference: Adresse der Variable landet auf dem Stack. Wenn du in der Funktion den Variablennamen verwendest, wird über diese Adresse (wie mit einem Pointer) auf die Variable zugegriffen, d.h. sie bleibt auch außerhalb der Funktion geändert.
  • Call by Value: Der Wert der Variablen landet auf dem Stack. Wird auf die Variable zugegriffen, wird der Wert im Stack manipuliert, nicht die ursprüngliche Variable. Sobald man aus der Funktion zurückspringt, wird der Stack verkleinert und die Veränderungen werden nicht übertragen, sondern gehen verloren.


*Stack meint in dem Fall den Ort, wo Rücksprungadressen, lokale Variablen und Parameter gespeichert werden.
Meine Sachen: https://bitbucket.org/chtisgit https://github.com/chtisgit

UNZ

BeitragFr, Feb 08, 2013 17:15
Antworten mit Zitat
Benutzer-Profile anzeigen
Gut, vergessen wir die Zeiger.
Da die Sachen, die ich kontrollieren will, (wie das meiste bei OOP) gesammelt in einer Klasse sind, kann ich sie auch entsprechend übergeben.

Code: [AUSKLAPPEN]
SuperStrict
Framework brl.standardio

local me:myType = new myType
me.name = "abc"
me.number= 123

Local o:Ttest = New Ttest
o.set(me)

Print me.name
print me.number
o.modify()
Print me.name
print me.number

Type Ttest
   Field obj:Object
   
   Method set(obj:Object)
      self.obj= obj
   End Method
   
   Method modify()
      local o:myType= myType(obj)   
      o.name= "xyz"
      o.number= 789
   End Method   
   
End Type

'-----------------------------
Type myType
   
   field name:String   
   field number:int
   
End Type

Allerdings wirft das gerade ein paar Fragen auf, die ich mir so noch nie gestellt habe.
Wie kommt es, dass ich ein Objekt übergebe und in dem Ttest Type das selbe referenziert wird, aber bei einem String nicht?
Wiederum ist es ja so, dass das Null setzen nur für die Referenz gilt.
Code: [AUSKLAPPEN]

Method modify()
   local o:myType= myType(obj)   
   o.name= "xyz"
   o.number= 789
   o= null'<--- hat keinen Einfluss auf die eigentliche Instanz
End Method

Wollte ich die Instanz itself Null setzen, müsste ich in der Methode gleich die Referenz selbst übergeben z.B. mit Code: [AUSKLAPPEN]
modify(obj:myType var)



Zurück zu den Strings:
Strings sind doch genauso Objekte, wie alle anderen, oder nicht?
Es gibt ja auch Methoden bei Strings z.B. Code: [AUSKLAPPEN]
print "abc".toUpper()

Gibt es dann auch ein Field bei Strings, mit 'nem int Array, in dem die Zeichen stehen?


Was passiert eigentlich wenn ich schreibe
Code: [AUSKLAPPEN]
a$= "abc"+"def"

Es ist hier "abc" und "def" ja jeweils ein String.
Es wird dann a ein neuer String; praktisch die Rückgabe der Operation + angewendet auf zwei einzelne Objekte, oder?


Die Sachen sind eigentlich recht offensichtlich, aber ich hab nie so drüber nachgedacht.
Das muss besser als perfekt!

Thunder

BeitragFr, Feb 08, 2013 18:33
Antworten mit Zitat
Benutzer-Profile anzeigen
Zitat:
Wie kommt es, dass ich ein Objekt übergebe und in dem Ttest Type das selbe referenziert wird, aber bei einem String nicht?
...
Strings sind doch genauso Objekte, wie alle anderen, oder nicht?


Ein String ist ganz klar eine Erweiterung der Object-Klasse, sonst könntest du Strings nicht nach Object casten. Dennoch sind Strings "etwas Besonderes": Wie du bemerkt hast, kannst du sie addieren, was weder aus mathematischer, noch aus syntaktischer Sicht (Addition zweier Objekte) einen Sinn macht. Was hier passiert ist Abstraktion. Es ist für BASIC-Programmierer logisch, dass sie das dürfen, deswegen werden die Compiler so programmiert, dass sie intern eine "Addition" von zwei Strings umwandeln in einen Funktionsaufruf zu einer Funktion "bbStringConcat", die dann die Strings zusammenfügt.
Wenn du einen String übergibst, wird er zuerst kopiert, um ihn zu schützen. Es ist quasi String der einzige Datentyp, der so ein bisschen ein Primitiver Datentyp ist (denn die sind durch Call by Value auch geschützt) und ein bisschen ein Objekt. Das macht aber der Compiler.

Zitat:
Gibt es dann auch ein Field bei Strings, mit 'nem int Array, in dem die Zeichen stehen?

Jup! Hier ist die Definition der BBString-Klasse. Ein String ist ein Zeiger auf eine Instanz dieser Struktur.
C-Code: [AUSKLAPPEN]
struct BBString{
   BBClass*   clas;
   int      refs;
   int      length;
   BBChar   buf[];
};

Und so schaut eine initialisierte Instanz davon aus:
Assembler-Code: [AUSKLAPPEN]
   dd   bbStringClass
   dd   2147483647
   dd   3
   dw   97,98,99

Als erstes kommt ein Verweis auf die bbStringClass (4 Byte). Als nächstes obligatorisch der Maximalwert für ein positives Int (4 Byte), hab ich zumindest noch nicht anders beobachtet. Als nächstes die Stringlänge (4 Byte). Und dann ein Short-Array aus den Zeichen (2 Byte pro Zeichen).

Zitat:
Wollte ich die Instanz itself Null setzen, müsste ich in der Methode gleich die Referenz selbst übergeben


Was heißt für dich, die Instanz Null zu setzen?
Ich kann einen Zeiger Null setzen. Die stdlib definiert NULL als ((void*) 0), also ein typenloser Zeiger auf die Adresse 0 im virtuellen Speicher. Dort wird traditionell nichts gespeichert, damit man zwischen initialisierten und nicht initialisierten Zeiger unterscheiden kann.
Eine Instanz ist ein (meist größerer) kontinuierlicher Speicherbereich, wo ein Datenpaket drinnen steht. Was willst du Null setzen? Es mit Nullen überschreiben?


Zitat:
Es ist hier "abc" und "def" ja jeweils ein String.
Es wird dann a ein neuer String; praktisch die Rückgabe der Operation + angewendet auf zwei einzelne Objekte, oder?

Das ist richtig. Und die Operation + wird eben vom Compiler auf ein bbStringConcat zurückgeführt.
Meine Sachen: https://bitbucket.org/chtisgit https://github.com/chtisgit

UNZ

BeitragFr, Feb 08, 2013 19:36
Antworten mit Zitat
Benutzer-Profile anzeigen
Mit "Null setzen" meine ich das Überschreiben des Zeigers, so dass dessen Methoden nicht mehr aufgerufen werden können.
Der GC übernimmt dann ja das eigentliche Freigeben der Instanz, damit der Speicher wieder neu zugewiesen werden kann, wenn ich mich nicht irre.

Code: [AUSKLAPPEN]
SuperStrict
Framework brl.standardio

local me:myType = new myType
me.name = "abc"
me.number= 123

Local o:Ttest = New Ttest
Print me.name
print me.number

o.modify(me)

Print me.name
print me.number

Type Ttest
   Method modify(o:myType var)
      o.name= "xyz"
      o.number = 789
      o= null
   End Method   
End Type

'-----------------------------
Type myType
   field name:String   
   field number:int
End Type


Das Programm wird 'nen Fehler ausgeben.
Das muss besser als perfekt!

Thunder

BeitragFr, Feb 08, 2013 20:32
Antworten mit Zitat
Benutzer-Profile anzeigen
Ok. Und ja, das mit dem GC stimmt.
Die Sache ist nur: Was ist jetzt die eigentliche Frage? Dass dein Programm einen Fehler gibt, bestätigt ja nur, dass alles funktioniert hat. Sobald du nämlich o auf Null setzt ist me auch Null, weil es ja von o referenziert wird. Dann greifst du aber nochmal auf Instanzvariablen von me zu, was du nicht mehr darfst - du merkst also, dass es einwandfrei funktioniert hat. Oder meinst du das anders?

Edit: Ok, passt. Dachte es wäre noch was ungeklärt Very Happy
Meine Sachen: https://bitbucket.org/chtisgit https://github.com/chtisgit
  • Zuletzt bearbeitet von Thunder am Fr, Feb 08, 2013 23:36, insgesamt einmal bearbeitet

UNZ

BeitragFr, Feb 08, 2013 23:08
Antworten mit Zitat
Benutzer-Profile anzeigen
Das mit dem Fehler ist mir klar Smile (War nur zur Veranschaulichung).
Meine Fragen haben sich alle geklärt. Danke für die Antworten Wink
Das muss besser als perfekt!

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group