Object private member (was: objects: overhead, private data, naming
[1/8] from: dockimbel:free at: 20-Sep-2001 15:20
Hi Christophe,
CRS - Psy Sel/SPO, COUSSEMENT, Christophe, CPN
wrote:
> Hi REBOLians:
> About object private members, could anybody explain this to me:
<<quoted lines omitted: 7>>
> ]
> </code>
[...]
> So... it looks like within an object, the use of 'set invoque a
> privatization of the word, which is not any more visible from the outside.
No, you've defined '_b and 'get-b in the global context ! That's why o/_b and
o/get-b return an error.
>>_b
== 10
>>get-b
10
Regards,
DocKimbel.
[2/8] from: joel::neely::fedex::com at: 20-Sep-2001 3:22
Hi, Christope,
It's the other way 'round!
CRS - Psy Sel/SPO, COUSSEMENT, Christophe, CPN
wrote:
> Hi REBOLians:
>
> About object private members, could anybody explain this
> to me:
>
...
> So... it looks like within an object, the use of 'set
> invoque a privatization of the word, which is not any more
> visible from the outside.
>
No. The use of SET affects the global context, rather than
the context of the object you're constructing.
>> o: context [
[ _a: 5
[ set '_b 10
[ get-a: does [print-a]
[ set 'print-a does [print _a]
[ set 'get-b does [print _b]
[ ]
>> get-b
10
> Great: I can use this property for making private members,
> but this way of doing is still strange to me.
>
Sorry. This can't be used to create private members.
> Any clue why a 'set-word! has two different ways of
> handling things, within this context ?
>
You'd have to get someone from RT (Holger? Comments, please?)
to explain the original motivation, but there are some easy-
to-notice consequences. Notice first that
>> source o
o:
make object! [
_a: 5
get-a: func [][print-a]
]
shows us that not everything done during the creation of an
object ends up *in* the object. This allows us to do
something like the following:
>> obj-count: 0
== 0
>> obj-spec: [x: 0 y: 0 set 'obj-count obj-count + 1]
== [x: 0 y: 0 set 'obj-count obj-count + 1]
;; now we can make a bunch of similar objects...
>> ob1: make object! obj-spec
>> ob2: make object! obj-spec
>> ob3: make object! obj-spec
;; ...and keep up with how many there are...
>> obj-count
== 3
;; ...without any overhead within the individual objects!
>> source ob1
ob1:
make object! [
x: 0
y: 0
]
The object specification is simply a block of REBOL that is
evaluated in a special way; set-words in the object spec cause
new words to be placed in the context under construction, but
everything else just does whatever it does normally. You can
take advantage of this fact in a variety of ways:
>> chatty-spec: [
[ print "Hi! I'm making another object"
[ set 'obnr obnr + 1
[ selfnr: obnr
[ print ["This new object is numbered" obnr]
[ set 'temp now/time
[ selfwhen: temp
[ print ["and was created at" temp]
[ print "I've finished now!"
[ ]
== [
print "Hi! I'm making another object"
set 'obnr obnr + 1
selfnr: obnr
print ["This new object is numbered"...
>> obnr: 0
== 0
(Notice that both OBNR and TEMP are globals, but only OBNR needs
to be initialized.)
>> o1: make object! chatty-spec
Hi! I'm making another object
This new object is numbered 1
and was created at 3:19:42
I've finished now!
>> o2: make object! chatty-spec
Hi! I'm making another object
This new object is numbered 2
and was created at 3:19:50
I've finished now!
>> o3: make object! chatty-spec
Hi! I'm making another object
This new object is numbered 3
and was created at 3:19:59
I've finished now!
>> source o1
o1:
make object! [
selfnr: 1
selfwhen: 3:19:42
]
HTH!
-jn-
--
------------------------------------------------------------
Programming languages: compact, powerful, simple ...
Pick any two!
joel'dot'neely'at'fedex'dot'com
[3/8] from: coussement:c:js:mil:be at: 20-Sep-2001 15:57
Maarten & DocKimbel:
Thanks for the fast answer !
I didn't know this ;-(
Thanks to this ml and you guys, I feel I'm getting a little bit more
clever every day :)
Long life to REBOL!
==christophe
[4/8] from: rotenca:telvia:it at: 20-Sep-2001 20:25
Hi, Joel
> No. The use of SET affects the global context, rather than
> the context of the object you're constructing.
No. It affects the context to which the word is dinamically binded, in this
example a Use block:
>> a: 1 use [a] [x: context [b: 2 set 'a 3] print a] print a
3
1
in the context in which 'set is called, "a" is binded to the use block, so
'set affect the use-binded 'a:
In the next example 'set affect the 'a binded to the object 'x and do not
change the global 'a or the use 'a:
>> a: 1
== 1
>> use [a] [a: 2 x: context [a: 3 set 'a 4 ] print ["Use:" a]]
Use: 2
>> print ["Global:" a "Object:" x/a]
Global: 1 Object: 4
To explain, lets take this simple example:
context [a: 3]
At the start Rebol creates a new context with the word 'a unset, while self
points to the context:
>> context [print mold first get 'self a: 3]
[self a]
>> context [print [a] a: 3]
?unset?
>> context [print mold third self a: 3]
[a:]
It is like if the code would be:
context compose [a: (())]
Now Rebol execute the block: [a: 3] and it finds:
a: 3
and bind 'a to the Actual context: at that time, the Actual context says that
the 'a is local to the object 'x, so x/a is set and becomes = 3. Which is the
result we are waiting.
Now get this example:
context [a: 3 set 'a 4 ]
After all the pass we have already seen we have:
set 'a 4
Rebol binds 'a to the Actual context. In this case:
'set -> global
'a -> object
then executes the code which changes the value of x/a not of global 'a.
In this new example:
>> a: 1 context [set 'a 4 print a a: 3 print a] a
4
3
== 1
Rebol first unset x/a, then set it at 4 then set it at 3, while the global 'a
remain unchanged.
So, in the block the word argument of set is always bound to the object, only
if the word is not defined in the object, the bind default to the external
context of the object:
context [set 'b 4 a: 3] ; b is global because 'b is NOT defined in the object
use [b][context [set 'b 4 a: 3]] ; b is local at Use block because 'b is NOT
defined in the object
use [b][context [set 'b 4 b: 3]] ;b is local at object, because 'b IS defined
in the object
> -jn-
-----
ciao
romano
[5/8] from: coussement:c:js:mil:be at: 21-Sep-2001 11:05
Romano & Joel:
Thanks guys ! This thread is becoming _very_ interesting ;-) It does me
recall one about embedded objects a few months ago.
Let's go back to the subject of the first post (from Gregg Irwin I think)
...
If I have understand all it has been written - which I seriously doubt ;) -
it should be possible to implement privacy in a way, using the property "use
[b][context [set 'b 4 a: 3]]" where "b is local at Use block because 'b is
NOT defined in the object" :
<code>
;--- (using Gregg's naming convention:)
use [_print-a _print-b _b][
ctx: context [
;--> declare public members
a: 5
get-a: does [_print-a]
get-b: does [_print-b]
;--> declare private members
set '_b 20
set '_print-a does [print a]
set '_print-b does [print _b]
]
]
</code>
So, the private members should be only _visible_ from inside the context of
the object...
Let's test it:
>>; are the public members visible from the global
[ context, through the object definition ?
>> ctx/a
== 5
>>; are the public members visible from the global
[ context, and are the private members visible from
[ inside the object ?
>> ctx/get-a
5
>> ctx/get-b
20
>>; YES => OK
>>; are any members directly visible from the
[ global context ?
>> a
** Script Error: a has no value
** Near: a
>> _b
** Script Error: _b has no value
** Near: _b
>> _print-a
** Script Error: _print-a has no value
** Near: _print-a
>> _print-b
** Script Error: _print-b has no value
** Near: _print-b
>>; NO => OK
>>; are the private members visible from the
[ global context, through the object definition ?
>> ctx/_b
** Script Error: Invalid path value: _b
** Near: ctx/_b
>> ctx/_print-a
** Script Error: Invalid path value: _print-a
** Near: ctx/_print-a
>> ctx/_print-b
** Script Error: Invalid path value: _print-b
** Near: ctx/_print-b
>>; NO => OK
Isn't it the effect we were trying to reach, or did I miss something ?
==christophe
[6/8] from: rotenca:telvia:it at: 21-Sep-2001 14:55
> Romano & Joel:
> Thanks guys ! This thread is becoming _very_ interesting ;-) It does me
<<quoted lines omitted: 6>>
> NOT defined in the object" :
> Isn't it the effect we were trying to reach, or did I miss something ?
Yes, you are right. You can make it with Use, like in example or with context.
Here _b _print-a _print-p are not lit-word, so are not defined in the object
and their words are bound to the Use block, while ctx is global because is not
declared in the use block.
Remark 1. If you now make:
ctx2: context ctx []
ctx and ctx2 share all the privates field ('_b _print-a _print-b) while public
field ('a) is not the same. The private _b... are shared by all the objects
wich use ctx model (or ctx2 model an so on).
Remark 2. If you do:
ctx2: context ctx [_b: 0]
ctx2/get-b will access always the '_b local to the use block.
Remark 3. It is possible write a routine which changes the value of use _b
from the inner of the object:
;public
set-b: func [value][_set-b :value]
....
;private
set '_set-b func [value] [set/any '_b :value]
Remark 4: it is possible to write generic routines for getting/removing
private values:
;private
set '_set-private func [word [word!] value] [set/any bind :word '_set-private
:value]
set '_get-private func [word [word!]] [get/any bind :word '_get-private]
then they need public stub routines.
Or write routines which return by default the private value or the public if
declared.
I think there are few limits and that should be a good idea to write a routine
which create this type of contexts:
make-object: func [public [block!] private [block!] routine [block!]]
it should contrust the code and Use block on the fly and execute it.
---
Ciao
Romano
[7/8] from: rotenca::telvia::it at: 21-Sep-2001 16:02
errata corr.
> Yes, you are right. You can make it with Use, like in example or with
context.
> Here _b _print-a _print-p are not lit-word, so are not defined in the object
^^^^^^^
set-word
---------
ciao
romano
[8/8] from: greggirwin:starband at: 21-Sep-2001 10:13
Re: Object private member (was: objects: overhead, private data, naming
WOW!! Thanks for all your investigative efforts Christophe! So, it *is*
possible. I think this is a very important idiom that we all need to
remember. For building large systems, or components to be used by others,
this is invaluable. Now, using what you've discovered, I need to find time
to play around, learn about use, and see what happens when you start
inspecting contexts reflectively. E.g. if you have an object browser, what
will he be able to find out about an object.
Thanks again!
--Gregg
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted