Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SELFlessness Part 1: SYM_SELF out of binding #185

Closed
wants to merge 1 commit into from
Closed

SELFlessness Part 1: SYM_SELF out of binding #185

wants to merge 1 commit into from

Conversation

hostilefork
Copy link
Member

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:

for-each x [1 2 3] [print self/x + x]

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 an
object 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 mechanism
will 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 significant
change 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.

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

    for-each x [1 2 3] [print self/x + x]

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 an
object 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 mechanism
will 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 significant
change 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.
@hostilefork
Copy link
Member Author

Note that calling this "selflessness part 1" isn't entirely true as getting to the point of even being able to think about doing this required quite a lot of groundwork.

@hostilefork
Copy link
Member Author

I mentioned that Red is following in R3-Alpha's footsteps, and for those curious here are the lines:

@hostilefork
Copy link
Member Author

Rebased and merged.

@hostilefork hostilefork deleted the self-out-of-bind branch December 14, 2015 06:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant