SELFlessness Part 1: SYM_SELF out of binding #185
Closed
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
While billing itself a "language with no keywords" (in the sense of
built-ins to the evaluator), Rebol had a hardcoded hack for the
handling of a feature trying to offer something similar to what languages
might consider a "this" pointer in objects.
The feature was called SELF. As a hint of the hackishness, this is how
SYM_SELF (the symbol ID for the word "self") was hardcoded into the
binding process in R3-Alpha:
https://github.com/rebol/rebol/blob/25033f897b2bd466068d7663563cd3ff64740b94/src/core/c-frame.c#L825
Unlike all other words, SELF did not bind to a key in a context. It bound
to a context but with a special "0" number, indicating no key...but a desire
to retrieve a value representing the context object itself that it was bound to.
Notably this meant it was not possible to assign SELF (specifically, because
var slot 0 was used for a system purpose, and it would crash the system).
It also meant there needed to be a distinction between "selfish" and "selfless"
frames, because not every creation of a new context should bind self.
Otherwise the following code would print out 2 4 6:
This is because for-each needs to create a context "frame" containing just one
key and corresponding variable (for x), and then bind the body to that. If this
context happened to have one of these "invisible self" bindings as well, then it
would also bind self and self/x would be the same meaning as x (instead of
leaving self bound however it was from the enclosing context).
The concept created a distinction that frames were either "selfish" or "selfless",
pushing further complexity into something that was already dubious due to
disrupting the no-keyword paradigm.
This commit contains several adaptations surrounding the elimination of the
SELF hack of R3-Alpha. The end goal is to morph this into a solution that
strongly parallels the implementation strategy of Ren-C's "definitional RETURN",
where SELF is a word that uses the userspace concept of being hidden
(protect/hide) but is nevertheless present in the object as a key, and bound
using ordinary binding with no special symbolic exception or "0 index".
The idea is that
make object! [...]
as a primitive will necessarily make anobject with no SELF (just as in Ren-C a function declared via
make function!
has no RETURN). It will still be possible to get at the "self" by asking for the
bind-of
any bound word inside of the object...and this precise mechanismwill be how generators like OBJECT, CONTEXT, MODULE and others will
implement a "userspace SELF" as protocol.
This first commit is a step toward that, because it starts with adding a hidden
key as being part of what
make object!
does. This creates a significantchange for C code that used hardcoded indices into objects it created,
because formerly what was expected to be an index 1 will now be at index
2...because implementing a SELF now requires another key. As things
evolve, it may be that these objects being indexed into by the system did
not actually need a SELF in the first place. The macro SELFISH() is added
to add one to indices in places where this question can be reviewed.