Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

Pointers, Context in Rebol 3.0 (For the real Rebol Lovers)

 [1/10] from: gchillemi:aliceposta:it at: 23-Mar-2007 21:17


Hi to everyone, time ago I have been in front of a situation unsolvable within Rebol. Many of you gave me some suggestions compatible with Rebol but they used a different approach. Now that Rebol 3.0 is under development I want to submit to the mailing list this message... Think about an object with some functions inside template: make object! [ f1: func [a b] [a + b + aaa] f2: func [a b] [a * b + bbb] v1: now v2: [] v3: copy [] aaa: 1 bbb: 2 ] if you execute inst1: make template [] and then inst1/f1 3 4 you obtain 8 <- Correct Lets define a new function a1: func [a b] [a / b + aaa] and declare inst1: make template [f1: :a1] If you perform inst1/f1 3 4 aaa is no longer usable and it is reported to have no value. It seems rebol is not able to bind the new F1 to the context of the parent object. There could be a way to change this situation in Rebol 3.0 ? I would like to change the object fuction at object declaration and bid it to the context of the object which f1 belongs to automatically. A make/deep refinement would be good to. Now lets execute the following: a1: func [a b] [a / b] inst1: make template [f1: :a1] inst2: make template [f1: :a1] I expect that both inst1 and inst2 share the same "pointer to a1" Performing a: a1: func [a b] [a / b + 1] should change both INST1/f1 and INST2/f1 because they should point to the same function as I have declared [F1: :A1]. Instead only a1 is changed because a1 is copied during object creation and not pointed. For rebol 3.0 I ask you the ability to point to an external function like having a pointer to a function in C. Changing the pointed function should change the working of F1 in both the declared objects. Lets take both concept in one last line. For Rebol 3.0 I ask the ability to define many objects inst1: make template [f1: :a1] inst2: make template [f1: :a1] change the pointed function a1: func [a b] [a * b * bbb] with the effect of changing f1 in both INST1 and INST2 and having F1 able to access the object value bbb. If you introduce the "pointer to function" concept in some way we could declare (for example) 10.000 object and change the working of their inner functions with a simple line of code because we have declared them as pointers and not locally copied. What you think about this ? Giuseppe Chillemi

 [2/10] from: anton:wilddsl:au at: 24-Mar-2007 11:40


Remake the function, binding its body to the template object: inst1: make template [f1: func first :a1 bind second :a1 template] inst1/f1 3 4 ;== 1.75 Or, you could bind the body of the original function (now referred to as f1) : inst1: make template [f1: :a1 bind second :f1 template] Anton.

 [3/10] from: anton::wilddsl::net::au at: 24-Mar-2007 12:01


You can change the body code of the function
> a1: func [a b] [a / b] > > inst1: make template [f1: :a1] > inst2: make template [f1: :a1] > > I expect that both inst1 and inst2 share the same "pointer to a1"
a1 and f1 in each instance refer to the same function, yes.
> Performing a: > > a1: func [a b] [a / b + 1] > > should change both INST1/f1 and INST2/f1 because they should point to the > same function as I have declared [F1: :A1]. Instead only a1 is changed > because a1 is copied during object creation and not pointed.
You could do this: inst1: make template [] set in inst1 'f1 :a1 inst2: make template [] set in inst2 'f1 :a1 Another way is to put functions in a sub-object, just like face/feel. eg: template: context [ aaa: 1 funcs: context [f1: none f2: none] ] a1: func [a b] [a / b + 1] template/funcs/f1: :a1 inst1: make template [] inst2: make template [] inst1/funcs/f1 3 4 inst2/funcs/f1 3 4 These are a little bit uncomfortable. I think automatic copying in MAKE was a mistake. MAKE previously shared functions (ie. did not copy them). At the time of the discussion, people were confused about how VID worked and shared/copied its facets. I didn't have a strong opinion then because I wasn't sure myself, but these days I have a strong opinion of copying. --- AVOID it, because you can't "uncopy" afterwards. Regards, Anton.

 [4/10] from: Izkata:Comcast at: 23-Mar-2007 23:06


