I've had some success deploying this .word
as member idea, with a shallow object creation... and it seems like the right fit for many cases--enough so that I think it should be the "default" for what we would traditionally think of as the creation of traditional "objects" and "classes".
But as expected, there are cases that don't fit. For instance, in the bootstrap process, the configuration files make objects that are a bit more like modules:
REBOL [Title: "Filesystem configuration file"]
name: 'Filesystem
source: %filesystem/mod-filesystem.c
os: platform-config.name
if os = 'Windows [ ; means OS as it was just defined...
...
]
This looks module-like, but it's done with objects (in particular because the bootstrap executable doesn't do modules correctly). And additionally, it inherits from a base object.
So when I talk about the "component" operations, we have to consider:
-
What kind of thing are we making (OBJECT!, MODULE!, ERROR!, ...)
-
Is there a parent to inherit from? (if so, we presume this answers 1, which is why MAKE doesn't need to know the type if you pass an instance instead... you can't MAKE ERROR! from a parent that's a MODULE!)
-
Do you want the definitions of the object fields being defined to be visible to the code that's assigning those fields, or do you want the existing bindings to be visible?
With the CONSTRUCT I mention above, that gives you an OBJECT! with no parent...and the fields of the object are not visible to the code doing the assigning. (I propose this as the default behavior for FENCE!.)
I added a CONSTRUCT:WITH to pass in a parent, so you could add a parent...though it would be better if that argument came first
construct:with [
something: ...
...
] parent
vs.
construct:with parent [
something: ...
...
]
I could just go ahead and make it arity-2, though I'm not thrilled by it.
construct object! [...] ; shallow version, no parent
construct parent [...] ; shallow version, parent
make object! [...] ; inside version, no parent
make parent [...] ; inside version, parent
Why would MAKE vs. CONSTRUCT Be "Inside Binding"?
Outside of the inertia of history, I don't know how much sense this makes. It could be construct:inside
vs. plain construct
. :-/
>> x: 10
>> construct [x: 20, y: x + 100]
== #{x: 20 y: 110}
>> x: 10
>> construct:inside [x: 20, y: x + 100]
== #{x: 20 y: 120}
The inside version being implemented by wrap:context
was one idea I had:
>> x: 10
>> wrap:context [x: 20, y: x + 100]
== #{x: 20 y: 120}
What this has going for it:
-
"WRAP" really does sound like it's enclosing the code in a context
-
It aligns with what WRAP does to a BLOCK! normally... this would just say "make me a context out of that, vs. giving a block".
But then you have the other parameterization points... MODULE! vs. OBJECT! etc., and whether you want to inherit or not.
There's simply a lot of parameters here. Anyway, there's a lot of new mechanics that need to settle out while contemplating this, just wanted to write that down.