Hi, trying to answer your question.
(I warned you, no KISS! Let's try your example code with a slight
modification - hoping it would be OK with you to do so)
code: [
source code
words: [ print add write open ]
values: [ 1 "hi" ftp://ftp.rebol.com 2 %temp.txt ]
fragment: []
smc?: func [/local result] [
insert fragment pick words random 4
append fragment pick values random 5
append fragment pick values random 5
source code
result: copy fragment
clear fragment
result
]
smc?
]
;now, we can tell for sure Code is self-modifying in the following sense:
>> do code
code: [
source code
words: [print add write open]
values: [1 "hi" ftp://ftp.rebol.com 2 %temp.txt]
fragment: []
smc?: func [/local result] [
insert fragment pick words random 4
append fragment pick values random 5
append fragment pick values random 5
source code
result: copy fragment
clear fragment
result
]
smc?
]
code: [
source code
words: [print add write open]
values: [1 "hi" ftp://ftp.rebol.com 2 %temp.txt]
fragment: [write "hi" %temp.txt]
smc?: func [/local result] [
insert fragment pick words random 4
append fragment pick values random 5
append fragment pick values random 5
source code
result: copy fragment
clear fragment
result
]
smc?
]
== [write "hi" %temp.txt]
Another modification:
code: [
source code
words: [ print add write open ]
values: [ 1 "hi" ftp://ftp.rebol.com 2 %temp.txt ]
fragment: copy []
smc?: func [/local result] [
insert fragment pick words random 4
append fragment pick values random 5
append fragment pick values random 5
source code
result: copy fragment
clear fragment
result
]
smc?
]
;The same test:
>> do code
code: [
source code
words: [print add write open]
values: [1 "hi" ftp://ftp.rebol.com 2 %temp.txt]
fragment: copy []
smc?: func [/local result] [
insert fragment pick words random 4
append fragment pick values random 5
append fragment pick values random 5
source code
result: copy fragment
clear fragment
result
]
smc?
]
code: [
source code
words: [print add write open]
values: [1 "hi" ftp://ftp.rebol.com 2 %temp.txt]
fragment: copy []
smc?: func [/local result] [
insert fragment pick words random 4
append fragment pick values random 5
append fragment pick values random 5
source code
result: copy fragment
clear fragment
result
]
smc?
]
== [open "hi" "hi"]
; no self-modification of Code observed like in the former case, i.e. we can
surely tell that the behaviour of the latter code is different with respect
to Self-Modification. We can probably call this code non-SMC (opinions?)
Another modification:
code: [
source code
words: [print add write open]
values: [1 "hi" ftp://ftp.rebol.com 2 %temp.txt]
fragment: copy []
smc?: func [/local result] [
insert fragment pick words random 4
append fragment pick values random 5
append fragment pick values random 5
source code
result: copy fragment
clear fragment
result
]
if error? try [do smc?] [print "hmmm, not so safe."]
]
In the above sense even this is non-SMC, which means Code will not be
modified if we use the same test. Everybody feels, it is not the whole
story. The self-modification is hidden here, because Code is not everything
that is interpreted here. The code:
do smc?
executes something that we didn't take into account: the result of Smc?. So,
we can tell, that this code is self-modifying in the sense: "Result of Smc?
is created i.e. modified, if we consider creation of something as a
modification."
But, this (generic?) SMC is (arguably) more readable than the previous case,
because the code you read is not modified,
so what you see is what you get in a sense...
Ladislav
> Hi Ladislav,
>
> When I read your explanation on why you oppose self modifying code, I
> thought, hey the guy has a good point to make. It's not all black and
> white, but still...
>
> However, the kind of code that has been identified as self-modifying and
> the proposals to debunk the code both fail to live up to the reasoning you
> documented when in explaining your opposition to self modifying code.
>
> I think we urgently need a strong definition of what self-modifying code
> is, unless you want to see your arguments be transformed into triviality
> because of the examples provided.
>
> I found your reply to Russell puzzling. The only difference between the
> code you propose and the code Russell submitted is that you use
>
> b: copy ""
>
> instead of
> b: ""
>
> Now, this assignment occurs in the global context both in Russell's
example
> as well as in your example. You refer to Russell's code as self-modifying
> whereas you claim that your code is not self-modifying. Both functions
> behave exactly the same way. What do you believe to have accomplished by
> adding a copy into the assignment expression?
>
> Since Russell's assignment b: "" occurs outside of the function's context,
> In Russell's example there was no expectation that b would reference an
> empty string each time his function is called.
>
> Ladislave, Russell was following your example, in which you had debunked
> someone's code (was it Eric) by transferring Eric's:
>
> links: []
>
> from the local into the global context.
>
> That was your code. You stated that by having transferred links: [] to the
> global context, you had successfully transformed the "self modifying code"
> into a non-self-modifying version. Russell followed your example. Now
> again your unhappy, no it has to be
>
> b: copy ""
>
> not just
>
> b: ""
>
> Well, Ladislav, if b: "" won't do, then neither will your previous
> contribution
>
> links: []
>
> right?
>
> My example function continues to stand. If using a global b: copy "" takes
> care of it, than the folllowing function is not an example for self
> modifying code, right?
>
> words: [ print add write open ]
> values: [ 1 "hi" ftp://ftp.rebol.com 2 %temp.txt ]
>
> ;- here i'll use your latest notation:
>
> b: copy ""
>
> smc?: func [] [
> forever [
> insert b pick words random 4
> append b reduce [" " pick values random 5 " " pick values random 5]
> if error? try [do b] [print "hmmm, not so safe."]
> clear head b
> ]
> ]
>
> What do believe to have gained? I think, you have just added an
unnecessary
> instruction to duplicate the same behavior as Russell's original. Your
code
> is just as much or just as little self modifying as Russell's.
>
> In your second example you test whether str was assigned as a reference
and
> again set it to a copy of an empty string, if it wasn't. Again, I don't
see
> that you have gained anything over simply saying:
>
> str: ""
>
> What do you mean by self-modifying code, such that in your mind
>
> str: ""
>
> is self-modifying, whereas
>
> if not value? str [str: copy ""]
>
> isn't?
>
> Elan
>
> >
> >Hi, Russell,
> >
> >only one change and you have got a non-SMC, which is preferrable
> >
> >b: copy ""
> >f: func[/local a][a: b insert a "1" b]
> >f
> >f
> >f
> >
> >Results:
> >>> b: copy ""
> >== ""
> >>> f: func[/local a][a: b insert a "1" b]
> >>> f
> >== "1"
> >>> f
> >== "11"
> >>> f
> >== "111"
> >
> >You can write it even like this, if you prefer:
> >
> >f: func [] [
> > if not value? 'str [str: copy ""]
> > insert str "1"
> >]
> >
> >this is non-SMC either and the results are:
> >
> >>> f
> >== ""
> >>> f
> >== "1"
> >>> f
> >== "11"
> >>> f
> >== "111"
> >
> >----- Original Message -----
> >From: <[EMAIL PROTECTED]>
> >To: <[EMAIL PROTECTED]>
> >Sent: Thursday, December 23, 1999 1:37 AM
> >Subject: [REBOL] "logical" value referencing ... Re:(10)
> >
> >
> >> Hi Elan. This is not really a reply to your message, which I'm still
> >> digesting.
> >> I used 'reply" as a cheap way to stay on the thread.
> >>
> >> But here's a new approach to the problem of executing a function
modifying
> >> its source.
> >> Look at this console stuff:
> >>
> >> >> b: ""
> >> == ""
> >> >> f: func[/local a][a: b insert a "1" b]
> >> >> f
> >> == "1"
> >> >> f
> >> == "11"
> >> >> f
> >> == "111"
> >> >> b
> >> == "111"
> >> >> source f
> >> f: func [/local a][a: b insert a "1" b]
> >> >>
> >> I started by defining a global variable, 'b, referencing a null
string.
> >> In the function defn I used 'b instead of a literal "".
> >> It's quite clear (to me) that the local, 'a, is simply another
"pointer"
> >to
> >> the same data as 'b points to.
> >> Repeated executions of 'f show the same effect, but note that the
source
> >for
> >> 'f has not been changed.
> >>
> >> Somehow, this makes me a lot more comfortable about the results with
> >> f: func[/local a][a: "" insert a "1" a]
> >> in which case repeated executions change the "" to "1" "11" etc.
> >>
> >> Russell [EMAIL PROTECTED]
> >> ----- Original Message -----
> >> From: <[EMAIL PROTECTED]>
> >> To: <[EMAIL PROTECTED]>
> >> Sent: Wednesday, December 22, 1999 1:00 PM
> >> Subject: [REBOL] "logical" value referencing ... Re:(9)
> >>
> >>
> >> > Hi Ladislav,
> >> >
> >> > At 04:01 AM 12/22/99 -0800, I wrote. And I should have been in bed
fast
> >> > asleep. Sorry for taking up so much unnecessary bandwidth. My
> >imagination
> >> > was running wild.
> >> >
> >> > Two points I'd like to make:
> >> >
> >> > in 1. I comment on the unlikelyhood of there being a "return
context".
> >> >
> >> > in 2. I provide a simple illustration for what I spent too much time
on
> >> > earlier this morning.
> >> >
> >> > 1. I mentioned the "return context of reduce". I have no proof that
> >there
> >> > is a return context. On the contrary, it appears much more likely
that
> >> > there is no return context. The following code certainly demonstrates
> >that
> >> > a word returned from a function is bound in the function's context
and
> >not
> >> > in some return context:
> >> >
> >> > >> f: func [/local a] [ a: 4 return 'a ]
> >> > >> b: f
> >> > == a
> >> > >> get b
> >> > == 4
> >> >
> >> > As expected. Now let us modify the value of a in the function's
> >evaluation
> >> > block:
> >> >
> >> > >> set first second :f 10
> >> > == 10
> >> >
> >> > b's version of 'a is apparently bound the context of the function's
> >body,
> >> > since it also returns the new value:
> >> >
> >> > >> get b
> >> > == 10
> >> >
> >> > 2. After a few hours of sleep, I think I also came up with a much
better
> >> > example to illustrate what I'm driving at with the literal string
thing:
> >> >
> >> > Assume the following function
> >> > >> f: func []
> >>
> >> > insert "" "bcd"
> >> > insert make string! 0 "xyz"
> >> > ]
> >> >
> >> > Before we evaluate 'f, let's see what the function's body contains:
> >> >
> >> > >> token: second :f
> >> >
> >> > ;- You could use probe or mold here:
> >> >
> >> > >> forall token
> >>
> >> > print [
> >> > rejoin [mold first token ":"]
> >> > mold type? first token
> >> > ]
> >> > ]
> >> > insert: word!
> >> > "": string!
> >> > "bcd": string!
> >> > insert: word!
> >> > make: word!
> >> > string!: word!
> >> > 0: integer!
> >> > "xyz": string!
> >> >
> >> > Now we evaluate 'f:
> >> >
> >> > >> f
> >> > == ""
> >> >
> >> > Let's see what the function's body contains after the evaluation:
> >> > >> token: second :f
> >> >
> >> > ;- You could use probe or mold here:
> >> >
> >> > >> forall token
> >>
> >> > print [
> >> > rejoin [mold first token ":"]
> >> > mold type? first token
> >> > ]
> >> > ]
> >> > insert: word!
> >> > "bcd": string!
> >> > "bcd": string!
> >> > insert: word!
> >> > make: word!
> >> > string!: word!
> >> > 0: integer!
> >> > "xyz": string!
> >> >
> >> > a) The literal string retains its modification: it was "", has now
> >become
> >> > "bcd". We expected that.
> >> > b) Where did the string returned by make string! 0, into which we
> >inserted
> >> > "xyz" go?
> >> >
> >> > I conclude from 2 that besides - as you pointed out - 'b being
assigned
> >to
> >> > a new string returned by copy each time your function was called,
there
> >is
> >> > another, underlying phenomenon. That phenomenon is documented in my
'f
> >> > function above: The return value of make string! (or copy ""), is not
> >> > retained from one function call to the next. In this respect the
literal
> >> > string and the string returned by make string! "" are different. It
was
> >> > this difference I had been commenting on.
> >> >
> >> > The literal string continues to exist - and with it the modifications
> >made
> >> > to it. The string returned by copy is not retained and the
modifications
> >> > made to it disappear with it.
> >> >
> >> > What determines whether a value continues to exist or not? The extent
of
> >> > its context. The literal string is created in the global context. The
> >> > string returned by copy is created in the context of the function
body
> >at
> >> > the time the expressions in the body are evaluated.
> >> >
> >> > My hypothesis is that as a result of being created during the time
the
> >> > function's body is evaluated, its context is the function's
evaluation
> >> > context. In saying that I'm assuming that a function has an
evaluation
> >> > context. When the function ceases to be evaluated, its context ceases
to
> >> be
> >> > valid and the string returned by copy is eventually garbage
collected.
> >> >
> >> > When I assign a word as a reference to the string returned by copy, I
> >> > extend that string's context. The extent of the set-word! b: is the
> >> > function body's context. When the string returned by copy becomes
> >> > referenced by 'b, the string's context is extended. That is why you
can
> >> > retrieve the string returned by copy after the function body has been
> >> > evaluated, provided you reference it with a word:
> >> >
> >> > >> f: func [/local b] [ b: copy "xyz" ]
> >> > >> f
> >> > == "xyz"
> >> > >> get first second :f
> >> > == "xyz"
> >> >
> >> > Last I remember, the REBOL Tech crew commented on the extent of words
> >> local
> >> > to the body of a function saying that the persistence of their value
> >> > binding between function calls is not guaranteed.
> >> >
> >> > Hope this helps,
> >> >
> >> > Elan
> >> >
> >> >
> >> >
> >> >
> >>
> >>
> >
> >
> >
>
>