On Fri, 2007-03-23 at 21:17 +0100, Giuseppe Chillemi wrote:
> Now lets execute the following: > a1: func [a b] [a / b]
<<quoted lines omitted: 9>>
> having a pointer to a function in C. Changing the pointed function should > change the working of F1 in both the declared objects.
a1 is already a pointer to a function, not the function itself. That's why INST1/f1 and INST2/f1 aren't changing - you're making a new function and pointing a1 at it rather than the one INST1/f1 and INST2/f1 are pointing at. Take a look at this:
>> T: make object! [
[ f1: none [ aaa: 1 [ ]
>> A: func [a b][a + b + aaa] >> I1: make T [f1: :A] >> print mold get in I1 'f1
func [a b][a + b + aaa]
>> print mold get 'A
func [a b][a + b + aaa]
>> remove back tail second get 'A
== []
>> append second get 'A 1
== [a + b + 1]
>> print mold get in I1 'f1
func [a b][a + b + 1] f1: :A does not create a pointer to 'A, if pointers are how you want to think of it. It gets what 'A is pointing at, then points at the same thing. Setting a new value for 'A makes it point at something else - modifying it as above without making it point at something else will modify an others that are also pointing at it. The only downside is that the function arguments don't seem to be changeable:
>> clear second get 'A
== []
>> append second get 'A [print [{The answer is: } a * 2]]
== [print ["The answer is: " a * 2]]
>> clear first get 'A
== []
>> append first get 'A [a]
== [a b a]
>> print mold get in I1 'f1
func [a b][print ["The answer is: " a * 2]]
>> print mold get 'A
func [a b][print ["The answer is: " a * 2]]
>> clear first get 'A
== []
>> print mold get 'A
func [a b][print ["The answer is: " a * 2]] (These results are the same in both View 1.3.2/Core 2.6.3 and Core 2.7.5 on Ubuntu Linux.)

 [5/10] from: gregg::pointillistic::com at: 23-Mar-2007 22:47


Hi Giuseppe, GC> For rebol 3.0 I ask you the ability to point to an external GC> function like having a pointer to a function in C. Changing the GC> pointed function should change the working of F1 in both the GC> declared objects. I'm not sure how well the concept fits with the prototype-based model REBOL uses. It's not that it can't be done, I think Max has built a class-based object system in REBOL already. The question is whether this is a better solution than how we would do it today (what you might call workarounds :). Carl's latest blog posts about objects indicate that there will be more flexibility in R3 objects. I'd like to hear some of the gurus weigh in on this too. -- Gregg

 [6/10] from: gabriele::colellachiara::com at: 24-Mar-2007 11:30


Hi Giuseppe, On Friday, March 23, 2007, 9:17:11 PM, you wrote: GC> aaa is no longer usable and it is reported to have no value. It seems rebol GC> is not able to bind the new F1 to the context of the parent object. It's not able to do so *automatically*. (And it shouldn't.) You just need to use BIND.
>> o: make object! [f: does [a] a: 1] >> o/f
== 1
>> f2: does [a] >> o2: make o [f: :f2] >> o2/f
** Script Error: a has no value ** Where: f ** Near: a
>> bind second :f2 o2
== [a]
>> o2/f
== 1 GC> There could be a way to change this situation in Rebol 3.0 ? Short answer: no. GC> a1: func [a b] [a / b] GC> inst1: make template [f1: :a1] GC> inst2: make template [f1: :a1] GC> I expect that both inst1 and inst2 share the same "pointer to a1" No - your model is just wrong here. You have three different words and all refer to the same value. If you change the value a word is referring, there's no reason why the value any other word is referring should change. a1 -----\ f1 --------> func [a b] [a / b] f1 -----/ You are just changing the arrow for a1; this operation should not have any effect on the arrows of the two f1. (They don't even know about a1.) (Please note that the above diagram is simplified.) GC> Performing a: GC> a1: func [a b] [a / b + 1] GC> should change both INST1/f1 and INST2/f1 because they should point to the GC> same function as I have declared [F1: :A1]. Just use something like f1: func [a b] [a1 a b] instead. GC> For rebol 3.0 I ask you the ability to point to an external function like GC> having a pointer to a function in C. Changing the pointed function should GC> change the working of F1 in both the declared objects. Changing the pointed function means something like: change second :a1 and *not* a1: some-new-thing The latter does *not* change the "pointed" function. GC> If you introduce the "pointer to function" concept in some way we could GC> declare (for example) 10.000 object and change the working of their inner GC> functions with a simple line of code because we have declared them as GC> pointers and not locally copied. They are *not* copied, they are the same function value. (And this is actually a problem, because it can't be bound to different contexts!) But changing the word does not change the value. Regards, Gabriele. -- Gabriele Santilli <gabriele-rebol.com> --- http://www.rebol.com/ Colella Chiara software division --- http://www.colellachiara.com/

 [7/10] from: gchillemi:aliceposta:it at: 27-Mar-2007 20:55


> You can change the body code of the function > > a1: func [a b] [a / b]
<<quoted lines omitted: 4>>
> > I expect that both inst1 and inst2 share the same "pointer to a1" > a1 and f1 in each instance refer to the same function, yes.
In other words if I write a1: func [a b] [a + b * a] I force a1 to point to something else while inst1/f1 point to the old function a1 pointed to. Previously I thought that f1: :a1 was meaning "use a1 as pointer to the function and f1 will point to whather a1 is pointing". Changing the pointer should change the function pointed to. Now it is clear that inst1/f1 point to the content of a1 ant not to the content which the pointer a1 is pointing too (subtle difference)
> You could do this: > > inst1: make template [] set in inst1 'f1 :a1 > inst2: make template [] set in inst2 'f1 :a1
Nice, but this does not solve the problem of using values contained inside the object. As Gabriele Santilli noted in its message I must add bind second :a1 inst1 bind second :a1 inst2 to let a1 content see the values inside the objects
> Another way is to put functions in a sub-object, > just like face/feel. eg:
<<quoted lines omitted: 9>>
> inst2/funcs/f1 3 4 > These are a little bit uncomfortable.
I'll further investigate on this solution, I still do not understand the difference. Could you explain ? Giuseppe Chillemi

 [8/10] from: gchillemi::aliceposta::it at: 27-Mar-2007 21:10


> No - your model is just wrong here. You have three different words > and all refer to the same value. If you change the value a word is
<<quoted lines omitted: 6>>
> have any effect on the arrows of the two f1. (They don't even know > about a1.)
...
> Changing the pointed function means something like: > > change second :a1 > > and *not* > > a1: some-new-thing > > The latter does *not* change the "pointed" function.
Your message opened my eyes. Now I understand the problem and the solution. Where I could find some documentation on object to understand the results I get using the following commands: myobj: make object! [a: 1] obj: make myobj [] probe first :obj
> [self a]
probe second :obj
> [make object! [ > a: 1 > ] 1]
probe third :obj
> [a: 1]
probe fourth :obj1 ** Script Error: fourth expected series argument of type: series date port tuple event ** Where: halt-view ** Near: probe fourth :obj
> They are *not* copied, they are the same function value. (And this > is actually a problem, because it can't be bound to different > contexts!) But changing the word does not change the value.
I do not understand why it is actually a problem, could you explain ? Giuseppe Chillemi

 [9/10] from: gabriele::colellachiara::com at: 28-Mar-2007 0:16


2007/3/27, Giuseppe Chillemi <gchillemi-aliceposta.it>:
> Where I could find some documentation on object to understand the results I > get using the following commands:
I think this should be in the Core guide somewhere... but anyway:
> probe first :obj > > [self a]
You can model a context as a pair of blocks. The first block can only contain word! values; the second block contains the values that are associated with the words in the first block. So if the first block is [a b c] and the second block is [1 2 3], a is associated with 1, b with 2 and c with 3. FIRST on an object returns the first block. So it's basically the list of words in the context. keep in mind that the words in this block are not bound.
> probe second :obj > > > [make object! [ > > a: 1 > > ] 1]
SECOND returns the second block, so the block of values. Here you can see the values of SELF and A. SELF obviously refers to the object itself.
> probe third :obj > > > [a: 1]
THIRD was added more recently. It returns a block that can be used with CONSTRUCT to recreate the object. So, SELF is omitted (because it is created automatically for object, and for obvious reasons), and you just get [a: 1].
> > They are *not* copied, they are the same function value. (And this > > is actually a problem, because it can't be bound to different > > contexts!) But changing the word does not change the value. > > I do not understand why it is actually a problem, could you explain ?
Since the function is not copied, the body block is the same for all the objects. So are the words contained in it. But a word can only be bound to one context at a time. So you cannot have the function bound to more than one of your objects. If you bind it to INST1 you lose the binding to INST2 and viceversa. If you want to share the function across contexts, you need to pass it the instance as argument expliticly, otherwise you need a copy of the function for each object. Indeed, in REBOL methods (which are called actions - see the action! type) are usually not put in the object at all, and the object is just the first argument of the function. Regards, Gabriele.

 [10/10] from: anton::wilddsl::net::au at: 28-Mar-2007 15:23


Giuseppe,
> > You can change the body code of the function > >
<<quoted lines omitted: 17>>
> is pointing > too (subtle difference)
Yes, I can understand the confusion, and that would be a cool trick if it were possible. But, no, using a get-word (:a1) is just a "safe" way of getting the function value without evaluating it.
> > You could do this: > >
<<quoted lines omitted: 5>>
> bind second :a1 inst2 > to let a1 content see the values inside the objects
Aha, I forgot about binding. Yes, you would have to bind your function body to the correct object just before each time you call the function. eg: template: context [ aaa: 1 f1: none ] a1: func [a][a + aaa] inst1: make template [f1: :a1] inst2: make template [f1: :a1 aaa: 2] bind second :a1 inst1 inst1/f1 10 ;== 11 bind second :a1 inst2 inst2/f1 10 ;== 12 Or, you could pass the object instance to the function as an argument and use path notation to access each object's words (just like FEEL), eg: template: context [ aaa: 1 feel: context [ f1: func [obj a][a + obj/aaa] ] ] inst1: make template [] inst2: make template [aaa: 2] inst1/feel/f1 inst1 10 ;== 11 inst1/feel/f1 inst2 10 ;== 12 To avoid path notation the function can bind its body code to the passed object, thus: template: context [ aaa: 1 feel: context [ f1: func [obj a][do bind [a + aaa] obj] ] ]
> > Another way is to put functions in a sub-object, > > just like face/feel. eg:
<<quoted lines omitted: 17>>
> difference. Could you explain ? > Giuseppe Chillemi
Anton.

Notes
  • Quoted lines have been omitted from some messages.
    View the message alone to see the lines that have been omitted