2013-10-07 10 views
7

ich in der Regel Programm von Funktionen in einer „instinktiven“ Art und Weise, aber mein aktuelles Problem kann leicht durch Objekte gelöst werden, so dass ich voran gehen mit dieser Methode.gibt es einen Objektkonstruktor in Rebol

Doing so, ich versuche, einen Weg zu finden, ein Objekt eine Konstruktormethode, das Äquivalent von init() in Python, zum Beispiel zu geben.

sah ich in der http://www.rebol.com/docs/core-fr/fr-index.html Dokumentation, aber ich kann nichts relevant finden.

Antwort

3

Eigentlich indem Sie erneut die Rebol Core-Dokumentation zu lesen (ich folgte nur den guten alten Rat: „Lesen Sie das Französisch Manual“), gibt es eine weitere Möglichkeit, einen Konstruktor zu implementieren, ganz einfach:

http://www.rebol.com/docs/core-fr/fr-rebolcore-10.html#section-8

natürlich ist es auch im englischen Handbuch:

http://www.rebol.com/docs/core23/rebolcore-10.html#section-7

=>

Ein weiteres Beispiel für die Selbst Variable ist eine Funktion, die selbst klont:

person: make object! [ 
    name: days-old: none 
    new: func [name' birthday] [ 
     make self [ 
      name: name' 
      days-old: now/date - birthday 
     ] 
    ] 
] 

lulu: person/new "Lulu Ulu" 17-May-1980 

print lulu/days-old 
7366 

Ich finde das sehr bequem, und auf diese Weise liegt der Konstruktor innerhalb des Objekts. Diese Tatsache macht das Objekt autarker.

ich nur implementiert, die erfolgreich für einige geologische Sachen, und es funktioniert gut:

>> source orientation 
orientation: make object! [ 
    matrix: [] 
    north_reference: "Nm" 
    plane_quadrant_dip: "" 
    new: func [{Constructor, builds an orientation object! based on a measurement, as given by GeolPDA device, a rotation matrix represented by a suite of 9 values} m][ 
     make self [ 
      foreach [a b c] m [append/only matrix to-block reduce [a b c]] 
      a: self/matrix/1/1 
      b: self/matrix/1/2 
      c: self/matrix/1/3 
      d: self/matrix/2/1 
      e: self/matrix/2/2 
      f: self/matrix/2/3 
      g: self/matrix/3/1 
      h: self/matrix/3/2 
      i: self/matrix/3/3 
      plane_normal_vector: reduce [matrix/1/3 
       matrix/2/3 
       matrix/3/3 
      ] 
      axis_vector: reduce [self/matrix/1/2 
       self/matrix/2/2 
       self/matrix/3/2 
      ] 
      plane_downdip_azimuth: azimuth_vector plane_normal_vector 
      plane_direction: plane_downdip_azimuth - 90 
      if (plane_direction < 0) [plane_direction: plane_direction - 180] 
      plane_dip: arccosine (plane_normal_vector/3) 
      case [ 
       ((plane_downdip_azimuth > 315) or (plane_downdip_azimuth <= 45)) [plane_quadrant_dip: "N"] 
       ((plane_downdip_azimuth > 45) and (plane_downdip_azimuth <= 135)) [plane_quadrant_dip: "E"] 
       ((plane_downdip_azimuth > 135) and (plane_downdip_azimuth <= 225)) [plane_quadrant_dip: "S"] 
       ((plane_downdip_azimuth > 225) and (plane_downdip_azimuth <= 315)) [plane_quadrant_dip: "W"] 
      ] 
      line_azimuth: azimuth_vector axis_vector 
      line_plunge: 90 - (arccosine (axis_vector/3)) 
     ] 
    ] 
    repr: func [][ 
     print rejoin ["Matrix: " tab self/matrix 
      newline 
      "Plane: " tab 
      north_reference to-string to-integer self/plane_direction "/" to-string to-integer self/plane_dip "/" self/plane_quadrant_dip 
      newline 
      "Line: " tab 
      rejoin [north_reference to-string to-integer self/line_azimuth "/" to-string to-integer self/line_plunge] 
     ] 
    ] 
    trace_te: func [diagram [object!]][ 
     len_queue_t: 0.3 
     tmp: reduce [ 
      plane_normal_vector/1/(square-root (((plane_normal_vector/1 ** 2) + (plane_normal_vector/2 ** 2)))) 
      plane_normal_vector/2/(square-root (((plane_normal_vector/1 ** 2) + (plane_normal_vector/2 ** 2)))) 
     ] 
     O: [0 0] 
     A: reduce [- tmp/2 
      tmp/1 
     ] 
     B: reduce [tmp/2 0 - tmp/1] 
     C: reduce [tmp/1 * len_queue_t 
      tmp/2 * len_queue_t 
     ] 
     L: reduce [- axis_vector/1 0 - axis_vector/2] 
     append diagram/plot [pen black] 
     diagram/trace_line A B 
     diagram/trace_line O C 
     diagram/trace_line O L 
    ] 
] 
>> o: orientation/new [0.375471 -0.866153 -0.32985 0.669867 0.499563 -0.549286 0.640547 -0.0147148 0.767778] 
>> o/repr 
Matrix:  0.375471 -0.866153 -0.32985 0.669867 0.499563 -0.549286 0.640547 -0.0147148 0.767778 
Plane: Nm120/39/S 
Line: Nm299/0 

Ein weiterer Vorteil dieser Art und Weise ist, dass Variablen, die von der „neuen“ Methode definiert gehört direkt auf das Objekt „Instanz“ (Ich geriet in Schwierigkeiten, mit den anderen Methoden, wobei ich selbst/manchmal erwähnen muss, Variablen initialisieren oder nicht).

6

