oops.. just one little detail... 'SAME? isn't a mezz.. its a native...

-MAx

On Mon, Sep 14, 2009 at 4:56 PM, Maxim Olivier-Adlhoch <[email protected]> w=
rote:
> Hi Giuseppe,
>
> Sorry I didn't check the ML for a few days and yours slipped in the crack=
s!
>
> Here is a long and verbose explanation of most of what happens. =A0If
> something isn't clear, ask a precise question and I'll do my best to
> explain it further.
>
> so here we go... saddle-in, this is going to be a big ride into the
> depths of some REBOL Guru level secrets. =A0;-)
>
> I'll start by reposting the original code snippet as a reference:
>
> person: context [
> =A0 uid: func [/set value][data: [#[none]] =A0either set [data/1: value][=
data/1]]
> =A0 name: "me"
> ]
> ....
>>> =A0person/uid/set 222
> =3D=3D 222
>>> managers/ceo
> =3D=3D 222
>
>
> about functions as values
> ------------------------------------
> Basically, all rebol datatypes are evaluated when they are encountered
> by the interpreter. =A0because functions require no more syntax than a
> normal variable, they can be silently "slipped-in" as if they WHERE a
> simple variable (cause in fact they are! :-).
>
> The 'UID function, when created by the 'FUNC function creates a
> context for itself. =A0This context persists for as long as the function
> exists.
>
> If you notice the following:
>
> data: [#[none]]
>
> I assign a block! to 'DATA (I **DON'T** copy it at each function
> evaluation). =A0This block is actually part of the 'UID function's
> context when the function is created. =A0So it persists throughout that
> function's existence... This means every time 'UID is evaluated, 'DATA
> really is the same block, every time.
>
> When I simply ask for the value of 'UID =A0(person/uid), the function is
> evaluated as normal, and it returns the first data of the persistent
> block.
>
> When I use the function's /SET refinement, I simply stores a new value
> into this persistent block:
>
> data/1: value
>
> As a side note, remember that you can use blocks as indirections, a
> bit like double referencing in C. =A0Its a bit like saying get the first
> value pointed to by the block pointed to by 'DATA. =A0(I prefer to use
> the term "refers" and "contains" respectively though).
>
>
> About sharing functions across objects:
> --------------------------------------------------------
> Normally, when you make objects and use another object as the basis,
> all of the functions are copied to the new object bound and bound to
> it. =A0This means that any words which are present in the body of the
> function will now refer to those found in that object, or to those in
> the arguments of the function. =A0For example, if I had done this:
>
> employee: make person [
> =A0 title: "Workaholic"
> ]
>
> And tried the function trick, the 'UID function inherited from 'PERSON
> would not be shared because 'EMPLOYEE would contain a New &
> independent copy of the 'UID function with its own persistent function
> context.
>
> The trick is to tell 'MAKE, what we we explicitly want the 'UID to be:
>
> ('CONTEXT is a mezzanine function which simply does: =A0make object!)
>
> employee: context [
> =A0 uid: get in person 'uid
> =A0 title: "Workaholic"
> ]
>
> Here you see that we tell 'EMPLOYEE to use the exact same function as
> the one in person. =A0We 'GET it from the other object, and 'MAKE will
> assign it to the new object, at the location referred to by word 'UID
> in this new object.
>
> It won't be bound to the new 'EMPLOYEE object, and 'UID will actually
> be the same function as person/uid, NOT a copy of it.
>
> This is a VERY powerful feature of REBOL.
>
> From this point on, employee/uid and person/uid, being the same
> function, really share the same function context, so will set and get
> the same value.
>
>
> Function hack level 2
> -----------------------------
> You said you wanted other examples of the function trick... Here we'll
> go Fubar weird!!!
>
> Lets refer to values of =A0**another** object using 'SELF... =A0:-)
>
> ;------------------------ the code -------------------------
>
> person: context [
> =A0 =A0full-name: ["luke" "skywalker"]
> =A0 =A0first-name: func [/set val][either set [self/full-name/1:
> val][self/full-name/1]]
> =A0 =A0last-name: func [/set val][either set [self/full-name/2:
> val][self/full-name/2]]
> ]
>
> employee: context [
> =A0 =A0first-name: get in person 'first-name
> =A0 =A0last-name: get in person 'last-name
> =A0 =A0full-name: func [][reduce [first-name last-name]]
> ]
>
> ;--------------------------------------------------------------
>
>
> Within 'PERSON, we create a similar function-as-value trick, but this
> time, we use 'SELF to refer to the context (object!) the function is
> bound to, and then interact with another member of that object using
> path notation.
>
> 'EMPLOYEE, if you recognize the pattern explained earlier, simply
> borrows ('GETs) two of those functions-as-values and stores them in
> its own context... but notice a HUGE detail. =A0 'SELF in these
> functions, still refers to the 'PERSON object, because the functions
> are still bound to 'PERSON !!!
>
> 'FULL-NAME within 'EMPLOYEE, is bound normally since it is created by
> 'EMPLOYEE 's =A0make. =A0Meaning, it will evaluate whatever value is
> referred to by the words 'FIRST-NAME and 'LAST-NAME within 'EMPLOYEE.
>
> BUT!!! =A0These, as we just explained, are values taken from the other
> object, namely 'PERSON. =A0So basically, you have an object calling
> methods from another object, directly. =A0This is far beyond the level
> of control you can achieve with traditional inheritance and
> polymorphism, IMHO.
>
> You could go a step further and if you really wanted to go nuts with
> this, you could change the person which is assigned to the
> function-as-value referred by 'EMPLOYEE on the fly (but I won't go
> there for risk of loosing you for now ;-)
>
> All of this is AFAIK, a feature very few, if any, other languages
> allow you to do so "legally", safely and with so much detail and
> dynamic control.
>
> here are a few lines of console code which play around with the above
> "level 2" function hack:
>
>>> employee/full-name
> =3D=3D ["luke" "skywalker"]
>>> employee/first-name/set "bill"
> =3D=3D "bill"
>>> employee/full-name
> =3D=3D ["bill" "skywalker"]
>>> person/full-name
> =3D=3D ["bill" "skywalker"]
>>> same? person/full-name/1 employee/first-name
> =3D=3D true
>>> same? person/first-name employee/first-name
> =3D=3D true
>
> 'SAME is a mezzanine function that only returns True if its the same
> string, not just by its text content like equal?... it really is the
> same string "pointer" in memory.
>
> sweet isn't it ? =A0:-D
>
>
> about other uses of the function hack
> -----------------------------------------------------
> you might want to replace a value by an SQL statement
> function-as-a-value which is executed every time a value is needed...
> and if you set the value, it is inserted back directly... this way,
> you are sure that your data is coherent.
>
> In VID you can put functions instead of values for some facets...
> example are colors, texts & effects which change every time the face
> is shown... with a little tweak in the redraw :
>
> example:
>
> view layout [
> =A0 =A0button with [
> =A0 =A0 =A0 =A0texts: =A0reduce [ does [to-string counter] does [random "=
ABCDE"]]
> =A0 =A0 =A0 =A0colors: reduce [ does [random white] does [random white]]
> =A0 =A0 =A0 =A0effects: reduce [
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0does [reduce ['gradient 0x1 color color - =
75.75.75]]
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0does [reduce ['gradient 0x-1 color color -=
 75.75.75]]
> =A0 =A0 =A0 =A0]
> =A0 =A0]
> =A0 =A0feel [
> =A0 =A0 =A0 =A0 =A0 =A0redraw: func [face act pos /local state][
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0counter: counter + 1
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if all [face/texts face/texts/2] [
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0face/text: either face/state [face=
/texts/2] [face/texts/1]
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0]
> =A0 =A0 =A0 =A0 =A0 =A0if face/edge [face/edge/effect: pick [ibevel bevel=
] face/state]
> =A0 =A0 =A0 =A0 =A0 =A0state: either not face/state [face/blinker] [true]
> =A0 =A0 =A0 =A0 =A0 =A0if face/colors [face/color: either face/state
> [face/colors/2] [face/colors/1]]
> =A0 =A0 =A0 =A0 =A0 =A0if face/effects [face/effect: either face/state
> [face/effects/2] [face/effects/1]]
> =A0 =A0 =A0 =A0 =A0 =A0]
> =A0 =A0]
> ]
>
> here face/colors/2 is evaluated each time the face is drawn... so you
> might want to put an sql statement which checks if an error occurred
> on the db for example. =A0whenever the face is refreshed it will be up
> to date... which is pretty useful.
>
> the view face is not a normal object so most of the primitive facets
> (like color) will not respond if they are set to functions because the
> view engine actually uses the values directly.
>
> as an example if you put a function in face/text it will actually
> display ?function? as the text...
>
> but it should give you ideas on other uses... just the same.
>
> -MAx
>
>
> On Thu, Sep 3, 2009 at 5:38 AM, Giuseppe Chillemi
> <[email protected]> wrote:
>>
>>> person: context [
>>> =A0 =A0uid: func [/set value][data: [#[none]] =A0either set
>>> [data/1: value][data/1]]
>>> =A0 =A0name: "me"
>>> ]
>> .....
>>> >> =A0person/uid/set 222
>>> =3D=3D 222
>>> >> managers/ceo
>>> =3D=3D 222
>>> >>
>>>
>>> this is one way to use the function hack, but there are many
>>> others, and they depend on the application itself.
>>>
>>> there are a few little details when using the hack, but
>>> usually, its pretty invisible.
>>
>> Hello Maxim, I have read your interesting post but I want the details. H=
ow
>> it works ? What happens underneat (at interpeter and structure details) =
when
>> you read the value of UID using another object like "managers/ceo" =A0?
>> Also, I whis to know the notes you have omitted about this approach and
>> eventually which other approach exists...
>> There are a lot of things I still have to know about objects.
>>
>> Giuseppe Chillemi
>>
>> --
>> To unsubscribe from the list, just send an email to
>> lists at rebol.com with unsubscribe as the subject.
>>
>>
>
-- 
To unsubscribe from the list, just send an email to 
lists at rebol.com with unsubscribe as the subject.

Reply via email to