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

World: r3wp

[Core] Discuss core issues

Geomol
15-Aug-2011
[2120x2]
then call it design flaw


When I first saw it, I didn't know, it was intentional behaviour. 
To me, it looked clearly as a bug, so I called it a bug.
Gabriele, if we continue with design flaws related to binding, the 
following is to me in that category:

>> blk: [x]
== [x]
>> x: 1
== 1
>> context [x: 2 append blk 'x]		; 1st alternative x

>> use [x] [x: 3 append blk 'x]		; 2nd alternative x just to show 
different ways to do this
== [x x x]
>> blk
== [x x x]
>> reduce blk
== [1 2 3]


I came to think of this from your comment on scope. To me, REBOL 
does have scope, it's just different from most languages. In REBOL, 
every word belong somewhere, and three times the same word in a block 
can belong to three different places. That's the scoping rules. Now 
I want to save and load that block:


>> save/all %/tmp/ex1.r blk	; using /all , even if it makes no difference 
here, but this questions /all, doesn't it?
>> blk: load %/tmp/ex1.r
== [x x x
]
>> reduce blk
== [1 1 1]


So doing that changes everything. This design flaw (you may call 
it a "design feature") can be the cause of so much confusion and 
program failures, that I might even call it a "bug". ;)
Ladislav
15-Aug-2011
[2122]
'This design flaw (you may call it a "design feature") can be the 
cause of so much confusion and program failures, that I might even 
call it a "bug". ;)' - that is (IMO) neither of "design flaw", "design 
feature", "bug". I think, that it is a problem, which you might help 
to solve if you come with a good idea ;-)
Geomol
15-Aug-2011
[2123]
Typing into the console (REBOL prompt) can be considered the same 
as appending to a block. If I type the same word several times, each 
has the same meaning. So the block should define the binding, not 
each word.
Ladislav
15-Aug-2011
[2124x5]
Aha, so you do not want to suggest any LOAD/MOLD changes, you want 
to have C
But, how that can help you with the above issue is a mystery
Example:

x: 1
blk: []
context [x: 2 append append blk 'x 'x]
reduce blk ; == [2 2]
reduce load mold blk ; == [1 1]
(and that is not the only way how to run into trouble)
So, good luck with that!
Geomol
16-Aug-2011
[2129]
In your last example here, blk is created outside the context block. 
What I suggest is, that when you append x to blk, it doesn't matter, 
where you do that. The block defines the binding. So reducing blk 
in your example should give [1 1], and reduce load mold blk should 
also give [1 1]. Appending words to a block should mean that: appending 
words.
Ladislav
16-Aug-2011
[2130]
Just being curious how does the "the block defines the binding" apply 
to the following?


dr: func [block /local r] [r: copy [] foreach sb block [append/only 
r reduce sb]]
x: 1
blk: [[x]]
context [x: 2 append/only blk [x]]
use [x] [x: 3 append/only blk [x]]
blk
dr blk
dr load mold blk
Steeve
16-Aug-2011
[2131]
- "The block defines the binding".
It's against Rebol's first law. 
AFAIK binding (context) is a property of words. Series have not.
Gabriele
16-Aug-2011
[2132x6]
the consequence of such complicated rules

 - I don't understand where the complication is. Should writing a: 
 [...] also do a copy? Should everything do a copy? You're arguing 
 that sometimes REBOL should copy things, sometimes not. *That* is 
 a list of complicated rules.
most programmers will put in COPY/DEEP many places in the code in 
front of blocks.
 - how many programs on rebol.org do this?
BIND modifying the block is a useful feature at times. For example, 
the copy that has been added "for security reasons" in many places 
makes a number of "tricks" harder to do.
To me, REBOL does have scope, it's just different from most languages.

 - oh well, of course you are free to change the definition of  the 
 word "scope" so that it fits REBOL... lol.
MOLD missing words context: where did I ever say this was a feature? 
As Ladislav said, this is just a non-trivial problem, because to 
solve it you may have to save the whole interpreter state. (One of 
your X there is bound to system/words, if you save that you basically 
save everything.)
So the block should define the binding, not each word.
 - that kills dialecting.


Geomol, really, have a look at Scheme. It works exactly like you 
want... REBOL works differently for a reason.
Geomol
16-Aug-2011
[2138]
Ladislav, if you try follow my thoughts, you can figure that out 
yourself.


Steeve, maybe that law is a design flaw, that causes many problems? 
Like the example returning "bug", which started much of this conversation.


Gabriele, ... Gabriele, you strengten my tolerance, and thank you 
for that. "that kills dialecting" I've seen you writing that before, 
and it puzzles me every time. (Well, probably different understanding 
again.) Thank you for suggesting Scheme, but I don't have time to 
dig into a new language right now.

Should we let it rest?
Ladislav
16-Aug-2011
[2139]
Ladislav, if you try follow my thoughts, you can figure that out 
yourself.
 I cannot, but nevermind
Geomol
16-Aug-2011
[2140]
Gabriele, it hard to have a conversation, when you go to extremes 
like in the following:


I don't understand where the complication is. Should writing a: [...] 
also do a copy? Should everything do a copy? You're arguing that 
sometimes REBOL should copy things, sometimes not. *That* is a list 
of complicated rules.


Do REBOL copy things sometimes today? Like in function definitions:

make function! spec body


Maybe REBOL should copy in the example, we discuss, maybe it's a 
bad idea. The complication (for me and most likely others) in the 
above example is, when I read it, I would expect some output from 
my intuition. The actual output is different, and it's really hard 
to see, why that output is intentional.
BrianH
16-Aug-2011
[2141x2]
MAKE function! doesn't copy its arguments. The wrappers for it in 
R3 copy their arguments explicitly, but the MAKE operation doesn't, 
for efficiency and flexibility. The same goes for MAKE closure! vs. 
CLOSURE, and MAKE module! vs. MODULE (for unbinding, not copying).
None of these copy by default for three reasons:

- You can't uncopy something that's been copied, but you can copy 
something that hasn't been copied yet.

- MAKE doesn't take options that can't fit in its argument(s), so 
optional behavior can only happen if the spec says so.

- Efficiency means avoiding copying, particularly in a non-compiled 
language. That's why a so many functions are modifying.
Ladislav
16-Aug-2011
[2143]
Yes, and there is no reason, why such a rule could not be held for 
e.g. CONTEXT, to follow the suit as well
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"].