Concluding on object creation (copy and bind)
Thank you for your comments on earlier articles related to object creation, #239 and #212. (I apologize for repeating myself.)
I've spent the last few days reading your comments and thinking about the issues. Objects are used for a lot of things in REBOL: for structures of raw data, environments of inter-bound data, namespaces such as modules, and prototype-based objects with accessor functions. So, we need many different behaviors from object creation, and no single approach will provide them all.
After reading your comments, here's what I've concluded can be done right away for A80:
- Keep the default MAKE compatible with R2. So, we will not copy sub-objects. This just makes porting easier, and we do want developers moving to R3.
- Change COPY to do a shallow copy of objects. This will be very fast, with no deep copying and no binding. It let's you make a clone of an object with the same references.
- Let COPY/deep deep copy all object fields of all types. Everything is copied, but no binding is done. (Use bind for that.)
Then, I think we should consider these additions for A81:
- Provide a new refinement to COPY that accepts a typeset to indicate what is to be copied. For example, if you want to copy only strings, you specify STRING!. To copy all block types, you'd use the ANY-BLOCK! typeset. (Suggest name of the refinement.)
- Add a spec block to objects. This is a block similar to the spec block of functions or the header blocks of modules. It gives us a way to embed documentation into objects (to show up on HELP), specify a creation init function (that runs as part of MAKE), and specify a typeset for what to copy on MAKE.
The general form of object creation would be:
make object! [spec body]
Note that the form is similar to the low level function creator:
make function! [spec body]
where spec and body are both blocks.
Of course, the classic form would still be accepted; you can still write:
obj0: make object! [
var2: [a block here]
But, if you need more control or want embedded-docs, you write:
obj1: make object! [
title: "Example object"
var2: [a block here]
This will deep copy all series datatypes, rebind all block-related types, and call the internal my-init function at the end of the MAKE.
We could also define a helper function:
object: func [spec body] [
make object! reduce [spec body]
Note that if you don't specify the copy option, then the default copy method occurs (R2-defined.) If you give it a NONE, then no values are copied (a shallow object copy.)
Also, it should be pointed out that the object's spec would be referenced by all derived objects. If you write:
obj2: make obj1 [var3: 123]
the original spec still applies and it is also referenced from obj2. (This might have some implications for MOLD.)
There are a few other options that might make sense.