r3wp [groups: 83 posts: 189283]
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

World: r3wp

[Core] Discuss core issues

BrianH
16-Aug-2011
[2144x2]
Yup. The reason that CONTEXT currently doesn't copy is the same as 
why MODULE doesn't copy: They are generally used for one-off creations, 
based on large specs that are rarely reused, and inefficient to deep-copy. 
We could easily make them copy, but it would continue to be a bad 
idea for those reasons.
The FUNC used to load the mezzanine functions at startup doesn't 
copy either, for the same efficiency reasons.
Ladislav
16-Aug-2011
[2146]
Hmm, I doubt it is needed
BrianH
16-Aug-2011
[2147x2]
Doing it that way shrinks the startup time and memory quite a bit. 
There's a lot of the loading process that is dedicated to reducing 
code copying.
This is also why that while most of the large mezzanine functions 
are written using FUNCT, the actual mezzanine build process converts 
those definitions to calls to the non-copying FUNC, with no preprocessing 
or copying needed at startup time. The user-level mezzanine FUNC 
is copying for safety reasons though.
Gregg
16-Aug-2011
[2149]
We all know you can make REBOL do just about anything. We also know 
there are a few things that trip people up (e.g. copying series values 
defined in funcs). My questions for John are: 


1) Has this behavior ever been behind a bug in any of your REBOL 
code? If so, what was the context and what was the impact (e.g., 
how did you work around it)?


2) If you got your wish, what would the consequences be? i.e., how 
would it change REBOL?
Geomol
17-Aug-2011
[2150x2]
More confusion?

>> body: [a + b]
== [a + b]
>> f: make function! [a b] body
>> pick :f 2
== [a + b]
>> same? body pick :f 2
== false
>> insert body '-
== [a + b]
>> body
== [- a + b]
>> pick :f 2
== [a + b]
>> f 1 2
== 3


To me, MAKE function! seem to copy the body block. What are the arguments, 
that the body block isn't copied?
Gregg, I get back to you, as answering your questions might take 
this into another direction.
Gabriele
17-Aug-2011
[2152]
Geomol, it's not make that copies the function body, it is pick. 
that was added for "security" reasons. blame Brian for this sort 
of things. :P
Geomol
17-Aug-2011
[2153x2]
Gabriele, that can't be true. See:

>> b: [a]
== [a]
>> blk: []
== []
>> insert/only blk b
== []
>> blk
== [[a]]
>> same? b pick blk 1
== true
(Notice this is the "Core" group, not the "!REBOL3" group, and I'm 
talking R2.)
Ladislav
17-Aug-2011
[2155]
Gregg: "1) Has this behavior ever been behind a bug in any of your 
REBOL code? If so, what was the context and what was the impact (e.g., 
how did you work around it)?" - you should not have asked this question, 
since the answer is already present above
Gabriele
17-Aug-2011
[2156x4]
Geomol, I meant PICK when done on a function! value.
ok, no, you're right and that was R3. R2 copies on make function!. 
to me, *this* is a bug. or rather, either make should always copy 
or it should never do it. having exceptions is silly.
(note, exceptions are added to make people happy wrt to "bugs" like 
the one you described above. the result is more confusion imho.)
(always copy would make sense only if rebol could do copy on write 
- which is a bit tricky. given the way rebol works "never copy" makes 
much more sense, then you add copy to helpers like FUNC etc. Then, 
we can discuss whether CONTEXT should have a copy, and imho it should 
not because this "bug" never happens in practice.)
Ladislav
17-Aug-2011
[2160x3]
'this "bug" never happens in practice' - that is actually false
Moreover, it is silly, that all helpers copy, but CONTEXT does not, 
isn't it?
;-)
Geomol
17-Aug-2011
[2163x7]
Ok, now we're getting somewhere. A question is raised, if MAKE should 
copy arguments given to it. This isn't the bug, as I see it, and 
I'll explain that a bit later.


But first, if MAKE disn't copy the body block when making a function, 
then we would be able to change the function by changing the original 
block. Like:

>> b: []   
== []
>> f: make function! [] b
>> f
>> insert b 42
== []
>> f


After the last call to f, we would get the result 42, if the body 
block wasn't copied. This is not desirable to me. Is it to you guys?
Then the MAKE object! . The block given to make this time is also 
copied, as this shows:

