Objekt ohne Interface oder Struktur mit Funktion

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
mk-soft
Beiträge: 3695
Registriert: 24.11.2004 13:12
Wohnort: Germany

Objekt ohne Interface oder Struktur mit Funktion

Beitrag von mk-soft »

Hatte mal wieder zu viel Zeit 8)

Code: Alles auswählen

;-TOP

; -----------------------------------------------------------------------------

CompilerIf #PB_Compiler_Version > 561
  CompilerError "Warning: Check ASM-Compiler for valid RBP-Register!"
CompilerEndIf

Macro GetCaller(self) ; Get frame pointer from caller
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    EnableASM
    mov self, ebp
    DisableASM
  CompilerElse
    EnableASM
    mov self, rbp
    DisableASM
  CompilerEndIf  
EndMacro

; -----------------------------------------------------------------------------

Prototype protoAdd(Value.i)
Prototype protoSub(Value.i)
Prototype protoResult()

Structure sObject
  Add.protoAdd
  Sub.protoSub
  Result.protoResult
  Value.i
EndStructure

Procedure Add(Value.i)
  Protected *self.sObject
  GetCaller(*self)
  ;Debug *self
  *self\Value + Value
EndProcedure

Procedure Sub(Value.i)
  Protected *self.sObject
  GetCaller(*self)
  ;Debug *self
  *self\Value - Value
EndProcedure

Procedure Result()
  Protected *self.sObject
  GetCaller(*self)
  ;Debug *self
  ProcedureReturn *self\Value
EndProcedure

Procedure Init(*self.sObject)
  ; set procedure address
  *self\Add = @Add()
  *self\Sub = @Sub()
  *self\Result = @Result()
  ; set default values
  *self\Value = 0
EndProcedure

; -----------------------------------------------------------------------------

;-Test

Define a1.sObject
Debug "Init Object"
Init(a1)
;Debug @a1
Debug "Add and Sub"
a1\Add(100)
a1\Sub(20)
Debug "Result = " + a1\Result()

;-Test 2

Debug "Array of object"
Dim args.sObject(1000)
For i = 1 To 1000
  Init(args(i))
Next

For i = 1 To 1000
  args(i)\Add(Random(100))
  ;args(i)\Add(1); Random(100))
Next

For i = 1 To 1000
  r1 + args(i)\Result()
Next

Debug "Result = " + r1
Information
Ich habe mich mal wieder mit ASM beschäftigt und den Aufruf-Konvention.
Weil 'Fred' unser großer Purebasic Entwickler ist, hält er sich als Profi an den Aufruf-Konvention und verwendet das rbp-register als Zeiger auf den aktuellen Rekord (Frame-Pointer).
Somit können wird auf den Zeiger von der aktuellen Struktur (record) vom Aufrufer zugreifen.

Diese funktioniert natürlich nur so lange, wenn der Compiler kein anderes Verfahren verwendet. Zum beispiel auf ein Prozessor unabhängigen Compiler (LLVM-Compiler)
Zuletzt geändert von mk-soft am 03.09.2017 12:37, insgesamt 2-mal geändert.
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
GPI
Beiträge: 1511
Registriert: 29.08.2004 13:18
Kontaktdaten:

Re: Objekt ohne Interface oder Struktur mit Funktion

Beitrag von GPI »

Das kommt mir bekannt vor. Und soweit ich weis, gabs damals das Problem, das sehr schnell Beispiele aufgetaucht sind, wo das ganze nicht mehr ging.

Interessante Möglichkeit, aber auch irgendwie aufwendiger. Vor allen weil man immer ein Prototype schreiben muss.
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
Benutzeravatar
mk-soft
Beiträge: 3695
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Objekt ohne Interface oder Struktur mit Funktion

Beitrag von mk-soft »

Prototypes gibt es seit PB-Version 4.0 und habe die version noch einmal installiert.
Zur Sicherheit habe ich ein CompilerError eingebaut um eine Warnung auszugeben falls jemand diese verwendet.

Ist aber eine interessante Möglichkeit um schnelle Methoden zu schreiben, aber nicht Zukunftssicher.
Der sichere Weg ist weiterhin mit Interfaces zu arbeiten.
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
uweb
Beiträge: 461
Registriert: 13.07.2005 08:39

Re: Objekt ohne Interface oder Struktur mit Funktion

