2013-10-07 15 views
7

Di solito programma per funzioni in modo "istintivo", ma il mio problema corrente può essere facilmente risolto dagli oggetti, quindi procedo con questo metodo.c'è un costruttore di oggetti in rebol

In questo modo, sto cercando di trovare un modo per assegnare a un oggetto un metodo di costruzione, l'equivalente di init() in python, ad esempio.

Ho cercato nella documentazione http://www.rebol.com/docs/core-fr/fr-index.html, ma non ho trovato nulla di rilevante.

risposta

3

In realtà, leggendo di nuovo la documentazione Rebol Nucleo (ho appena seguito il buon vecchio consiglio: "leggere il manuale francese"), c'è un altro modo per implementare un costruttore, piuttosto semplice:

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

Naturalmente è anche nel Manuale inglese:

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

=>

0.123.516,41 mila

Un altro esempio di utilizzo della variabile sé è una funzione che clona stessa:

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 

Trovo che questo sia molto comodo, e in questo modo, il costruttore si trova all'interno dell'oggetto. Questo fatto rende l'oggetto più autosufficiente.

ho implementato che con successo per alcune cose geologico, e funziona bene:

>> 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 

Un altro vantaggio di questo modo è che le variabili definite dal metodo "nuovo" appartiene direttamente alla "istanza" oggetto (Mi sono imbattuto in qualche problema, con gli altri metodi, dovendo menzionare se stessi/a volte, dover inizializzare le variabili o no).

6

Non v'è alcuna funzione speciale costruttore in Rebol, ma v'è la possibilità di scrivere ad hoc codice init se ne avete bisogno sulla creazione dell'oggetto nel spec blocco. Per esempio:

a: context [x: 123] 

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

Quindi, se si definisce una propria funzione "costruttore" per convenzione in oggetto di base, si può chiamare il blocco specifiche sulla creazione. Se si vuole rendere automatica, si può avvolgere che in una funzione, come questo:

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

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

b: new-a 456 

Una più robusta (ma un po 'più a lungo) versione di nuovo un che permetterebbe di evitare la possibile collisione di argomenti passati a init con le parole dello stesso oggetto sarebbe:

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

si potrebbe anche scrivere un più generico nuova funzione che avrebbe preso un oggetto di base come primo argomento e richiamare automaticamente una funzione di costruzione-by-convenzione dopo clon l'uso dell'oggetto, ma supportare gli argomenti facoltativi del costruttore in modo generico è quindi più complicato.

Ricordate che il modello a oggetti di Rebol è basato sui prototipi (vs basato su classi in Python e molti altri linguaggi OOP), quindi la funzione "costruttore" ottiene duplicati per ogni nuovo oggetto creato. Potresti voler evitare tali costi se stai creando un numero enorme di oggetti.

+0

Sì, entrambi si ritrovano con soluzioni molto simili. init o nuovo? questa è la domanda, per denominare il metodo di costruzione ... Ovviamente, se una grande quantità di oggetti deve essere generata, tali metodi dovrebbero essere assolutamente evitati. Nella mia attuale problematica, in realtà stavo pensando a qualche oggetto, nemmeno a una dozzina. – Pierre

5

A mia conoscenza, non esiste un metodo/convenzione formale per l'utilizzo di costruttori di oggetti come init(). V'è naturalmente il metodo incorporato di costruire oggetti derivati:

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

mio miglior suggerimento sarebbe quello di definire una funzione che controlla un oggetto per un metodo di costruzione, quindi applica tale metodo, qui è una tale funzione che 've 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]] 
      ] 
     ] 
    ] 
] 

l'utilizzo è molto semplice: se un oggetto prototipo ha un valore new, allora sarà applicata nella costruzione dell'oggetto derivato:

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

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

nota che questo approccio funziona sia in Rebol 2 che in 3.

+0

ok: tutto ciò di cui abbiamo bisogno, quindi, è una convenzione appropriata per un metodo di costruzione in un oggetto, se necessario. – Pierre

3

Sto cercando di scoprire come funziona OO in REBOL. Prototipico davvero. Ieri mi sono imbattuto in questa pagina, che mi ha ispirato al modello OO classica di seguito, senza duplicazione di funzioni:

;---- 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 
    ] 
] 

Poi si può fare questo:

;---- 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 

(Funziona in REBOL 2, e stampa 3, 6, 9, 12, 12, 12 successivamente.) Quasi nessun sovraccarico. Probabilmente non sarà difficile trovare una dozzina di altre soluzioni. Esattamente questo è il vero problema: ci sono troppi modi per farlo. (Forse è meglio usare LoyalScript.)

Problemi correlati