>> b: [a: 1]
== [a: 1]
>> o: make object! b
>> third :o     
== [a: 1]
>> same? b third :o
== false
>> append b [c: 2]
== [a: 1 c: 2]
>> third :o
== [a: 1]


So the block is copied, and then that's not the reason, the example 
from Ladislav's Bindology returns "bug".
Let's look at the example again. My version of the example is this:

f: func [x] [
    get in make object! [
        a: "ok"
        if x = 1 [
            a: "bug!"
            f 2
            a: "ok"
        ]
    ] 'a
]

I can pick the inner-most block this way:

>> b1: pick pick pick :f 2 5 7
== [
    a: "bug!" 
    f 2 
    a: "ok"
]

Now I run the example and pick the block again:

>> b2: pick pick pick :f 2 5 7
== [
    a: "bug!" 
    f 2 
    a: "ok"
]
>> same? b1 b2
== true

It's the same block.
I ran the example before b2 was picked with:

>> f 1
== "bug!"


So, running the example, which makes the object doesn't change the 
block (other than binding) and MAKE object! makes a copy of the block. 
The conclution to me is, that MAKE rebinds the block before copying 
it, where it should do that after making its copy, andt that is a 
bug.
Sorry for a couple of long posts, but this takes room to explain.
Also, if MAKE object! didn't copy the block argument, then the code 
in the block would still be in the object, and this is not desirable. 
That is, the object would hold all this information:

[
    a: "ok" 
    if x = 1 [
        a: "bug!" 
        f 2 
        a: "ok"
    ]
]

Instead of just [a: 1].
Sorry, instead of just [a: "ok"].
Ladislav
17-Aug-2011
[2170x4]
MAKE object! makes a copy of the block

 I gave a proof it does not make a copy. Interesting, how much you 
 try to reinvent the wheel, taking into account, that the correct 
 explanation to your results is available from public sources.
A copy of the MAKE OBJECT! block is actually never made, as this 
example shows:

b: [a: 1 "this is the block"]
o: make object! b
third o


good luck with reinventing the wheel instead of reading publicly 
availalbe sources that explain what is going on
The fact is, that the object does not "store" any block, only the 
THIRD function tries to "create" something like that
That can be easily proven by examining:

same? third o third o
Geomol
18-Aug-2011
[2174x4]
Cool, thanks! This is complicated! :)
So we're back to, it isn't a bug, that MAKE doesn't copy the block, 
when making objects. It's intended behaviour. And MAKE does copy 
the block, when making functions, and that is intended behaviour 
too. And the SECOND function doesn't try to create a block, when 
used on functions:

>> f: does []
>> same? second :f second :f
== true

while THIRD does do that, when used on objects.
Gregg, about your questions.


1) Has this behavior ever been behind a bug in any of your REBOL 
code? If so, what was the context and what was the impact (e.g., 
how did you work around it)?


I guess, you mean series inside functions. I'm not for everything 
should do a copy, as Gabriele imply. The problem with series in functions 
is only a problem, because functions in REBOL isn't functions in 
the traditional understanding. They are semi-closures. If they were 
functions, the local values would just be on the stack. Because the 
locals live on, this was a problem for me years ago. First I solved 
it by putting COPY in series definitions, then I in many cases changed 
to just do a CLEAR, like in:

local-block: clear []


Now with the discovered behaviour regarding objects, I find the binding 
rules so complicated, that I would forget, how it works in two weeks. 
I will remember, that I have to be very careful, when making objects 
inside functions, especially if it's recursive functions. The consequence 
for me is, that I will probably put COPY/DEEP in, when making objects. 
As I won't start new big projects in REBOL, I will probably not do 
this a lot in practice.
The second question was:


2) If you got your wish, what would the consequences be? i.e., how 
would it change REBOL?


When making an object in REBOL, I think of it as making a context. 
When making a function, I also assiciate this with making a context. 
If the rules were somehow similar regarding the two different contexts, 
it would be easier or more "simple", as I see it.


If your question was about binding, that I suggest blocks should 
define the binding and not each word, then that's a change, I find 
interesting but can't see the full consequences of. I think, it would 
work, and work well.
Ladislav
18-Aug-2011
[2178x5]
And MAKE does copy the block, when making functions, and that is 
intended behaviour too.
 - not exactly, in R3 it does not
 And the SECOND function doesn't try to create a block, when used 
 on functions:
 - again, not exactly, in R3 this has changed