Beitrag von uweb »

@mk-soft:
Ich habe den Trick noch nicht gekannt. Deswegen auch hier im deutschen Forum: Vielen Dank!

Interessante Möglichkeit, aber auch irgendwie aufwendiger. Vor allen weil man immer ein Prototype schreiben muss.

Code: Alles auswählen

;-TOP

; -----------------------------------------------------------------------------

CompilerIf #PB_Compiler_Version > 561
  CompilerError "Warning: Check ASM-Compiler for valid RBP-Register!"
CompilerEndIf

Macro GetCaller(self) ; Get frame pointer from caller
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    EnableASM
    mov self, ebp
    DisableASM
  CompilerElse
    EnableASM
    mov self, rbp
    DisableASM
  CompilerEndIf 
EndMacro

; -----------------------------------------------------------------------------

; Simpler Procedures:

Procedure Add(ObjectValue.i, OperationValue.i) : ProcedureReturn ObjectValue + OperationValue : EndProcedure : Add = @Add()

Procedure Sub(ObjectValue.i, OperationValue.i) : ProcedureReturn ObjectValue - OperationValue : EndProcedure : Sub = @Sub()

Procedure Result(ObjectValue.i, OperationValue.i) : ProcedureReturn ObjectValue : EndProcedure : Result = @Result()


; For additional operators there is no need to change anything elsewhere. - e.g:

Procedure Mult(ObjectValue.i, OperationValue.i) : ProcedureReturn ObjectValue * OperationValue : EndProcedure : Mult = @Mult()

; -----------------------------------------------------------------------------

Prototype protoExecute(*Operation, OperationValue.i=0)

; Needs a little less memory:

Structure sObject
  Execute.protoExecute
  Value.i
EndStructure

Procedure Execute(*Operation, OperationValue.i=0)
  Protected *self.sObject
  GetCaller(*self)
  ;Debug *self
  *self\Value = CallFunctionFast(*Operation, *self\Value, OperationValue.i)
  ProcedureReturn *self\Value
EndProcedure

Procedure Init(*self.sObject)
  ; set procedure address
  *self\Execute = @Execute()
  ; set default values
  *self\Value = 0
EndProcedure

; -----------------------------------------------------------------------------

;-Test

Define a1.sObject
Debug "Init Object"
Init(a1)
;Debug @a1
Debug "Add and Sub"
a1\Execute(Add, 100)
a1\Execute(Sub, 20)
Debug "Result = " + a1\Execute(Result)

a1\Execute(Mult, 42)
Debug "Result * 42 = " + a1\Execute(Result)
;-Test 2

Debug "Array of object"
Dim args.sObject(1000)
For i = 1 To 1000
  Init(args(i))
Next

For i = 1 To 1000
  args(i)\Execute(Add, Random(100))
  ;args(i)\Execute(Add, 1); Random(100))
Next

For i = 1 To 1000
  r1 + args(i)\Execute(Result)
Next

Debug "Result = " + r1
GPI
Beiträge: 1511
Registriert: 29.08.2004 13:18
Kontaktdaten:

Re: Objekt ohne Interface oder Struktur mit Funktion

Beitrag von GPI »

Dann hast du aber auch nur ein Parameter :) und irgendwie auch kompliziert. Auch der große Vorteil, das IDE die Methoden vorschlägt, fällt auch flach.
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
Benutzeravatar
mk-soft
Beiträge: 3695
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Objekt ohne Interface oder Struktur mit Funktion

Beitrag von mk-soft »

Neues Beispiel :wink:

Code: Alles auswählen

;-TOP

; -----------------------------------------------------------------------------

CompilerIf #PB_Compiler_Version > 561
  CompilerError "Warning: Check ASM-Compiler for valid RBP-Register!"
CompilerEndIf

Macro GetCaller(self) ; Get frame pointer from caller
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    EnableASM
    mov self, ebp
    DisableASM
  CompilerElse
    EnableASM
    mov self, rbp
    DisableASM
  CompilerEndIf  
EndMacro

; -----------------------------------------------------------------------------

Prototype protoInvoke()

Structure sBox
  width.i
  height.i
  depth.i
  volume.protoInvoke
  sureface.protoInvoke
EndStructure

Procedure Volume()
  Protected *self.sBox, result.i
  GetCaller(*self)
  With *self
    result = \width * \height * \depth
  EndWith
  ProcedureReturn result
