[REBOL] [constructors] Re: Some other questions
From: joel::neely::fedex::com at: 22-Nov-2003 23:47
Hi, Mike,
Mike Loolard wrote:
> 3) Back on objects:
> objects seem to be pretty neat in REBOL - but I didn't find anything about
> implementing
> and using constructor/destructors ?
>
> I know I could manually add a function that serves as constructor each time
> I create an object, but is that the way REBOL requires it ?
>
You don't need constructors in REBOL. Since REBOL also doesn't have
classes, objects can either be created directly:
tally: make object! [
count: 0
total: 0
put: func [x [number!]] [
total: total + x
count: count + 1
]
get: func [] [
reduce [total total / max count 1]
]
reset: func [] [count: total: 0]
]
or created from a "prototype" object. In this second case, you must
supply a block (possibly empty) of changes or additions. The simplest
case is constructing another object with identical properties:
tally2: make tally []
whose initial values will be based on the current values of the object
used as a prototype.
You can also base a new object on an existing one, but make some changes
in the initial state, add methods/attributes, or change methods.
enr0n: make tally [
total: 1000000
put: func [x [number!]] [
total: total + x + 1000000
count: count + 17
]
]
If you *want* to implement a function that serves as a constructor, you
certainly can, using the above standard capabilities. As OBJECT! is a
first-class data type in REBOL, there's nothing magical about writing a
function which returns an object:
make-tally: func [] [
make object! [
count: 0
total: 0
put: func [x [number!]] [
total: total + x
count: count + 1
]
get: func [] [
reduce [total total / max count 1]
]
reset: func [] [count: total: 0]
]
]
...but that doesn't buy us much. It would be more useful if we had a
small number of attributes that were initialized based on the function's
arguments, but that's just a convenience issue, not a fundamental issue
of REBOL capabilities.
Finally, when I know I will be using multiple similar objects, I have
sometimes put a function within the object itself to provide me with
another, similar object (again just for convenience), as in:
tally: make object! [
count: 0
total: 0
put: func [x [number!]] [
total: total + x
count: count + 1
]
get: func [] [
reduce [total total / max count 1]
]
reset: func [] [count: total: 0]
new: func [/local result] [
result: make self []
result/reset
result
]
]
That way the fresh "instance" is always initialized to some standard
beginning state. Actually, I'd be more likely to write this as:
tally: make object! [
count: 0
total: 0
put: func [x [number!]] [
total: total + x
count: count + 1
]
get: func [] [
reduce [total total / max count 1]
]
reset: func [] [count: total: 0 self]
new: func [] [do in make self [] 'reset]
]
As for "destructors", there's little need in REBOL as memory management
(including garbage collecting) is automatic. If you *want* to add a
method to an object to release big data structures, print final state,
or whatever, you can certainly do so, but you'll have to invoke it for
yourself, as the concept of an automatic call to a finalizer is not
in REBOL.
-jn-