Es gibt keine spezielle Konstruktorfunktion in Rebol, aber es gibt eine Möglichkeit, Ad-hoc- init-Code zu schreiben, wenn Sie es auf Objekterstellung in dem Block spec müssen. Zum Beispiel:

a: context [x: 123] 

b: make a [ 
    y: x + 1 
    x: 0 
] 

Also, wenn Sie Ihre eigene „Konstruktor“ Funktion durch Konvention im Basisobjekt definieren, können Sie es nennen die Spezifikation Block auf Schöpfung. Wenn Sie es automatisch machen möchten, können Sie dies in einer Funktion wickeln, wie folgt aus:

a: context [ 
    x: 123 
    init: func [n [integer!]][x: n] 
] 

new-a: func [n [integer!]][make a [init n]] 

b: new-a 456 

Eine robustere (aber etwas länger) Version von neu ein, die die mögliche Kollision der übergebenen Argumente vermeiden würde zu init mit eigenen Worten Objekt wäre:

new-a: func [n [integer!] /local obj][ 
    also 
     obj: make a [] 
     obj/init n 
] 

Sie auch ein allgemeineres neue Funktion, die ein Basisobjekt als erstes Argument nehmen würde und automatisch aufrufen, um eine Konstruktor-by-Konvention Funktion nach clon schreiben konnte das Objekt ing, aber optional Konstruktorargumente in allgemeiner Weise unterstützt, ist dann komplizierter.

Denken Sie daran, dass das Objektmodell von Rebol ist Prototyp-basierte (vs klassenbasierte in Python und die meisten anderen OOP-Sprachen), so dass die „Konstruktor“ -Funktion erhält für jedes neue Objekt erstellt dupliziert. Sie sollten solche Kosten vermeiden, wenn Sie eine große Anzahl von Objekten erstellen.

+0

Ja, Sie haben beide sehr ähnliche Lösungen. init oder neu? das ist die Frage, um die Konstruktormethode zu benennen ... Natürlich, wenn eine große Menge von Objekten erzeugt werden soll, sollten solche Methoden auf jeden Fall vermieden werden. In meiner gegenwärtigen Problematik habe ich tatsächlich an ein paar Objekte gedacht, nicht einmal an ein Dutzend. – Pierre

5

Meines Wissens gibt es keine formale Methode/Konvention für Objektkonstruktoren verwenden wie init(). Es ist natürlich die integrierte Methode zur Konstruktion Derivat Objekte:

make prototype [name: "Foo" description: "Bar"] 
    ; where type? prototype = object! 

Mein bester Vorschlag wäre, eine Funktion zu definieren, die für eine Konstruktor-Methode ein Objekt untersucht, gilt dann das Verfahren, hier ist eine solche Funktion, die ich habe proposed previously:

new: func [prototype [object!] args [block! none!]][ 
    prototype: make prototype [ 
     if in self 'new [ 
      case [ 
       function? :new [apply :new args] 
       block? :new [apply func [args] :new [args]] 
      ] 
     ] 
    ] 
] 

die Benutzung ist ganz einfach: wenn ein Prototyp-Objekt einen new Wert hat, dann wird es in der Konstruktion des Derivats Objekt angewendet werden:

thing: context [ 
    name: description: none 
    new: [name: args/1 description: args/2] 
] 

derivative: new thing ["Foo" "Bar"] 

beachten Sie, dass dieser Ansatz sowohl in Rebol 2 und 3 arbeitet.

+0

ok: Alles was wir brauchen, ist dann eine richtige Konvention für eine Konstruktormethode in einem Objekt, falls nötig. – Pierre

3

Ich versuche herauszufinden, wie OO in REBOL funktioniert. Prototypisch in der Tat. Gestern stieß ich auf dieser Seite, die mich unter dem klassischen OO-Modell inspiriert, ohne Duplizierung von Funktionen:

;---- Generic function for class or instance method invocation ----; 
invoke: func [ 
    obj [object!] 
    fun [word!] 
    args [block!] 
][ 
    fun: bind fun obj/.class 
    ;---- Class method names start with a dot and instance method names don't: 
    unless "." = first to-string fun [args: join args obj] 
    apply get fun args 
] 

;---- A class definition ----; 
THIS-CLASS: context [ 
    .class: self       ; the class refers to itself 

    ;---- Class method: create new instance ----; 
    .new: func [x' [integer!] /local obj] [ 
     obj: context [x: x' .class: none] ; this is the object definition 
     obj/.class: self/.class   ; the object will refer to the class 
              ; it belongs to 
     return obj 
    ] 

    ;---- An instance method (last argument must be the instance itself) ----; 
    add: func [y obj] [ 
     return obj/x + y 
    ] 
] 

Dann können Sie dies tun:

;---- First instance, created from its class ----; 
this-object: THIS-CLASS/.new 1 
print invoke this-object 'add [2] 

;---- Second instance, created from from a prototype ----; 
that-object: this-object/.class/.new 2 
print invoke that-object 'add [4] 

;---- Third instance, created from from a prototype in another way ----; 
yonder-object: invoke that-object '.new [3] 
print invoke yonder-object 'add [6] 

;---- Fourth instance, created from from a prototype in a silly way ----; 
silly-object: yonder-object/.class/.class/.class/.class/.new 4 
print silly-object/.class/add 8 silly-object 
print this-object/.class/add 8 silly-object 
print THIS-CLASS/add 8 silly-object 

(Es funktioniert in REBOL 2 und druckt 3, 6, 9, 12, 12, 12 nacheinander.) Kaum Overhead. Wahrscheinlich wird es nicht schwierig sein, ein Dutzend anderer Lösungen zu finden. Genau das ist das eigentliche Problem: Es gibt zu viele Möglichkeiten, es zu tun. (Vielleicht verwenden wir besser LoyalScript.)