REBOL3 tracker
  0.9.12 beta
Ticket #0001549 User: anonymous

Project:



rss
TypeBug Statuscomplete Date29-Mar-2010 00:30
Versionalpha 97 CategoryNative Submitted byLadislav
PlatformAll Severitymajor Prioritynormal

Summary Behavior of BIND and IN should be consistent with the binding behavior of the function that created the context
Description The tests below are designed to check whether the behavior of BIND, particularly its binding of 'self, matches the default binding behavior of the code that created the context. They all should print TRUE, but, in A97 the closure test prints FALSE.

When writing code in REBOL it is often useful to explicitly bind blocks of code to the context you are using. If the binding behavior of the BIND and IN functions doesn't match the default binding behavior that the code block of the function, loop, whatever you are working on, uses, then this can lead to hard-to-find errors. And the lack of apparent consistency can make the language look bad, and your code look worse.

This is a case where the importance of consistency with the function that created the context outweighs the inconsistency with the behavior of object! contexts later on.

In R3c-A97 all the tests print TRUE.
Example code
; All these tests should print "true".

; BIND works 'as expected' in object spec
b1: [self]
ob: make object! [
    b2: [self]
    print same? first b2 first bind/copy b1 'b2
]

; BIND works 'as expected' in function body
b1: [self]
f: func [/local b2] [
    b2: [self]
    print same? first b2 first bind/copy b1 'b2
]
f

; BIND works 'as expected' in closure body
b1: [self]
f: closure [/local b2] [
    b2: [self]
    print same? first b2 first bind/copy b1 'b2
]
f

; BIND works 'as expected' in REPEAT body
b1: [self]
repeat i 1 [
    b2: [self]
    print same? first b2 first bind/copy b1 'i
]

Assigned ton/a Fixed inalpha 98 Last Update2-Nov-2010 00:32


Comments
(0002141)
BrianH
29-Mar-2010 18:02

The bug in #447 has been fixed already. The one in #1529 can be fixed using the same method. Please explain what, exactly, is "irreparable" here. And all references to R2 compatibility will be referred to #666; R3 has a different object model.

The general rule here is to either describe in detail what the exact problem is, or provide example code and examples of its use, or both. For bugs, this is preferably with return values that don't do what you want to, and showing what you do want. This is why you see a lot of bugs with copied console sessions with "; should be" in them, or the "Current behavior", "Desired behavior" format.

Just writing out a function and saying that it has "irreparable bugs", without saying what those bugs are, is not enough. And if your description is just a couple of references to other tickets, then this is just a duplicate ticket. If you have something new to add, please do so.
(0002149)
BrianH
30-Mar-2010 01:43

Sorry, the reference to R2 compatibility was in one of your comments. Thanks for adding more code.

You still haven't said exactly *how* #447 is supposed to be not fixed. The best place to say so is in a comment to #447 so that we can decide whether or not to reopen that ticket, but while we're here, I'll hazard a guess that you can confirm or deny.

