Obscure? You be the judge!
[1/20] from: joel:neely:fedex at: 13-May-2002 23:17
I don't have a good explanation for this bit of surprising behavior.
All donations of wisdom gladly accepted.
Here's a odd-looking little object:
bug?: make object! [
width: 3
data: [1]
plop: func [b [block!]] [append data b]
child-proto: make object! [
label: "no such"
dataref: data
dump: func [] [print [label newline tab mold dataref]]
reset: func [] [dataref: head dataref]
]
children: make block! width
repeat i width [
append children make child-proto [
label: join "Child-" i
]
]
fizz: func [] [
foreach child children [
child/dump
]
]
]
It contains a data store (called DATA surprisingly enough) and
a block of subordinate objects that need to share access to DATA.
Within each child object, DATAREF is supposed to refer to the
same series as DATA. That way, after BUG?/PLOP is used to add
entries to DATA, the DUMP routine of each child should show the
additions. Let's try it:
>> bug?/fizz
Child-1
[1]
Child-2
[1]
Child-3
[1]
>> bug?/plop [3 5 7]
== [1 3 5 7]
>> bug?/fizz
Child-1
[1]
Child-2
[1]
Child-3
[1]
>>
Wozzattt?? It appears that each child's DATAREF has become a
completely independent block!? Howesomever...
If we add one line to the initialization of CHILDREN (inside
the REPEAT about a dozen lines in) like so:
bug?: make object! [
width: 3
data: [1]
plop: func [b [block!]] [append data b]
child-proto: make object! [
label: "no such"
dataref: data
dump: func [] [print [label newline tab mold dataref]]
reset: func [] [dataref: head dataref]
]
children: make block! width
repeat i width [
append children make child-proto [
label: join "Child-" i
dataref: data ;;; this line added
]
]
fizz: func [] [
foreach child children [
child/dump
]
]
]
... we now get the expected behavior!
>> bug?/fizz
Child-1
[1]
Child-2
[1]
Child-3
[1]
>> bug?/plop [3 5 7]
== [1 3 5 7]
>> bug?/fizz
Child-1
[1 3 5 7]
Child-2
[1 3 5 7]
Child-3
[1 3 5 7]
>>
As tempted as I am to sing
"Plop, plop, fizz, fizz,
Oh what a relief it is!"
I'm not feeling relieved. Why does the second version behave
differently? Both are initializing DATAREF to DATA, just at
different times, so I'm a bit puzzled.
Do I need more coffee?
-jn-
--
; Joel Neely joeldotneelyatfedexdotcom
REBOL [] do [ do func [s] [ foreach [a b] s [prin b] ] sort/skip
do function [s] [t] [ t: "" foreach [a b] s [repend t [b a]] t ] {
| e s m!zauafBpcvekexEohthjJakwLrngohOqrlryRnsctdtiub} 2 ]
[2/20] from: joel::neely::fedex::com at: 13-May-2002 23:45
More on obscure behavior...
I'm sure everyone on this list will understand why the following
change resolves the problem...
bug?: make object! [
width: 3
data: [1]
plop: func [b [block!]] [append data b]
child-proto: make object! [
label: "no such"
dataref: func [] [dataref: data] ;; changed line here
dump: func [] [print [label newline tab mold dataref]]
reset: func [] [dataref: head dataref]
]
children: make block! width
repeat i width [
append children make child-proto [
label: join "Child-" i
]
]
fizz: func [] [
foreach child children [
child/dump
]
]
]
... but that doesn't bring me any closer to understanding why
there's a problem to be resolved!
-jn-
--
; Joel Neely joeldotneelyatfedexdotcom
REBOL [] do [ do func [s] [ foreach [a b] s [prin b] ] sort/skip
do function [s] [t] [ t: "" foreach [a b] s [repend t [b a]] t ] {
| e s m!zauafBpcvekexEohthjJakwLrngohOqrlryRnsctdtiub} 2 ]
[3/20] from: nitsch-lists:netcologne at: 14-May-2002 11:52
Re: Obscure? You be the judge!
Hi Joel,
>> a: context [ b: [1]]
>> c: make a[]
>> d: make a[]
>> same? a/b c/b
== false
>> same? c/b d/b
== false
when you 'make an 'object!, all strings, blocks and functions are copied.
that allows for example in 'layout :
box with[append init[my-inits]]
without destroying the original in box.
also blocks, like functions, are rebound.
so [make child-proto []] gives a copy of 'dataref, not the original.
but objects are not copied,
so the 'face/feel are all the same after [make face[]].
or in your case,
do [
ex: func ["probe-tool" block] [print [">>" mold/only block "^/"] do block]
bug?: make object! [
width: 2
data: context [block: [1]] ;;; object!
plop: func [b [block!]] [append data/block b]
child-proto: make object! [
label: "no such"
dataref: data
dump: func [] [print [label newline tab mold dataref]]
reset: func [] [dataref/block: head dataref/block]
]
children: make block! width
repeat i width [
append children make child-proto [
label: join "Child-" i
]
]
fizz: func [] [
foreach child children [
child/dump
]
]
]
ex [bug?/fizz]
ex [bug?/plop [3 5 7]]
ex [bug?/fizz]
]
>> bug?/fizz
Child-1
make object! [
block: [1]
]
Child-2
make object! [
block: [1]
]
>> bug?/plop [3 5 7]
>> bug?/fizz
Child-1
make object! [
block: [1 3 5 7]
]
Child-2
make object! [
block: [1 3 5 7]
]
greetings
-volker
Am Dienstag, 14. Mai 2002 06:17 schrieb Joel Neely:
[4/20] from: joel:neely:fedex at: 14-May-2002 7:57
Hi, Volker,
Thanks for the explanations. As Larry Wall said:
Just because something is obviously happening doesn't mean
that something obvious is happening.
;-)
However, I'm still left with a puzzled look on my face over
one aspect of this...
Volker Nitsch wrote:
> Hi Joel,
> >> a: context [ b: [1]]
<<quoted lines omitted: 14>>
> so the 'face/feel are all the same after [make face[]].
> or in your case,
(Oh, by the way, did you find this documented anywhere, did you
just figure it out for yourself, or is there another path to
enlightenment? ;-)
Thanks to your explanation, I have a more compact example...
gub?: make object! [
data: [1]
proto: make object! [
number: 0
dataref: data
speak: func [] [print [number mold dataref]]
]
things: []
append things make proto [number: 1]
append things make proto [number: 2 dataref: data]
tweak-n-speak: func [blk [block!]] [
insert data blk
foreach thing things [thing/speak]
]
]
...which behaves as follows...
>> gub?/tweak-n-speak ["OK,"]
1 [1]
2 ["OK," 1]
My remaining puzzlement is over this contrast:
If I accept the description that (during the construction of
GUB?/PROTO) GUB?/DATA is copied and GUB?/PROTO/DATAREF is set
to refer to the copy, then that explains the behavior of
GUB?/THING/1 .
However, during the construction GUB?/THING/2 the additional
spec block *also* refers to GUB?/DATA , but apparently the copy
behavior does *not* occur (even though the referenced data value
is still only a block).
This makes me wonder if the issue here is a difference in the
evaluation of the specblock parts of
make object! [...specblock...]
vs.
make some-object [...specblock...]
This is uncomfortably reminiscent of FORTH, in which one must
have a complete operational model of the interpreter's internal
state if one is to understand the behavior the more advanced
(and hence more useful) aspects of the language. At least FORTH
had both liberal documentation and available source to help with
the construction/communication of such an operational mental
model...
-jn-
--
; Joel Neely joeldotneelyatfedexdotcom
REBOL [] do [ do func [s] [ foreach [a b] s [prin b] ] sort/skip
do function [s] [t] [ t: "" foreach [a b] s [repend t [b a]] t ] {
| e s m!zauafBpcvekexEohthjJakwLrngohOqrlryRnsctdtiub} 2 ]
[5/20] from: cyphre:seznam:cz at: 14-May-2002 17:22
----- Original Message -----
From: "Volker Nitsch" <[nitsch-lists--netcologne--de]>
To: <[rebol-list--rebol--com]>
Sent: Tuesday, May 14, 2002 11:52 AM
Subject: [REBOL] Re: Obscure? You be the judge!
.............
when you 'make an 'object!, all strings, blocks and functions are copied.
that allows for example in 'layout :
box with[append init[my-inits]]
without destroying the original in box.
also blocks, like functions, are rebound.
so [make child-proto []] gives a copy of 'dataref, not the original.
but objects are not copied,
so the 'face/feel are all the same after [make face[]].
..................
That's why lot of people are asking RT for adding something like 'clone or
'make/deep ;-)
Or should it be a default Rebol's behaviour when working with objects?
Regards,
Cyphre
[6/20] from: g:santilli:tiscalinet:it at: 14-May-2002 23:12
Hi Joel,
On Tuesday, May 14, 2002, 6:17:17 AM, you wrote:
JN> I don't have a good explanation for this bit of surprising behavior.
I think I can help. :) MAKE copies (deep) and rebinds blocks and
functions when cloning objects (so that methods work :). I think
this is happening before the code block passed to MAKE is
evaluated, so that your second version works as expected.
JN> All donations of wisdom gladly accepted.
Well, just my two euro cents. ;-)
JN> Do I need more coffee?
Nope, REBOL needs better docs. ;-)
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r
[7/20] from: lmecir:mbox:vol:cz at: 15-May-2002 1:10
Hi Joel,
<<From: "Joel Neely">>
...
As Larry Wall said:
Just because something is obviously happening doesn't mean
that something obvious is happening.
;-)
However, I'm still left with a puzzled look on my face over
one aspect of this...
...
> when you 'make an 'object!, all strings, blocks and functions are
> copied.
<<quoted lines omitted: 6>>
> so the 'face/feel are all the same after [make face[]].
> or in your case,
...
(Oh, by the way, did you find this documented anywhere, did you
just figure it out for yourself, or is there another path to
enlightenment? ;-)
<</Joel>>
<<L>>
I think, that he figured it out for himself...
<</L>>
<<Joel>>
...
Thanks to your explanation, I have a more compact example...
gub?: make object! [
data: [1]
proto: make object! [
number: 0
dataref: data
speak: func [] [print [number mold dataref]]
]
things: []
append things make proto [number: 1]
append things make proto [number: 2 dataref: data]
tweak-n-speak: func [blk [block!]] [
insert data blk
foreach thing things [thing/speak]
]
]
...which behaves as follows...
>> gub?/tweak-n-speak ["OK,"]
1 [1]
2 ["OK," 1]
My remaining puzzlement is over this contrast:
If I accept the description that (during the construction of
GUB?/PROTO) GUB?/DATA is copied and GUB?/PROTO/DATAREF is set
to refer to the copy, then that explains the behavior of
GUB?/THING/1 .
However, during the construction GUB?/THING/2 the additional
spec block *also* refers to GUB?/DATA , but apparently the copy
behavior does *not* occur (even though the referenced data value
is still only a block).
<</Joel>>
<<L>>
That "apparently" is incorrect. Here is a Rebol model of the MAKE PROTO
behaviour: (testing appreciated)
make-proto: function [
{MAKE PROTO simulation}
proto [object!]
spec [block!]
] [set-words object sw word value spc body] [
set-words: copy []
; get local words from proto
foreach word next first proto [
append set-words to set-word! word
]
; append all set-words from SPEC
parse spec [
any [
copy sw set-word! (append set-words sw) |
skip
]
]
; create a blank object with the desired local words
object: blank-object set-words
; set 'self in object to refer to the object
object/self: object
; copy the contents of the proto
repeat i (length? first proto) - 1 [
word: pick next first proto i
any-type? set/any 'value pick next second proto i
any [
all [string? get/any 'value set in object word copy value]
all [block? get/any 'value set in object word bind/copy
value in object word]
all [
function? get/any 'value
spc: load mold third :value
body: bind/copy second :value in object word
set in object word func spc body
]
any-type? set/any in object word get/any 'value
]
]
; bind the SPEC to the object
bind spec in object 'self
; evaluate it
spec-eval spec
; return the value of 'self as the result
return get/any in object 'self
]
<</L>>
[8/20] from: nitsch-lists:netcologne at: 14-May-2002 21:37
Hi Joel,
Am Dienstag, 14. Mai 2002 14:57 schrieb Joel Neely:
> Hi, Volker,
> Thanks for the explanations. As Larry Wall said:
<<quoted lines omitted: 30>>
> just figure it out for yourself, or is there another path to
> enlightenment? ;-)
Meditation, tea and trying everything out ;)
> Thanks to your explanation, I have a more compact example...
> gub?: make object! [
<<quoted lines omitted: 30>>
> vs.
> make some-object [...specblock...]
All pure sientific, no magic needed.
before a spec-block is executed, it is parsed for set-words.
only the contents of set-words are copied.
here:
append things make proto [number: 1]
append things make proto [number: 2 dataref: data]
you see there is no set-word for 'data, so it remains untouched.
the copying happens before execution, so you get a copy
append things make proto [number: 2 ? dataref dataref: data]
but then overwrite it with the original
append things make proto [
number: 2 ? dataref dataref: data ? dataref
]
the trick used for "export" is based on that.
context[
set 'something-outside "this will not be part of new context"
]
'something is no set-word, so it will not be included in the new context,
so the outside word stays bound and goes modified.
> This is uncomfortably reminiscent of FORTH, in which one must
> have a complete operational model of the interpreter's internal
<<quoted lines omitted: 3>>
> the construction/communication of such an operational mental
> model...
no state and immediate words needed in rebol.
I know this should be impossible :)
> -jn-
greetings
-Volker
[9/20] from: ammon:rcslv at: 13-May-2002 4:45
A short time ago, Joel Neely, sent an email stating:
[10/20] from: nitsch-lists:netcologne at: 15-May-2002 1:27
Am Dienstag, 14. Mai 2002 17:22 schrieb Cyphre:
> ----- Original Message -----
> From: "Volker Nitsch" <[nitsch-lists--netcologne--de]>
<<quoted lines omitted: 13>>
> That's why lot of people are asking RT for adding something like 'clone or
> 'make/deep ;-)
I know.
> Or should it be a default Rebol's behaviour when working with objects?
>
Actually i like it the current way.
===cloning, complex structures
In my experience with other languages
cloning of complex structures gets pretty complicated
and automatics are not very helpfull there.
make/deep could manage one or two nesting steps maybe,
with more something usually needs to be shared and the language
needs constructs/conventions to control clone/sharing and the programmer
has to be aware of it. well, cloning is a bit like the last sentence ;)
Also Carl avoids it, so i expected my "trap"-view is right,
and rebol has a better "native" way.
Not necessary better as in 'good,
but as in "you know, if you open this other box..".
So for a while I started to chose between blocks/objects
based on my sharing/cloning decisions.
Just to see what happens.
And oops, its handy! Now it is a good commodity.
===constants, cloning deep faces?
Also if i know i modify an object, by default i make it.
about rebol its one sentence
if you want to modify it, its object!, its shared, so 'make it
,
other languages have nice keywords like 'constant.
and then 'mutable somewhere inside because the constant is not
so completely constant in a special case.
works, but another piece to keep in mind.
in c its a page of paper with some extra hints in specialized books
to use the constant-concept correctly.
(if you have a const pointer, is the pointed stuff const too or not?)
So if i want to scroll text in a face, i look
which object is affected, and use [area para[]].
(fortunally i discovered that somehow, because docs..)
==switching between blocks and objects
a: context[b: 123] a/b: 234 probe a/b
a: [b 123] a/b: 234 probe a/b
are very similar. and scripts short enough to change the other places ;)
> Regards,
>
> Cyphre
greetings
Volker
[11/20] from: rotenca:telvia:it at: 15-May-2002 15:18
Hi Ladislav,
> make-proto: function [
> {MAKE PROTO simulation}
<<quoted lines omitted: 41>>
> return get/any in object 'self
> ]
Some observations:
1) set-words should be unique, this is not a problem with your blank-object,
but is a problem with your lfunc.
2) Because of return bug, it is better
get/any in object 'self
instead of
return get/any in object 'self
3) I did not test your code, but it seems to me that it bind the body function
to the new context. This is only half correct: binding is done in Rebol before
adding the new set-words of spec to the new object:
d: "global"
a: context [b: does [print d]]
a/b; == global
a2: make a [d: "local to a2"]
a2/b; == global
As you can see, the d word in the func body is not binded to the a2 context.
But:
a: context [b: does [print d] d: "local to a"]
a/b; == local to a
a2: make a [d: "local to a2"]
a2/b; == local to a2
I think that your code gives always the result of second example (but i did
not tested it).
4) instead of parsing all the block, because the only oddity of make object is
copy and binding the function bodies, one could use bind and copy deep and
then finding and changing only the function values, but i did not try.
5) why this any-type? ?
any-type? set/any 'value pick next second proto i
---
Ciao
Romano Paolo Tenca
[12/20] from: joel:neely:fedex at: 15-May-2002 8:32
Hello, all,
(I'm replying to self because several folks have made helpful
comments during this thread. Thanks to all who've contributed!)
I've done further experimenting to try to clarify the differences
for myself. Perhaps they will be of help to someone else. My
apologies for the length, but I'd appreciate comments on the
coding convention at the end.
-jn-
Joel Neely wrote:
> Thanks to your explanation, I have a more compact example...
>
Thanks to comments from Volker, Gabriele, and Ladislav, I have
a more complete example, given below. I'm sure that all I've
done here is re-discover/-state what was already said, but I'm
a bit slow... ;-)
gub?: make object! [
data: [1]
proto: make object! [
number: 0
dataref: data
speak: func [] [print [number mold dataref]]
]
things: []
append things make proto [number: 1]
append things make proto [number: 2 dataref: data]
append things make proto [number: 3 dataref: proto/dataref]
tweak-n-speak: func [blk [block!]] [
insert data blk
proto/speak
foreach thing things [thing/speak]
]
]
By adding the line containing "PROTO/SPEAK" to the last function,
I was able to get more photons from the filament!
>> gub?/tweak-n-speak ["what's" "different?"]
0 ["what's" "different?" 1]
1 [1]
2 ["what's" "different?" 1]
3 ["what's" "different?" 1]
When GUB?/PROTO was made, its DATAREF was initialized to refer to
GUB?/DATA as expected.
When GUB?/PROTO/1 was made, it began life as a (deep) clone of
GUB?/PROTO and then had its NUMBER set to 1. Its DATAREF now
refers to a clone of the initial GUB?/DATA (via the reference in
GUB?/PROTO/DATAREF).
When GUB?/PROTO/2 was made, it began life as a (deep) clone of
GUB?/PROTO and then had its NUMBER set to 2, *and* its DATAREF
(re-)set to refer to the same series as GUB?/DATA (explicitly,
via the GUB?/DATA reference).
When GUB?/PROTO/3 was made, it began life as a (deep) clone of
GUB?/PROTO and then had its NUMBER set to 3, *and* its DATAREF
(re-)set to refer to the same series as GUB?/DATA (explicitly,
via the GUB?/PROTO/DATAREF reference).
At that point the references in GUB?/DATA and GUB?/PROTO/DATAREF
and GUB?/THINGS/2/DATAREF and GUB?/THINGS/3/DATAREF are all
equivalent, while the reference in GUB?/THINGS/1/DATAREF refers
to a distinct block (originally cloned via GUB?/PROTO/DATAREF).
Normal shared-block-reference behavior ensues *after* this point.
KEY LESSON: When using an existing object as a prototype, the
default behavior is to copy referenced *values*,
and special effort must be taken to *suppress* the copying, in
contrast to other REBOL handling of reference data, where the
default behavior is to copy *references* and special effort
must be taken to *cause* copying.
For example, every REBOL programmer eventually learns that:
palindrome: func [b [block!] /local result] [
result: []
append result b
append result head reverse b
result
]
will (probably) surprise him/her *twice*, as in:
>> foo: [1 3 5 7]
== [1 3 5 7]
>> baz: palindrome foo
== [1 3 5 7 7 5 3 1]
>> foo
== [7 5 3 1]
>> bletch: palindrome [2 4 6]
== [1 3 5 7 7 5 3 1 2 4 6 6 4 2]
and therefore should (probably) be written more like:
safe-palindrome: func [b [block!] /local result] [
result: copy []
append result b
append result head reverse copy b
result
]
(Yes, I know this dinky example can be written *much* better;
please don't miss the point and try to optimize this specimen
of noncopy-vs-noncopy behavior. If I had rewritten it as
safe-and-short-palindrome: func [b [block!]] [
join b head reverse copy b
]
the point regarding copying would have been harder to see.)
In contrast to the you-must-ask-for-copying-if-you-want-it
general rule, when creating objects from a prototype object
that is intended to contain reference(s) to shared block(s),
REBOL requires that we take special action to *avoid* the
default copying behavior.
It seems to me that the clearest way to do this is likely
something similar to what I did above with the third anonymous
object in GUB?/THINGS where the prototype contains:
proto: make object! [
number: 0
dataref: data
;;...
]
and the construction-from-prototype pattern of
make proto [
number: 3
dataref: proto/dataref
]
explicitly calls the reader's attention to the fact that the
DATAREF attribute of the new object is intended to share
reference with the corresponsing attribute of the prototype.
(In passing, it's interesting that NUMBER must be initialized
explicitly to get a different value from the prototype, but
DATAREF must be initialized explicitly to get the same value
as the protype.)
I'm leaning toward writing
dataref: proto/dataref
instead of
dataref: data
in the construction-from-prototype expression to make it clear
that the *current* value of the prototype's attribute should be
the basis of the shared reference. For example...
some-proto: make object! [
block-ref: some-global-block
;;...
]
other-proto: make first-proto [
block-ref: other-global-block
;;...
]
leaves a situation in which
some-instance: make some-proto [
block-ref: some-proto/block-ref
;;...
]
other-instance: make other-proto [
block-ref: other-proto/block-ref
;;...
]
is more likely correct (and obvious to the reader) than
some-instance: make some-proto [
block-ref: some-global-block
;;...
]
other-instance: make other-proto [
block-ref: some-global-block
;;...
]
Thoughts?
--
; Joel Neely joeldotneelyatfedexdotcom
REBOL [] do [ do func [s] [ foreach [a b] s [prin b] ] sort/skip
do function [s] [t] [ t: "" foreach [a b] s [repend t [b a]] t ] {
| e s m!zauafBpcvekexEohthjJakwLrngohOqrlryRnsctdtiub} 2 ]
[13/20] from: greggirwin:mindspring at: 15-May-2002 12:34
Hi Joel,
I like the convention you put forth. I'm learning a lot from this thread.
This is behavior worth documenting in Core.pdf.
--Gregg
[14/20] from: lmecir:mbox:vol:cz at: 15-May-2002 21:34
Hi Romano,
<<Romano>>
...
Some observations:
1) set-words should be unique, this is not a problem with your blank-object,
but is a problem with your lfunc.
<</Romano>>
<<L>>
Yes, I know that LFUNC isn't able to handle the cases, in which duplicities
occur. I should repair it... I wonder, how many users does the function
have?
OTOH, it is unnecessary to complicate the above code (IMHO)...
<</L>>
<<Romano>>
2) Because of return bug, it is better
get/any in object 'self
instead of
return get/any in object 'self
<</Romano>>
<<L>>
The native MAKE PROTO can return even error values. I cannot simulate that
without RETURN...
<</L>>
<<Romano>>
3) I did not test your code, but it seems to me that it bind the body
function
to the new context. This is only half correct: binding is done in Rebol
before
adding the new set-words of spec to the new object:
d: "global"
a: context [b: does [print d]]
a/b; == global
a2: make a [d: "local to a2"]
a2/b; == global
As you can see, the d word in the func body is not binded to the a2 context.
But:
a: context [b: does [print d] d: "local to a"]
a/b; == local to a
a2: make a [d: "local to a2"]
a2/b; == local to a2
<</Romano>>
<<L>>
Thanks for your analysis. This behaviour is really complicated. (I wonder
what will Joel say to this?)
d: "global"
a: context [b: [d]]
get first a/b; == global
a2: make a [d: "local to a2"]
get first a2/b; == global
a: context [b: [d] d: "local to a"]
get first a/b; == local to a
a2: make a [d: "local to a2"]
get first a2/b; == local to a2
(uff)
I need to define a special binding function that binds only partially, I
didn't find any other way how to simulate it?
<</L>>
<<Romano>>
4) instead of parsing all the block, because the only oddity of make object
is
copy and binding the function bodies, one could use bind and copy deep and
then finding and changing only the function values, but i did not try.
<</Romano>>
<<L>>
neither did I...
<</L>>
<<Romano>>
5) why this any-type? ?
any-type? set/any 'value pick next second proto i
---
Ciao
Romano Paolo Tenca
<</Romano>>
<<L>>
It could be any type value (e.g. error).
Ciao
Ladislav
[15/20] from: rotenca:telvia:it at: 16-May-2002 14:25
Hi, Ladislav
> The native MAKE PROTO can return even error values. I cannot simulate that
> without RETURN...
...
> It could be any type value (e.g. error).
I always forget error return (i do not like it).
> Thanks for your analysis.
Thank you for your emulation which made me think to the problem.
> This behaviour is really complicated.
It is hard to emulate, but it seems to me simpler to understand:
1) object is cloned as is (with func block copied)
2) new setword coming from spec added to the object context
(this should mean that Rebol is internally already able to add new words
to an existing context beyond global context)
3) spec block is bound to the expanded context
4) spec block is evaluated and object/self returned
> Ciao
> Ladislav
---
Ciao
Romano
[16/20] from: nitsch-lists:netcologne at: 17-May-2002 21:49
Am Freitag, 17. Mai 2002 13:58 schrieb Gabriele Santilli:
> Hi Romano,
>
> On Thursday, May 16, 2002, 2:25:41 PM, you wrote:
>
> RPT> 2) new setword coming from spec added to the object context
> RPT> (this should mean that Rebol is internally already able to add new
> words RPT> to an existing context beyond global context)
>
> This raises an interesting point. Holger?
>
Well, make knows the numbers of words to allocate.
i think one problem with general ability is, one can not move context in
memory without confusing all references currently?
maybe make/keep-free object! [] 15 , keeping free 15 words to add, but..
> Regards,
> Gabriele.
greetings
Volker
[17/20] from: g:santilli:tiscalinet:it at: 18-May-2002 11:41
Hi Volker,
On Friday, May 17, 2002, 9:49:04 PM, you wrote:
VN> Well, make knows the numbers of words to allocate.
But then, why binding before actually adding the new words?
VN> i think one problem with general ability is, one can not move context in
VN> memory without confusing all references currently?
That can be easily solvable, by having the words and values
referenced by the context! and the words referencing the context!
itself (maybe with an index to the position in words/values). I
think it is very likely to work this way already... (Remember that
before 2.2 you could modify the block of words or the block of
values independently...)
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r
[18/20] from: joel:neely:fedex at: 18-May-2002 10:34
Hi, Ladislav,
Ladislav Mecir wrote:
> <<Romano>>
> 3) I did not test your code, but it seems to me that it bind the
<<quoted lines omitted: 17>>
> Thanks for your analysis. This behaviour is really complicated.
> (I wonder what will Joel say to this?)
He didn't say anything. He just ran from the room screaming
incoherently!!! ;-)
Seriously, I wasn't nearly as surprised by this example as I have
been by some other "interesting" examples. Since encountering
REBOL I have been on a (non-terminating ;-) quest to find the
simplest possible model/principles from which to understand and
describe the behavior of the language. For example, once one
understands the way REBOL uses the concepts of "word" and "context"
it is follows very logically that in the following:
a: make object! [
p: 42
q: "Howzabout them apples?"
r: func [] [
pick q (length? q) // p + 1
]
]
b: make a [
p: 7
q: "I have nothing to say and I am saying it."
]
each of A and B must have its own copy of R with no code-sharing.
Similarly, the non-intuitive behavior of Romano's example above
can be explained fairly simply in terms of the "definition-time
binding" rule and the way MAKE OBJECT! treats top-level set-words
in the spec block.
>From my mathematical background, I don't see a contradiction in
simultaneously seeing something as "non-intuitive" and "simple"
because that background has taught me that intuition is trained
by experience. Something outside our everyday experience is
likely to be non-intuitive/surprising more from our unfamiliarity
with it than from its inherent complexity. Given the fact that
different people have different styles of thinking and learning,
I conclude that the best way to teach something unfamiliar is to
use a combination of *both*:
* axiom-like basic principles from which the behavior of the new
thing can be deduced (for obsessively top-down, deductive
thinkers like me), and
* cumulative experience, beginning with simple examples and
leading up to the more out-of-the-ordinary cases (for the folks
at the other end of the thinking-style spectrum who are more
bottom-up and inductive).
I'd love to write such an introduction to REBOL one of these days,
but feel compelled to learn it better myself before doing so. I
also would like to feel a high level of confidence in the stability
of the core language concepts. The upcoming dosage of Valium to be
adminstered to word evaluation would certainly have made some of my
previous models and descriptions inaccurate! ;-)
-jn-
--
; Joel Neely joeldotneelyatfedexdotcom
REBOL [] do [ do func [s] [ foreach [a b] s [prin b] ] sort/skip
do function [s] [t] [ t: "" foreach [a b] s [repend t [b a]] t ] {
| e s m!zauafBpcvekexEohthjJakwLrngohOqrlryRnsctdtiub} 2 ]
[19/20] from: g:santilli:tiscalinet:it at: 17-May-2002 13:58
Hi Romano,
On Thursday, May 16, 2002, 2:25:41 PM, you wrote:
RPT> 2) new setword coming from spec added to the object context
RPT> (this should mean that Rebol is internally already able to add new words
RPT> to an existing context beyond global context)
This raises an interesting point. Holger?
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r
[20/20] from: nitsch-lists:netcologne at: 18-May-2002 20:02
Am Samstag, 18. Mai 2002 11:41 schrieb Gabriele Santilli:
> Hi Volker,
>
> On Friday, May 17, 2002, 9:49:04 PM, you wrote:
>
> VN> Well, make knows the numbers of words to allocate.
>
> But then, why binding before actually adding the new words?
semantics? lets say:
>> ctx: context[print-me: does[print ["iam" mold self]]]
>> ctx2: make ctx[mold: "oops"]
>> ctx2/print-me
iam
make object! [
print-me: func [][print ["iam" mold self]]
mold: "oops"
]
this way one can create an object with basic functions, like 'print-me.
Its obvious not to redefine them.
but it is obvious too not to redefine 'mold?
> VN> i think one problem with general ability is, one can not move context
> in VN> memory without confusing all references currently?
<<quoted lines omitted: 4>>
> before 2.2 you could modify the block of words or the block of
> values independently...)
Well, IIRC i started around 2.2 ..
AFAIK they blocked that because adding words crashed the interpreter?
can imagine insert sees a block, thinks "ok, i resize", bang?
Or was it asymetric resizing (adding a word, bot not a value)?
Hmm, one could try to optimize by storing like
3 word word word value value value
where 3 is the offset words/1 -> values/1 .
that would save some pointer-lookups.
Carl has some tricks in this area. Remember exec-list-headers :)
but its trying to look behind the curtain.. ;)
> Regards,
> Gabriele.
greetings
Volker
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted