Global variable lookup

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

Global variable lookup

Bert Freudenberg
(reposting as separate thread)

I do wonder why Class>>bindingOf:environment: looks into the environment first, however. This means that a global variable would shadow an inherited class variable or pool variable, which is against my intuition of how scoping works. Does anyone know why this would be intended?

- Bert -


Reply | Threaded
Open this post in threaded view
|

Re: Global variable lookup

Eliot Miranda-2



On Fri, Jan 11, 2013 at 10:28 AM, Bert Freudenberg <[hidden email]> wrote:
(reposting as separate thread)

I do wonder why Class>>bindingOf:environment: looks into the environment first, however. This means that a global variable would shadow an inherited class variable or pool variable, which is against my intuition of how scoping works. Does anyone know why this would be intended?

FYI, the VisualWorks namespace system does bind inherited class vars before imports/globals.
--
best,
Eliot


Reply | Threaded
Open this post in threaded view
|

Re: Global variable lookup

Igor Stasenko
In reply to this post by Bert Freudenberg
FYI, this is a code from Pharo, which we are did _right_ (of course
from Pharo perspective ;)

Class>>bindingOf: varName
        "Answer the binding of some variable resolved in the scope of the
receiver, or nil
        if variable with such name is not defined"

        "The lookup recurses up to superclasses looking inside their class
and shared pools,
        but not the environment, since two classes, even if they have
ancestry relationship,
        could use different environments.
        That's why we doing an environment lookup only as a last step of symbol lookup
        and taking only the environment of receiver only, not any of it's
superclass(es) "
       
        | aSymbol binding |
        aSymbol := varName asSymbol.

        ^ (self innerBindingOf: aSymbol) ifNil: [
                 self environment bindingOf: aSymbol
        ]


Class>>innerBindingOf: aSymbol
        "Answer the binding of some variable resolved in the scope of the
receiver, or one of its superclass
        but do not look up binding in receiver's environment.
        Use #bindingOf: for looking up the variable binding in a full scope,
including receiver's environment"
       
        | binding |

        "First look in classVar dictionary."
        binding := self classPool bindingOf: aSymbol.
        binding ifNotNil: [^binding].

        "Next look in shared pools."
        self sharedPools do: [:pool |
                | aBinding |
                aBinding := pool bindingOf: aSymbol.
                aBinding ifNotNil: [^aBinding ].
        ].

        superclass ifNotNil: [
                ^ superclass innerBindingOf: aSymbol.
        ].
        ^ nil


On 11 January 2013 19:28, Bert Freudenberg <[hidden email]> wrote:
> bindingOf:environment:



--
Best regards,
Igor Stasenko.

Reply | Threaded
Open this post in threaded view
|

Re: Global variable lookup

Eliot Miranda-2



On Fri, Jan 11, 2013 at 11:05 AM, Igor Stasenko <[hidden email]> wrote:
FYI, this is a code from Pharo, which we are did _right_ (of course
from Pharo perspective ;)

+1.  local variable definitions override explicitly imported variable definitions inherited variable definitions override "global" variable definitions.

But does the system automatically recompile importers of shared pools when bindings are added or removed from shared pools?  At least Squeak does not.  And this is an issue in the context of loading Monticello packages.  With the VMMaker I refactored a lot of globals into shared p[ools when I decomposed ObjectMemory from the Interpreter hierarchy and added the Cogit hierarchy.  I would have to manually recompile to get the references right on e.g. moving a variable from being a class variable of ObjectMemory into some shared pool, or on moving the variable from one shared pool to another.
 

Class>>bindingOf: varName
        "Answer the binding of some variable resolved in the scope of the
receiver, or nil
        if variable with such name is not defined"

        "The lookup recurses up to superclasses looking inside their class
and shared pools,
        but not the environment, since two classes, even if they have
ancestry relationship,
        could use different environments.
        That's why we doing an environment lookup only as a last step of symbol lookup
        and taking only the environment of receiver only, not any of it's
superclass(es) "

        | aSymbol binding |
        aSymbol := varName asSymbol.

        ^ (self innerBindingOf: aSymbol) ifNil: [
                 self environment bindingOf: aSymbol
        ]


Class>>innerBindingOf: aSymbol
        "Answer the binding of some variable resolved in the scope of the
receiver, or one of its superclass
        but do not look up binding in receiver's environment.
        Use #bindingOf: for looking up the variable binding in a full scope,
including receiver's environment"

        | binding |

        "First look in classVar dictionary."
        binding := self classPool bindingOf: aSymbol.
        binding ifNotNil: [^binding].

        "Next look in shared pools."
        self sharedPools do: [:pool |
                | aBinding |
                aBinding := pool bindingOf: aSymbol.
                aBinding ifNotNil: [^aBinding ].
        ].

        superclass ifNotNil: [
                ^ superclass innerBindingOf: aSymbol.
        ].
        ^ nil


On 11 January 2013 19:28, Bert Freudenberg <[hidden email]> wrote:
> bindingOf:environment:



--
Best regards,
Igor Stasenko.




--
best,
Eliot


Reply | Threaded
Open this post in threaded view
|

Re: Global variable lookup

Bert Freudenberg
On 11.01.2013, at 11:19, Eliot Miranda <[hidden email]> wrote:

> On Fri, Jan 11, 2013 at 11:05 AM, Igor Stasenko <[hidden email]> wrote:
>> FYI, this is a code from Pharo, which we are did _right_ (of course
>> from Pharo perspective ;)
>>
> +1.  local variable definitions override explicitly imported variable definitions inherited variable definitions override "global" variable definitions.

Yep. Thanks Igor, that looks more reasonable.

>> But does the system automatically recompile importers of shared pools when bindings are added or removed from shared pools?  At least Squeak does not.  And this is an issue in the context of loading Monticello packages.  With the VMMaker I refactored a lot of globals into shared p[ools when I decomposed ObjectMemory from the Interpreter hierarchy and added the Cogit hierarchy.  I would have to manually recompile to get the references right on e.g. moving a variable from being a class variable of ObjectMemory into some shared pool, or on moving the variable from one shared pool to another.

Let's fix it.

- Bert -

>>  
>>
>> Class>>bindingOf: varName
>>         "Answer the binding of some variable resolved in the scope of the
>> receiver, or nil
>>         if variable with such name is not defined"
>>
>>         "The lookup recurses up to superclasses looking inside their class
>> and shared pools,
>>         but not the environment, since two classes, even if they have
>> ancestry relationship,
>>         could use different environments.
>>         That's why we doing an environment lookup only as a last step of symbol lookup
>>         and taking only the environment of receiver only, not any of it's
>> superclass(es) "
>>
>>         | aSymbol binding |
>>         aSymbol := varName asSymbol.
>>
>>         ^ (self innerBindingOf: aSymbol) ifNil: [
>>                  self environment bindingOf: aSymbol
>>         ]
>>
>>
>> Class>>innerBindingOf: aSymbol
>>         "Answer the binding of some variable resolved in the scope of the
>> receiver, or one of its superclass
>>         but do not look up binding in receiver's environment.
>>         Use #bindingOf: for looking up the variable binding in a full scope,
>> including receiver's environment"
>>
>>         | binding |
>>
>>         "First look in classVar dictionary."
>>         binding := self classPool bindingOf: aSymbol.
>>         binding ifNotNil: [^binding].
>>
>>         "Next look in shared pools."
>>         self sharedPools do: [:pool |
>>                 | aBinding |
>>                 aBinding := pool bindingOf: aSymbol.
>>                 aBinding ifNotNil: [^aBinding ].
>>         ].
>>
>>         superclass ifNotNil: [
>>                 ^ superclass innerBindingOf: aSymbol.
>>         ].
>>         ^ nil
>>
>>
>> On 11 January 2013 19:28, Bert Freudenberg <[hidden email]> wrote:
>> > bindingOf:environment:
>>
>
>
> --
> Best regards,
> Igor Stasenko.
>
>
>
>
> --
> best,
> Eliot
>



Reply | Threaded
Open this post in threaded view
|

Re: Global variable lookup

Igor Stasenko
In reply to this post by Eliot Miranda-2
On 11 January 2013 20:19, Eliot Miranda <[hidden email]> wrote:

>
>
>
> On Fri, Jan 11, 2013 at 11:05 AM, Igor Stasenko <[hidden email]> wrote:
>>
>> FYI, this is a code from Pharo, which we are did _right_ (of course
>> from Pharo perspective ;)
>
>
> +1.  local variable definitions override explicitly imported variable
> definitions inherited variable definitions override "global" variable
> definitions.
>
> But does the system automatically recompile importers of shared pools when
> bindings are added or removed from shared pools?  At least Squeak does not.

i did not checked, but i suspecting Pharo is on par with Squeak on this :)
You are right, changing pool should trigger recompilation of
all dependent classes.

> And this is an issue in the context of loading Monticello packages.  With
> the VMMaker I refactored a lot of globals into shared p[ools when I
> decomposed ObjectMemory from the Interpreter hierarchy and added the Cogit
> hierarchy.  I would have to manually recompile to get the references right
> on e.g. moving a variable from being a class variable of ObjectMemory into
> some shared pool, or on moving the variable from one shared pool to another.
>
>>
>>
>> Class>>bindingOf: varName
>>         "Answer the binding of some variable resolved in the scope of the
>> receiver, or nil
>>         if variable with such name is not defined"
>>
>>         "The lookup recurses up to superclasses looking inside their class
>> and shared pools,
>>         but not the environment, since two classes, even if they have
>> ancestry relationship,
>>         could use different environments.
>>         That's why we doing an environment lookup only as a last step of
>> symbol lookup
>>         and taking only the environment of receiver only, not any of it's
>> superclass(es) "
>>
>>         | aSymbol binding |
>>         aSymbol := varName asSymbol.
>>
>>         ^ (self innerBindingOf: aSymbol) ifNil: [
>>                  self environment bindingOf: aSymbol
>>         ]
>>
>>
>> Class>>innerBindingOf: aSymbol
>>         "Answer the binding of some variable resolved in the scope of the
>> receiver, or one of its superclass
>>         but do not look up binding in receiver's environment.
>>         Use #bindingOf: for looking up the variable binding in a full
>> scope,
>> including receiver's environment"
>>
>>         | binding |
>>
>>         "First look in classVar dictionary."
>>         binding := self classPool bindingOf: aSymbol.
>>         binding ifNotNil: [^binding].
>>
>>         "Next look in shared pools."
>>         self sharedPools do: [:pool |
>>                 | aBinding |
>>                 aBinding := pool bindingOf: aSymbol.
>>                 aBinding ifNotNil: [^aBinding ].
>>         ].
>>
>>         superclass ifNotNil: [
>>                 ^ superclass innerBindingOf: aSymbol.
>>         ].
>>         ^ nil
>>
>>
>> On 11 January 2013 19:28, Bert Freudenberg <[hidden email]> wrote:
>> > bindingOf:environment:
>>
>>
>>
>> --
>> Best regards,
>> Igor Stasenko.
>>
>
>
>
> --
> best,
> Eliot
>
>
>



--
Best regards,
Igor Stasenko.

Reply | Threaded
Open this post in threaded view
|

Re: Global variable lookup

Colin Putney-3
In reply to this post by Bert Freudenberg

On Fri, Jan 11, 2013 at 1:28 PM, Bert Freudenberg <[hidden email]> wrote:
I do wonder why Class>>bindingOf:environment: looks into the environment first, however. This means that a global variable would shadow an inherited class variable or pool variable, which is against my intuition of how scoping works. Does anyone know why this would be intended?

When adding the environment: argument, I preserved the existing logic from Class>>bindingOf:, so as not to break anything while bootstrapping, but I agree it's wrong.

I suspect that this is a holdover from the original Environments implementation, which lacked import/export between environments. Letting an environment shadow variables is the only way to override the superclass's environment. And without a way to do that, there can only be one environment!

Colin