You appear to have a problem with the fact that closures (and loop functions in #1529) generate objects that have the word 'self in them, like any other object. So you have created a function that works with objects to demonstrate that fact (without showing the results of that function, or saying why they are bad, but that is another point).

Now keep in mind that whether closures (#447) or loop functions (#1529) bind 'self in their code blocks is a completely separate issue from that of whether the objects that they make to store the bindings have the hidden 'self there at all. You can just not bind 'self in those functions, without getting rid of 'self altogether. You can even override the hidden 'self with your own regular 'self field, so if you want to use 'self as a loop variable you can (or even as a closure parameter once #1528 is fixed).

The only thing you can't do if you don't have a hidden 'self field is use IN and BIND properly. To illustrate, let's look at the behavior of function! bindings.

BIND? returns true rather than the object because the contexts aren't supposed to persist.
>> do func [a] [bind? 'a] 1
== true

If you use a function binding with BIND block! word! while the function is running, 'self is not overriden. This is arguably an error, but counts as a gotcha because the behavior of function bindings is known to be weird; you aren't supposed to be doing this kind of thing with them.
>> same? self do func [a] [do bind [self] 'a] 1
== true ; Would expect false, but that is the gotcha

And once the function has returned, the binding is invalid (though with a weird error).
>> do bind [self] do func [a] ['a] 1
** Script error: none word is not bound to a context
** Where: bind
** Near: bind [self] do func [a] ['a] 1

The same would affect IN object! block!, but since BIND? doesn't return the function! binding as an object you can't use IN.

Since you can't use object! to do what you want without breaking a lot of code, let's assume you created a third binding type that direct-binds like object! rather than stack-relative like function! bindings, so it can have indefinite extent, but doesn't have 'self - let's call it selfless! for now. The selfless! type wouldn't be able to be added to any-object! because all types in that typeset are expected to do the 'self unhiding with BIND block! any-object! and IN any-object! block!.

So to make it possible to use selfless! with BIND, we would need to implement the #1543 or #1544 mode trick - let's go with #1544 (BIND/self). If you BIND block! selfless! there would be no 'self unhiding, same as with BIND block! any-object!. And BIND/self block! selfless! would trigger an error. At least then we could fix the function! binding gotcha mentioned above: function! bindings would also cause BIND/self to trigger an error - that's a plus.

So if you have a selfless! type, this leads to three questions:
- What advantages does selfless! have over any-object! bindings?
- When would it be appropriate to use selfless! and why?
- Are these advantages sufficient to justify the additional choice that developers have to make when writing their code? The any-object! vs. selfless! choice would be comparable to the none! vs. unset! choice developers have to deal with now.
(0002155)
BrianH
30-Mar-2010 03:31

However, your changed summary is accurate now. Your DO-IN function demonstrates a problem with BIND, though your example code doesn't. BIND block! word! should reliably override the word 'self in the block every time (until #1544 is implemented), and in the case where it is passed a word bound to a function! context it doesn't. That is a significant problem.
(0002157)
giesse
30-Mar-2010 10:22

(Gabriele here)

I still don't understand, why we need to add special treatment of 'self, and exceptions to BIND, when it would be much easier to make CONTEXT! first class instead.

I'm also not convinced that it is that important to protect 'self, but I guess YMMV.
(0002159)
abolka
30-Mar-2010 22:59

Brian:
> So if you have a selfless! type, this leads to two questions:
> - What advantages does selfless! have over any-object! bindings?

selfless! is the simpler approach as it does not induce special self treatment in BIND. selfless! is easier to explain. selfless! captures the essence of a context (that's why it should probably be called context!): a "binding environment", without bolted-on magic to support a particular implementation of an object system.

> - When would it be appropriate to use selfless! and why?

Always use selfless! The question would rather be: when would it be appropriate to _not_ use selfless! and why? And this is of course quickly answered: the more feature-rich object! should only be used for the object system provided as part of standard R3.

All function contexts, loop contexts, etc would use selfless!. Different object system implementations would probably also use selfless! (along with bind and maybe protect).
(0002164)
BrianH
31-Mar-2010 20:33

The only consistency that matters for BIND/self (just using this term to refer to BIND with the 'self trick, the current definition of BIND for R3) is that 'self should be bound, every time, or the function should trigger an error. That is currently not the case with function! bindings, so BIND/self is not reliable. And BIND/no-self (referring to BIND without the 'self trick) is not available in R3 yet, so we can't tell how reliable it is.

Gabriele, the reason for making 'self hidden was to prevent unintentional cycles when referring to the fields of an object (which R2 was prone to). And the reason to protect 'self from modification is part of many changes to R3 relative to R2 to make it easier to run untrusted code; this was never a problem in R2 because it was so impractical to run untrusted code that people just didn't do it. And you are right, if we completely give up that security aspiration and stick with what you could do in R2 then this whole thing would be unnecessary.

But if we have the hidden/non-modifiable 'self in objects (for the above reasons) then adding the selfless! type would not affect that in any way whatsoever: We would still need to do the same stuff for any-object! types. So what does selfless! add?
(0002260)
BrianH
27-Apr-2010 10:11

Gabriele, it was later revealed that the 'self context reference in objects is implicit in R3: It takes no space in the object, and thus has no value slot to set to another value. So 'self is not protected, so much as not there at all. And 'self is not hidden, then unhidden by BIND: It's a keyword of BIND and IN when they are binding a block, but otherwise not there at all.

So what Ladislav is requesting is that based on a hidden flag of an object that you can't set in current object syntax (impossible now, see #1437 for why, but there is a proposal to change object syntax in a way that would coincidentally allow this) - or for another object-like datatype (possible) - that BIND and IN not use the 'self keyword. But that they should use the 'self keyword for regular objects. And that this choice should be made by the person (or function) who created the object, not the person (or function) who is providing the block of code that has the actual keyword in it that would be affected by the choice.

Pardon the paraphrasing, Ladislav, but the previous phrasing doesn't reflect the new information about how 'self is actually implemented.
(0002269)
BrianH
28-Apr-2010 22:30

Added the code that Ladislav wrote in http://www.rebol.net/cgi-bin/r3blog.r?view=0312#comments that does a better job of expressing his philosophical point (thanks, Ladislav!).

Here are some tests also taken from there (with closure added) that express the practical effects:

; Objects
ob: object []
print same? ob do bind [self] ob
print same? ob do in ob [self]

; Objects created with CONSTRUCT
ob: construct []
print same? ob do bind [self] ob
print same? ob do in ob [self]

; Objects created with CONSTRUCT/only
ob: construct/only []
print same? ob do bind [self] ob
print same? ob do in ob [self]
; Should CONSTRUCT/only generate selfless contexts?

; CONSTRUCT should reserve 'self, same as MAKE object!
print error? try [construct [self: 1]]
print error? try [construct/only [self: 1]] ; see above

; Functions
ob: object [f: func [/x] [do bind/copy [self] 'x]]
print same? ob ob/f
; Can't use the context after the function returns.
; This is not a side effect of Ladislav's proposal.

; Functions with a 'self parameter (#1528)
ob: object [f: func [/self] [do bind/copy [self] 'self]]
print not same? ob ob/f

; Closures (#447)
ob: do closure [x] [bind? 'x] 1
print 1 = ob/x
print not same? ob do bind [self] ob
print not same? ob do in ob [self]

; Closures with a 'self parameter (#1528)
ob: do attempt [closure [self] [bind? 'self]] 1
print 1 = attempt [ob/self]
print not same? ob do bind [self] ob
print not same? ob do in ob [self]

; Closures shouldn't bind 'self unless it is a parameter (#447)
print same? self do closure [x] [self] 1
print not same? self do attempt [closure [self] [self]] 1

; Loops (#1529)
ob: repeat x 1 [bind? 'x]
print 1 = ob/x
print not same? ob do bind [self] ob
print not same? ob do in ob [self]

; Loops with a 'self variable (#1529)
ob: repeat self 1 [bind? 'self]
print 1 = attempt [ob/self]
print not same? ob do bind [self] ob
print not same? ob do in ob [self]

; Loops shouldn't bind 'self unless it's a variable (#1529)
print same? self repeat x 1 [self]
print not same? self repeat self 1 [self]

All print statements should print "true". Note that no errors are triggered by BIND, in contrast to the #1543 and #1544 proposals. See also #1552.
(0002730)
Ladislav
1-Nov-2010 15:57

in the core-tests suite

Date User Field Action Change
2-Nov-2010 00:32 BrianH Status Modified tested => complete
1-Nov-2010 15:57 Ladislav Comment : 0002730 Added -
7-May-2010 17:38 Ladislav Summary Modified Behavior of BIND and IN should be consistent with the binding behavior of the code that created the context => Behavior of BIND and IN should be consistent with the binding behavior of the function that created the context
7-May-2010 17:36 Ladislav Summary Modified Behavior of BIND and IN should be consistent with the binding behavior of the function the context came from => Behavior of BIND and IN should be consistent with the binding behavior of the code that created the context
6-May-2010 08:41 BrianH Status Modified submitted => tested
6-May-2010 08:41 BrianH Category Modified Unspecified => Native
6-May-2010 08:41 BrianH Fixedin Modified => alpha 98
6-May-2010 08:41 BrianH Description Modified -
6-May-2010 08:41 BrianH Summary Modified BIND result does not look like the provided specimen block in closures. => Behavior of BIND and IN should be consistent with the binding behavior of the function the context came from
29-Apr-2010 01:27 BrianH Comment : 0002269 Modified -
29-Apr-2010 01:27 BrianH Comment : 0002269 Modified -
28-Apr-2010 23:49 Ladislav Summary Modified BIND result does not look like the provided specimen in some contexts. => BIND result does not look like the provided specimen block in closures.
28-Apr-2010 23:48 Ladislav Description Modified -
28-Apr-2010 23:47 Ladislav Code Modified -
28-Apr-2010 23:47 Ladislav Description Modified -
28-Apr-2010 23:47 Ladislav Summary Modified DO-IN like functions do not work reliably in R3 => BIND result does not look like the provided specimen in some contexts.
28-Apr-2010 23:42 BrianH Comment : 0002269 Modified -
28-Apr-2010 23:41 Ladislav Comment : 0002192 Removed -
28-Apr-2010 23:41 Ladislav Comment : 0002161 Removed -
28-Apr-2010 23:41 Ladislav Comment : 0002160 Removed -
28-Apr-2010 23:41 Ladislav Comment : 0002148 Removed -
28-Apr-2010 23:41 Ladislav Comment : 0002146 Removed -
28-Apr-2010 23:41 Ladislav Comment : 0002140 Removed -
28-Apr-2010 23:41 Ladislav Comment : 0002139 Removed -
28-Apr-2010 23:22 BrianH Comment : 0002269 Modified -
28-Apr-2010 23:08 BrianH Comment : 0002269 Modified -
28-Apr-2010 22:57 BrianH Comment : 0002269 Modified -
28-Apr-2010 22:50 BrianH Comment : 0002269 Modified -
28-Apr-2010 22:30 BrianH Comment : 0002269 Added -
28-Apr-2010 22:15 BrianH Code Modified -
27-Apr-2010 10:17 BrianH Comment : 0002260 Modified -
27-Apr-2010 10:11 BrianH Comment : 0002260 Added -
5-Apr-2010 23:10 Ladislav Comment : 0002192 Modified -
5-Apr-2010 23:02 Ladislav Comment : 0002192 Added -
1-Apr-2010 12:23 Ladislav Code Modified -
1-Apr-2010 12:18 Ladislav Code Modified -
1-Apr-2010 12:16 Ladislav Code Modified -
1-Apr-2010 12:15 Ladislav Code Modified -
31-Mar-2010 20:46 BrianH Comment : 0002164 Modified -
31-Mar-2010 20:33 BrianH Comment : 0002164 Added -
31-Mar-2010 11:59 Ladislav Code Modified -
31-Mar-2010 11:56 Ladislav Code Modified -
31-Mar-2010 07:47 Ladislav Comment : 0002161 Modified -
31-Mar-2010 07:42 Ladislav Comment : 0002161 Modified -
31-Mar-2010 07:38 Ladislav Comment : 0002161 Added -
31-Mar-2010 07:32 Ladislav Comment : 0002160 Added -
31-Mar-2010 07:21 Ladislav Description Modified -
30-Mar-2010 23:04 abolka Comment : 0002159 Modified -
30-Mar-2010 23:01 abolka Comment : 0002159 Modified -
30-Mar-2010 23:00 abolka Comment : 0002159 Modified -
30-Mar-2010 22:59 abolka Comment : 0002159 Added -
30-Mar-2010 20:05 Ladislav Description Modified -
30-Mar-2010 11:01 Ladislav Severity Modified minor => major
30-Mar-2010 11:00 Ladislav Severity Modified major => minor
30-Mar-2010 10:22 giesse Comment : 0002157 Added -
30-Mar-2010 03:33 BrianH Comment : 0002155 Modified -
30-Mar-2010 03:31 BrianH Comment : 0002155 Added -
30-Mar-2010 01:49 BrianH Comment : 0002149 Modified -
30-Mar-2010 01:43 BrianH Comment : 0002149 Added -
29-Mar-2010 23:49 Ladislav Summary Modified The DO-IN function has "irreparable" bugs => DO-IN like functions do not work reliably in R3
29-Mar-2010 23:47 Ladislav Comment : 0002148 Added -
29-Mar-2010 19:28 Ladislav Comment : 0002146 Modified -
29-Mar-2010 19:26 Ladislav Code Modified -
29-Mar-2010 19:21 Ladislav Comment : 0002146 Modified -
29-Mar-2010 19:21 Ladislav Comment : 0002146 Modified -
29-Mar-2010 19:20 Ladislav Comment : 0002146 Modified -
29-Mar-2010 19:19 Ladislav Comment : 0002146 Modified -
29-Mar-2010 19:18 Ladislav Comment : 0002146 Modified -
29-Mar-2010 19:17 Ladislav Comment : 0002140 Modified -
29-Mar-2010 19:13 Ladislav Comment : 0002146 Added -
29-Mar-2010 19:09 Ladislav Description Modified -
29-Mar-2010 19:06 Ladislav Description Modified -
29-Mar-2010 19:03 Ladislav Code Modified -
29-Mar-2010 19:03 Ladislav Description Modified -
29-Mar-2010 18:26 BrianH Comment : 0002141 Modified -
29-Mar-2010 18:17 BrianH Comment : 0002141 Modified -
29-Mar-2010 18:03 BrianH Comment : 0002141 Modified -
29-Mar-2010 18:02 BrianH Comment : 0002141 Added -
29-Mar-2010 11:48 Ladislav Comment : 0002140 Modified -
29-Mar-2010 11:43 Ladislav Comment : 0002140 Modified -
29-Mar-2010 11:40 Ladislav Comment : 0002140 Modified -
29-Mar-2010 11:40 Ladislav Comment : 0002140 Modified -
29-Mar-2010 11:38 Ladislav Comment : 0002140 Modified -
29-Mar-2010 11:38 Ladislav Comment : 0002140 Added -
29-Mar-2010 11:36 Ladislav Comment : 0002139 Modified -
29-Mar-2010 11:35 Ladislav Description Modified -
29-Mar-2010 11:32 Ladislav Comment : 0002139 Modified -
29-Mar-2010 11:32 Ladislav Comment : 0002139 Modified -
29-Mar-2010 11:31 Ladislav Code Modified -
29-Mar-2010 11:29 Ladislav Comment : 0002139 Modified -
29-Mar-2010 11:27 Ladislav Comment : 0002139 Added -
29-Mar-2010 11:20 Ladislav Severity Modified minor => major
29-Mar-2010 11:20 Ladislav Code Modified -
29-Mar-2010 00:30 Ladislav Ticket Added -