On the other hand, it is not hard to understand why the THIRD function 
creates the block: there is no other option, since the block is not 
available from anywhere, so it *has to* create it
...Because the locals live on, this was a problem for me years ago. 
First I solved it by putting COPY in series definitions...

 - sorry to chime in, but I simply have to. The issues you mention 
 (series in functions, extent of function locals) are not related. 
 For example, the extent of function locals has changed a bit in R3, 
 while the issue with series remains unchanged.
I can easily prove, that the extent of function locals is immaterial, 
when the behaviour of series in functions is examined.
Gabriele
18-Aug-2011
[2183x2]
that all helpers copy

 - in R3? Yeah, maybe the all should, though I still prefer to be 
 practical here. i've never had to copy the block passed to context 
 for eg.
So the block is copied

 - your conclusion is wrong. the object does not "keep" the block 
 it is made from. THIRD simply generates its output each time.
Geomol
18-Aug-2011
[2185]
Yeah, I discovered that. Confusing, I think.
Ladislav
18-Aug-2011
[2186x4]
i've never had to copy the block passed to context for eg.
 - many people never had, but:

* Cyphre fell into "the trap" when writing async code

* the code written for R3GUI has to use copying due to the way how 
it is implemented
The issue has been demonstrated on recursive code, since that is 
the simplest case, but the async code is more likely to suffer
In my opinion, when we have two possible ways: MAKE OBJECT! and CONTEXT, 
it is practical if they differ in their properties to offer some 
flexibility.
Regarding the "MAKE FUNCTION! does not copy" versus the "BODY-OF 
function does copy" there are very good reasons why this is the best 
alternative:


1) MAKE FUNCTION! is a "lower level" approach, which should give 
the greatest flexibility. Such flexibility is achieved by not copying 
the body, which allows a custom function generator using MAKE FUNCTION! 
to make some additional adjustments to the function after the function 
has been created by MAKE FUNCTION!. An example code using this advantage 
has been committed by me to rebol.org.


2) Since the BODY-OF function does copy, a user may give a "sensitive" 
function as an argument to a "less trusted" code without having to 
fear that the "less trusted" code would modify it to achieve undesirable 
effects. This is highly practical, and not a limitation, since the 
"original body" of the function can be made available if the creator 
of the function wishes.
Geomol
18-Aug-2011
[2190]
What about MAKE block! ? Does that include a copy? Will it in R3?
Gregg
19-Aug-2011
[2191]
John, it sounds like where you get confused, or think of things as 
bugs or design flaws, is when having your REBOL "That's funny!" moments, 
borne of deep tinkering. Aside from the "copy series in funcs" behavior, 
which I think bites many people at some point, your issues don't 
come from writing application code in REBOL and bumping up against 
REBOL's behavior. Rather, it seems that REBOL's implementation and 
design don't match your expecations in these cases, and you really 
want it to. :-)


The reason I asked about consequences is because you may want a change 
that affects other users negatively. Imagine REBOLers as being in 
one of two groups. Group A is the gurus. They have internalized REBOLs 
design, understand it deeply, and use BIND and recursive PARSE rules 
without fear. That group is very small. Group C contains everybody 
else, which includes people that don't know about using /local with 
funcs, and suggest REBOL should use  = for "assignment". They have 
never used USE, BIND, or many other functions, because they aren't 
sure how they work. Some of them know a little about series references, 
so they always use COPY to be safe. (Yes, group B exists too, but 
they are much more like C than A).


If REBOL were meant only for A users, it would be very different. 
As a designer, it seems pragmatic to make it so things work well 
for the B and C users who, when they hit a problem that requires 
advanced understanding, will work around issues with the bits they 
understand (and adding many COPY calls), no matter how inelegant. 
Group A users may suffer at their expense, but I'm OK with that, 
because I'm not one of them.
Geomol
19-Aug-2011
[2192]
When I go into discussion like this, it's mostly because I want to 
understand, what REBOL is. After using it for like 10 years, there 
are still areas, where I'm not sure, what's intentional and what 
isn't. Must of the problem (of understanding the REBOL behaviour) 
is because it's not officially well documented. ("Officially" I mean 
by Carl.) REBOL is still not set in stone, as I see it.
Ladislav
19-Aug-2011
[2193]
What about MAKE block! ? Does that include a copy? Will it in R3?
 - this is a funny question. The

    make block! []


expression does make a copy of the block given, both in R2 and in 
R3. The reason is quite simple: if it did not make a copy of its 
argument it would not make a block at all.