EndProcedure

Procedure Sureface()
  Protected *self.sBox, result.i
  GetCaller(*self)
  With *self
    result = \width * \height * 2 + \width * \depth * 2 + \height * \depth * 2 
  EndWith
  ProcedureReturn result
EndProcedure

Procedure New()
  Protected *self.sbox
  *self = AllocateStructure(sBox)
  If *self
    *self\volume = @Volume()
    *self\sureface = @Sureface()
  EndIf
  ProcedureReturn *self
EndProcedure

*box1.sbox = New()
*box1\width = 20
*box1\height = 40
*box1\depth = 100
Debug "Volume = " + *box1\volume()
Debug "Sureface = " + *box1\sureface()
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
uweb
Beiträge: 461
Registriert: 13.07.2005 08:39

Re: Objekt ohne Interface oder Struktur mit Funktion

Beitrag von uweb »

@GPI

... nur ein Parameter?
Was spricht gegen ...

Code: Alles auswählen

Prototype protoExecute(*Operation, Parameter_1.i=0, Parameter_2.i=0, Parameter_3.i=0)
... auch kompliziert?
Wenn Du das Grundgerüst erst einmal übernommen hast reduziert sich der Mehraufwand auf 'Procedure = @Procedure()'.

Code: Alles auswählen

; For additional operators there is no need to change anything elsewhere. - e.g:

Procedure Mult(ObjectValue.i, OperationValue.i) : ProcedureReturn ObjectValue * OperationValue : EndProcedure : Mult = @Mult()
Dafür reduziert sich der Aufwand an anderer Stelle.


Der große Vorteil, dass die IDE die Methoden vorschlägt, fällt tatsächlich weg. Da hast Du ganz klar Recht. Aber das ist wohl auch eine Frage der Vorlieben und Gewohnheiten.

Ein Stück weit kann ich Dich verstehen. Ich tue mich auch noch mit OO schwer. Das liegt aber u.a. auch daran, dass ich mich gerne von Fundamentalisten fern halte - egal welche Religion, welches Programmierparadigma oder was auch immer. Mit dem Trick von mk-soft kann man nach meinem Empfinden aber etwas OO-Vereinfachung nutzen ohne sich komplett auf das OO-Spiel einlassen zu müssen.
GPI
Beiträge: 1511
Registriert: 29.08.2004 13:18
Kontaktdaten:

Re: Objekt ohne Interface oder Struktur mit Funktion

Beitrag von GPI »

Ach ich bin jetzt auch kein OOP-Fanatiker. Ich hätte gerne es in PB, aber Fred ist - aus welchen unsinnigen Gründen auch immer - dagegen.

Mit den Execute hat immer den Nachteil, das du mit den Parameter begrenzt bist, egal wie du das drehst und wendest.

Ich weis noch, die Methode wurde schon mal in Englischen Forum besprochen und da kamen sehr schnell Beispiele, wo es auf einmal nicht mehr funktioniert hat. Ich kann mich aber beim besten Willen nicht mehr erinnern. Irgendwie hat diese Lösung nie einer benutzt...

Das größte Problem ist, dass das ganze eine nicht dokumentierte Funktion von PB nutzt. Und diesmal gehts halt wirklich ins Detail runter. Wenns Blöd läuft, funktioniert das zu 99% und genau diese 1% suchst du dann ewig in Fehlerfall.

Problematisch ist auch, das in Zukunft das nicht mehr zwingend Funktioniert. Wenn das Passiert, darfst du deinen Code entweder kompliziert anpassen oder wegschmeißen.
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
Benutzeravatar
mk-soft
Beiträge: 3695
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Objekt ohne Interface oder Struktur mit Funktion

Beitrag von mk-soft »

Ich weis noch, die Methode wurde schon mal in Englischen Forum besprochen und da kamen sehr schnell Beispiele, wo es auf einmal nicht mehr funktioniert hat. Ich kann mich aber beim besten Willen nicht mehr erinnern. Irgendwie hat diese Lösung nie einer benutzt...
Also diese Methode funktioniert schon seit der Version 4.0 von 8. Mai 2006 mit der Einführung von Prototypes :wink:
Muss also was anderes gewesen sein...

Habe aber selber geschrieben das es nicht unbedingt Zukunftssicher ist, aber interessant und schnell
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Antworten