Binding a changed function within a context
[1/8] from: gscottjones:mchsi at: 5-Oct-2002 7:27
Hi, List,
I am working on an enhanced version of a field widget. In order to get the
enhanced functionality, I need to modify a function within the context of
edit-text in REBOL. The code is too long for easy use on the list (in my
opinion), so I have created a very simple example that (hopefully) recreates
the problem in the "small."
Here is my hypothetical context. It contains a local variable and a
function that prints that variable.
my-context: context [
local-var: 5
my-func: does [
print local-var
]
]
where then executing:
my-context/my-func ;yields 5
Now, let us say that I wish to dynamically change the function in this
object to the following:
my-func: does [
print ["new print" local-var]
]
where my-func will be bound into the context of my-context.
For your ease in running the code samples, I have included the original
context object with each example. In my non-hypothetical case, the shortest
code method would be to change the code in place like:
;### Method 1
;original
my-context: context [
local-var: 5
my-func: does [
print local-var
]
]
;make change
insert remove remove pick pick pick my-context 2 3 2 [print ["new print"
local-var]]
This makes my-context "look" correct (meaning that the data representation
of the code is correct when viewed with probe), but the inner function is
not bound into the context:
my-context/my-func ;expectedly yields an error
For completeness (to be sure that I understood the precept behind bind), I
also directly reassigned the function:
;### Method 2
;original
my-context: context [
local-var: 5
my-func: does [
print local-var
]
]
;make change
my-context/my-func: does [
print ["new print" local-var]
]
and again confirmed that an error occurs with my-context/my-func, because it
has not been bound into the context.
In the past, my tried and true way to make it work has been to "re-make" the
object with the new function:
;### Method 3
;original
my-context: context [
local-var: 5
my-func: does [
print local-var
]
]
;make change
my-context: make my-context [
my-func: does [
print ["new print" local-var]
]
]
which then works correctly when executing my-context/my-func (yields "new
print 5").
I understand the basic concepts behind scope and binding, and how these play
out in REBOL. It seems as though it should be easy enough to use bind, but
I can't figure out how to (successfully) do this when changing a function
within a context, at least with methods 1 and 2. Nothing wrong with method
3, but I would love to also be able to use method 1 or 2 with a
strategically and correctly placed bind statement. Any ideas?
--Scott Jones
[2/8] from: brett:codeconscious at: 5-Oct-2002 23:02
Not a general solution but given you are talking about edit-text, you could
try something like:
my-context: context [
local-var: 5
my-func: does [
print local-var
]
]
my-context/my-func: does bind [
print ["new print" local-var]
] in my-context 'self
Regards,
Brett.
[3/8] from: g:santilli:tiscalinet:it at: 5-Oct-2002 15:14
Hi Scott,
On Saturday, October 5, 2002, 2:27:53 PM, you wrote:
GSJ> ;### Method 1
GSJ> ;original
GSJ> my-context: context [
GSJ> local-var: 5
GSJ> my-func: does [
GSJ> print local-var
GSJ> ]
GSJ> ]
GSJ> ;make change
GSJ> insert remove remove pick pick pick my-context 2 3 2 [print ["new print"
GSJ> local-var]]
>> insert remove remove pick pick pick my-context 2 3 2 bind [print ["new print" local-var]]
in my-context 'self
== []
>> my-context/my-func
new print 5
GSJ> ;### Method 2
GSJ> ;original
GSJ> my-context: context [
GSJ> local-var: 5
GSJ> my-func: does [
GSJ> print local-var
GSJ> ]
GSJ> ]
GSJ> ;make change
GSJ> my-context/my-func: does [
GSJ> print ["new print" local-var]
GSJ> ]
>> my-context/my-func: does bind [print ["new print" local-var]] in my-context 'self
>> my-context/my-func
new print 5
HTH,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r
[4/8] from: gscottjones:mchsi at: 5-Oct-2002 8:52
Hi, Brett and Gabriele,
From: "Brett Handley"
...
> my-context: context [
> local-var: 5
<<quoted lines omitted: 5>>
> print ["new print" local-var]
> ] in my-context 'self
.. and moments later ..
From: "Gabriele Santilli"
> insert remove remove pick pick pick my-context 2 3 2 bind [print ["new
print" local-var]] in my-context 'self
..and ..
> my-context/my-func: does bind [print ["new print" local-var]] in
my-context 'self
Wow, you have both made it look so simple, but I can honestly say given your
solutions that I would have never figured this out, despite following the
list and reading Ladislav's and Patrick's bind comments. I guess this
demonstrates that a gap can still exist between reading concepts and
applying concepts.
Thanks!
--Scott Jones
[5/8] from: laurent::giroud::libertysurf::fr at: 5-Oct-2002 18:51
Hi Gabriele,
>>> my-context/my-func: does bind [print ["new print" local-var]] in my-context 'self
>>> my-context/my-func
> new print 5
reading your second example I came to the conclusion that 'bind must actually do
the binding then return the exact words it was passed as parameters.
Since "help bind" does not indicate what data 'bind effectively returns I tested
it directly by simply replicating only the last part of your example :
>> bind [print ["new print" local-var]] in my-context 'self
== [print ["other print" local-var]]
which confirms that 'bind effectively returns its first parameter.
But thinking a bit about this last line of code brought me more and more
questions.
First of all, in that test the word "self" is used in a context where it seems
to be innapropriate (there is no object lying around) : what does 'self refer to
in such a case ?
>> probe self
** Script Error: self has no value
** Where: halt-view
** Near: probe self
>> type? self
** Script Error: self has no value
** Where: halt-view
** Near: type? self
So do you have an idea why did my test not fail ? It seems like it should have
resulted in an error don't you think. Why is it not the cas ?
And finally, how does rebol exactly know how to correctly interpret 'self in
your example line ?
In it, you redefine a field of the my-context object : is it sufficient for
rebol to determine that the word self must refer to that object ?
I do not see clearly yet how and when rebol affects values to the 'self word.
Since context has much importance in rebol, I guess it's good to know such thing
;)
Regards,
Laurent
--
Laurent Giroud
[6/8] from: g:santilli:tiscalinet:it at: 5-Oct-2002 20:02
Hi Laurent,
On Saturday, October 5, 2002, 6:51:14 PM, you wrote:
LG> reading your second example I came to the conclusion that 'bind must actually do
LG> the binding then return the exact words it was passed as parameters.
It changes the argument block (unless the /COPY refinement is
used) and returns it.
LG> First of all, in that test the word "self" is used in a context where it seems
LG> to be innapropriate (there is no object lying around) : what does 'self refer to
LG> in such a case ?
First of all, notice it is a lit-word, and not a word. I.e. if you
write:
>> 'self
== self
you don't get an error, because you are not trying to get a value
from the word "self", but rather you are referring to the word
itself (thus "literal word").
After that, notice also that I wrote "in my-context 'self".
>> help in
USAGE:
IN object word
DESCRIPTION:
Returns the word in the object's context.
IN is a native value.
ARGUMENTS:
object -- (Type: object)
word -- (Type: word)
So "in my-context 'self" takes the word "self" and returns it
bound to the object's context. I used "self" just because any
object has that word. I could have used any other word in the
object. (If the passed word is not present in the object, IN
returns NONE.)
So we have:
(bind [...] (in my-context 'self))
BIND takes a word as its second argument, and binds the block
passed as its first argument to the same context to which that
word is bound. Since IN returns the word 'SELF bound to the
context of the object MY-CONTEXT, basically we are binding the
block to the context of the object MY-CONTEXT.
For better readability, one could write:
bind-to-object: func [block object] [bind block in object 'self]
and use that instead.
LG> Since context has much importance in rebol, I guess it's good to know such thing
LG> ;)
Absolutely. Feel free to ask.
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r
[7/8] from: laurent:giroud:libertysurf at: 5-Oct-2002 22:57
> For better readability, one could write:
> bind-to-object: func [block object] [bind block in object 'self]
> and use that instead.
Well, I am glad you clarified that one.
I had completely skipped the 'in function and the quote preceeding "self" thus
completely missing how the binding mecanism was actually taking place.
This looked like some kind of magic was operating there ;)
Thanks,
Laurent
--
Laurent Giroud
[8/8] from: brett:codeconscious at: 6-Oct-2002 15:24
For amusement, below are some examples of words bound to different contexts.
Just move throught the code by copying from the email and pasting bits of it
at a time into the console.
Regards,
Brett.
;
; Amusement 1
;
; BIND matches up words it can find in the target context.
ctx-1: context [country: "Australia"]
ctx-2: context [city: "Sydney"]
ctx-3: context [name: "Brett"]
expression: [join name [{ lives in } city {, } country]]
repeat ctx reduce [ctx-1 ctx-2 ctx-3] [bind expression in ctx 'self]
print expression
;
; Functions create a new context binding the words of their body block
; to their arguments:
my-func: func [name] expression
my-func "My wife"
;
; Amusement 2
;
; This first bit is straight forward - what appears to be
; nesting of contexts. As others have pointed out (probably
; more clearly than me) this is an effective or apparent
; nesting.
ctx-1: context [
word-a: #1a
word-b: #1b
word-c: #1c
ctx-2: context [
word-a: #2a
word-b: #2b
ctx-3: context [
word-a: #3a
set 'print-it does [
print ["First function" word-a word-b word-c]
]
]
]
]
print-it
;
; We can simulate the apparent scoping of CONTEXT with
; script that is obviously not nested...
;
ctx-1: context [word-a: #1a word-b: #1b word-c: #1c]
ctx-2: context [word-a: #2a word-b: #2b]
ctx-3: context [word-a: #3a]
contexts: reduce [ctx-1 ctx-2 ctx-3]
expression: [print ["Expression" word-a word-b word-c]]
repeat ctx contexts [bind expression in ctx 'self]
do expression
;
; Or indeed reverse it, or perhaps do other odd
; bindings.
;
reverse contexts
repeat ctx contexts [bind expression in ctx 'self]
do expression
;
; Amusement 3
;
; REBOL represents words to you using
; their names but does not have a visual representation for
; the context of those words.
; When you print the mold of the expression of this example
; you cannot see the difference between the two words that
; have the same name 'sample-word.
; Philosophical point:
; It is easy to fall into the trap of mistaking the name
; of a thing for the thing itself. As always with REBOL,
; the items you see in the console or in a file are not
; the things themselves but representations of the things.
ctx-1: context [sample-word: "Context1"]
ctx-2: context [sample-word: "Context2"]
expression: [{A word: }]
append expression in ctx-1 'sample-word
append expression [{^/A different word with the same name: }]
append expression in ctx-2 'sample-word
print expression
; This last example was admittedly contrived, and you
; wouldn't expect to see it used much. But I think
; it has value in showing a different way to look at
; REBOL words.
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted