How to escape implicit 'with (this)' of a method body

classic Classic list List threaded Threaded
18 messages Options
Reply | Threaded
Open this post in threaded view
|

How to escape implicit 'with (this)' of a method body

Michael Haufe-2
function foo () { return 'global'; }

class bar {
   function foo () { return 'local'; }

   function zot () {
     // How can I call the global foo from here?
     without (this) { foo(); }
   }
}


You could use window["foo"](); or whatever the global object is named in the environment

_______________________________________________
Es4-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es4-discuss
Reply | Threaded
Open this post in threaded view
|

Re: How to escape implicit 'with (this)' of a method body

P T Withington
On 2008-07-28, at 18:22EDT, Michael Haufe wrote:

> /function foo () { return 'global'; }
>
> class bar {
>  function foo () { return 'local'; }
>
>  function zot () {
>    // How can I call the global foo from here?
>    without (this) { foo(); }
>  }
> }/
>
> You could use window["foo"](); or whatever the global object is  
> named in the environment

Shouldn't there be an es4 standard way of doing it, without relying on  
a particular environment?

class bar {
  function foo () { return 'local'; }

  // I guess this should work, but it seems rather kludgey
  static function globalfoo (...) { return foo(...); }
  function zot () {
    globalfoo();
}
_______________________________________________
Es4-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es4-discuss
Reply | Threaded
Open this post in threaded view
|

Re: How to escape implicit 'with (this)' of a method body

Brendan Eich-2
In reply to this post by Michael Haufe-2
On Jul 28, 2008, at 3:22 PM, Michael Haufe wrote:
function foo () { return 'global'; }

class bar {
   function foo () { return 'local'; }

   function zot () {
     // How can I call the global foo from here?
     without (this) { foo(); }
   }
}

It's the same as if you lambda-coded the above (here shown in JS1.8 [Firefox 3], note the expression closures):

function bar() {
  function foo() 'local';
  function zot() global.foo();
}
function foo() 'global';

This example uses ES4's global synonym for the global object, but you could capture this in a global var at top level:

var global = this;
print(new bar().zot()); // print 'global'

in ES3 or JS1.8 to get the same effect.

You could use window["foo"](); or whatever the global object is named in the environment

No need to quote and bracket, of course -- window.foo() is fine too.

/be


_______________________________________________
Es4-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es4-discuss
Reply | Threaded
Open this post in threaded view
|

Re: How to escape implicit 'with (this)' of a method body

Brendan Eich-2
On Jul 28, 2008, at 9:46 PM, Brendan Eich wrote:

On Jul 28, 2008, at 3:22 PM, Michael Haufe wrote:
function foo () { return 'global'; }

class bar {
   function foo () { return 'local'; }

   function zot () {
     // How can I call the global foo from here?
     without (this) { foo(); }
   }
}

It's the same as if you lambda-coded the above (here shown in JS1.8 [Firefox 3], note the expression closures):

function bar() {
  function foo() 'local';
  function zot() global.foo();

+  return {foo: foo, zot: zot};

}
function foo() 'global';

This example uses ES4's global synonym for the global object, but you could capture this in a global var at top level:

var global = this;
print(new bar().zot()); // print 'global'

in ES3 or JS1.8 to get the same effect.

/be

_______________________________________________
Es4-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es4-discuss
Reply | Threaded
Open this post in threaded view
|

Re: How to escape implicit 'with (this)' of a method body

Jon Zeppieri-2
In reply to this post by Brendan Eich-2
2008/7/29 Brendan Eich <[hidden email]>:

> On Jul 28, 2008, at 3:22 PM, Michael Haufe wrote:
>
> function foo () { return 'global'; }
>
> class bar {
>    function foo () { return 'local'; }
>
>    function zot () {
>      // How can I call the global foo from here?
>      without (this) { foo(); }
>    }
> }
>
> It's the same as if you lambda-coded the above (here shown in JS1.8 [Firefox
> 3], note the expression closures):
> function bar() {
>   function foo() 'local';
>   function zot() global.foo();
> }
> function foo() 'global';
> This example uses ES4's global synonym for the global object, but you could
> capture this in a global var at top level:
> var global = this;
> print(new bar().zot()); // print 'global'
> in ES3 or JS1.8 to get the same effect.
>
> You could use window["foo"](); or whatever the global object is named in the
> environment
>
> No need to quote and bracket, of course -- window.foo() is fine too.
> /be

Isn't the 'with' statement in the original example significant?  In
the general case, assuming that you don't know what properties 'this'
has (as it may have dynamic properties in addition to the fixtures
determined by its class), you have no way of knowing whether 'global'
or 'window' refers to the global object or to some arbitrary property
of 'this.'

-Jon


>
> _______________________________________________
> Es4-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es4-discuss
>
>
_______________________________________________
Es4-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es4-discuss
Reply | Threaded
Open this post in threaded view
|

Re: How to escape implicit 'with (this)' of a method body

Brendan Eich-2
On Jul 28, 2008, at 10:05 PM, Jon Zeppieri wrote:

> Isn't the 'with' statement in the original example significant?  In
> the general case, assuming that you don't know what properties 'this'
> has (as it may have dynamic properties in addition to the fixtures
> determined by its class), you have no way of knowing whether 'global'
> or 'window' refers to the global object or to some arbitrary property
> of 'this.'

The original code used "without (this)", not "with", which I took to  
mean "avoid instance properties shadowing globals". If you read the  
original as "with", then there is no such problem. But if you  
construct a problematic case using 'with' and dynamic properties,  
then I concede that 'global' could be shadowed. This is a reason to  
avoid 'with'. In the ES4 proposals last sent out, you could always  
use __ES4__::global if you really wanted to avoid conflicts -- unless  
someone perversely added '__ES4__' as a dynamic instance property.

There's no solution to this problem other than reserving at least one  
name, and we can't do that compatibly. We could reserve __ES4__ in  
version-selected ES4 mode, but that seems unnecessary.

/be

_______________________________________________
Es4-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es4-discuss
Reply | Threaded
Open this post in threaded view
|

Re: How to escape implicit 'with (this)' of a method body

Jon Zeppieri-2
In reply to this post by Jon Zeppieri-2
On Tue, Jul 29, 2008 at 1:05 AM, Jon Zeppieri <[hidden email]> wrote:
>>    function zot () {
>>      // How can I call the global foo from here?
>>      without (this) { foo(); }
>>    }
>> }

Oh... yeah, I misread that.
And the 'implicit' in the subject.
_______________________________________________
Es4-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es4-discuss
Reply | Threaded
Open this post in threaded view
|

Re: How to escape implicit 'with (this)' of a method body

P T Withington
In reply to this post by Brendan Eich-2
On 2008-07-29, at 01:19EDT, Brendan Eich wrote:

> On Jul 28, 2008, at 10:05 PM, Jon Zeppieri wrote:
>
> The original code used "without (this)", not "with", which I took to  
> mean "avoid instance properties shadowing globals".

Indeed.  Perhaps I was being too clever in my pseudo-code.

> If you read the original as "with", then there is no such problem.  
> But if you construct a problematic case using 'with' and dynamic  
> properties, then I concede that 'global' could be shadowed. This is  
> a reason to avoid 'with'. In the ES4 proposals last sent out, you  
> could always use __ES4__::global if you really wanted to avoid  
> conflicts -- unless someone perversely added '__ES4__' as a dynamic  
> instance property.
>
> There's no solution to this problem other than reserving at least  
> one name, and we can't do that compatibly. We could reserve __ES4__  
> in version-selected ES4 mode, but that seems unnecessary.

I guess this is considered a small penalty to pay in exchange for  
adding the magical instance scope to methods (which O-O programmers  
seem to expect these days).  Something we'd regret more if we had  
multi-methods, perhaps...
_______________________________________________
Es4-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es4-discuss
Reply | Threaded
Open this post in threaded view
|

Re: How to escape implicit 'with (this)' of a method body

Dave Herman-2
>> There's no solution to this problem other than reserving at least  
>> one name, and we can't do that compatibly. We could reserve __ES4__  
>> in version-selected ES4 mode, but that seems unnecessary.
>
> I guess this is considered a small penalty to pay in exchange for  
> adding the magical instance scope to methods (which O-O programmers  
> seem to expect these days).  Something we'd regret more if we had  
> multi-methods, perhaps...

We should take this problem seriously. OO programmers expect dynamic
dispatch, but not dynamic scope! In OO languages with static type
systems, you can tell when a variable reference is being dynamically
dispatched because of the types. In traditional JavaScript, you can tell
dynamic dispatch is happening because the `this.' prefix is always
required. But now with classes, since we don't have a static type system
to know whether a dynamically inserted property might shadow a lexical
reference, dynamic scope has slipped in.

Dynamic scope is very bad.

Another solution is to require the `this.' prefix even inside classes,
just as they are required everywhere else, so you can distinguish
between a dynamically referenced variable and a lexically referenced
variable. I think Python (a more-or-less lexically scoped but
dynamically typed OO language) requires this? (Pythonistas please
correct me if I'm wrong.) If five characters are really too hard to
write, there's always the possibility of the `.foo' shorthand syntax.

Dave
_______________________________________________
Es4-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es4-discuss
Reply | Threaded
Open this post in threaded view
|

Re: How to escape implicit 'with (this)' of a method body

Dave Herman-2
> We should take this problem seriously. ...
>
> Dynamic scope is very bad.

Specifically:

- Classes are supposed to provide integrity, but dynamic scope makes the
internals of code brittle; any variable reference inside the
implementation could be subverted by the seemingly innocuous insertion
of a property.

- Dynamic dispatch has a reasonably understandable cost model, but only
if it's confined to explicit property references. With dynamic scope,
any variable reference could potentially be very expensive.

- Generally, code within a `with' block is brittle and hard to
understand, and as Tucker says, the implicit `this.' means that all code
inside class methods is within a `with' block... this means that all
code inside class methods is brittle!

- In the past, this has been enough for many programmers to deprecate
all use of `with' -- we should certainly hope to avoid the same
happening for classes.

Dave
_______________________________________________
Es4-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es4-discuss
Reply | Threaded
Open this post in threaded view
|

Re: How to escape implicit 'with (this)' of a method body

P T Withington
On 2008-07-31, at 08:24EDT, Dave Herman wrote:

>> We should take this problem seriously. ...
>> Dynamic scope is very bad.
>
> Specifically:
>
> - Classes are supposed to provide integrity, but dynamic scope makes  
> the internals of code brittle; any variable reference inside the  
> implementation could be subverted by the seemingly innocuous  
> insertion of a property.
>
> - Dynamic dispatch has a reasonably understandable cost model, but  
> only if it's confined to explicit property references. With dynamic  
> scope, any variable reference could potentially be very expensive.
>
> - Generally, code within a `with' block is brittle and hard to  
> understand, and as Tucker says, the implicit `this.' means that all  
> code inside class methods is within a `with' block... this means  
> that all code inside class methods is brittle!
>
> - In the past, this has been enough for many programmers to  
> deprecate all use of `with' -- we should certainly hope to avoid the  
> same happening for classes.

CLOS (Lisp) has something very like 'reformed with' to let you write  
shorter method bodies without magic:

http://www.lispworks.com/documentation/HyperSpec/Body/m_w_slts.htm

Here's my take at an example of brittleness:

var bar = 42;

class foo {
   function zot () { return bar; }
}

...

class subfoo extends foo {
   var bar = 'oops!';
}

(new foo).zot() => 42
(new myfoo).zot() => ?


_______________________________________________
Es4-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es4-discuss
Reply | Threaded
Open this post in threaded view
|

Re: How to escape implicit 'with (this)' of a method body

Peter Hall-4
> Here's my take at an example of brittleness:
>
> var bar = 42;
>
> class foo {
>   function zot () { return bar; }
> }
>
> ...
>
> class subfoo extends foo {
>   var bar = 'oops!';
> }
>
> (new foo).zot() => 42
> (new myfoo).zot() => ?


In AS3, the reference to bar in the zot function would be bound to
this.bar so, even in the subclass, there is no ambiguity and both
cases would output 42. I assume that ES4 would follow this behaviour.

The fragility is more likely to be in the opposite situation, where a
method in a class intends to access a global variable, but the
superclass has declared it too.


Peter
_______________________________________________
Es4-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es4-discuss
Reply | Threaded
Open this post in threaded view
|

Re: How to escape implicit 'with (this)' of a method body

P T Withington
On 2008-07-31, at 12:34EDT, Peter Hall wrote:

>> Here's my take at an example of brittleness:
>>
>> var bar = 42;
>>
>> class foo {
>>  function zot () { return bar; }
>> }
>>
>> ...
>>
>> class subfoo extends foo {
>>  var bar = 'oops!';
>> }
>>
>> (new foo).zot() => 42
>> (new myfoo).zot() => ?
>
>
> In AS3, the reference to bar in the zot function would be bound to
> this.bar

I don't follow.  There is no `this.bar` in the class where zot is  
defined.

> so, even in the subclass, there is no ambiguity and both
> cases would output 42. I assume that ES4 would follow this behaviour.
>
> The fragility is more likely to be in the opposite situation, where a
> method in a class intends to access a global variable, but the
> superclass has declared it too.

That was my original example, which would also exhibit fragility if  
the superclass is developed/evolves independently.  In either case,  
the fragility stems from the implicit (unreformed) `with this` in  
method bodies.
_______________________________________________
Es4-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es4-discuss
Reply | Threaded
Open this post in threaded view
|

Re: How to escape implicit 'with (this)' of a method body

Peter Hall-4
>>
>> In AS3, the reference to bar in the zot function would be bound to
>> this.bar
>
> I don't follow.  There is no `this.bar` in the class where zot is defined.
>

Sorry, I said that backwards. When class foo is compiled, there is no
member called bar, so the reference is bound to the global variable.
Defining a member variable called bar in the subclass does not affect
that.

I don't know how convention will develop in other environments but, in
AS3, global variables are almost always declared in packages, and
strict mode is on by default. The result is that you would always get
a compiler error in these cases instead of an ambiguous reference.

Peter
_______________________________________________
Es4-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es4-discuss
Reply | Threaded
Open this post in threaded view
|

Re: How to escape implicit 'with (this)' of a method body

Maciej Stachowiak
In reply to this post by Dave Herman-2

On Jul 31, 2008, at 5:24 AM, Dave Herman wrote:

>> We should take this problem seriously. ...
>>
>> Dynamic scope is very bad.
>
> Specifically:
>
> - Classes are supposed to provide integrity, but dynamic scope makes  
> the
> internals of code brittle; any variable reference inside the
> implementation could be subverted by the seemingly innocuous insertion
> of a property.
>
> - Dynamic dispatch has a reasonably understandable cost model, but  
> only
> if it's confined to explicit property references. With dynamic scope,
> any variable reference could potentially be very expensive.
>
> - Generally, code within a `with' block is brittle and hard to
> understand, and as Tucker says, the implicit `this.' means that all  
> code
> inside class methods is within a `with' block... this means that all
> code inside class methods is brittle!
>
> - In the past, this has been enough for many programmers to deprecate
> all use of `with' -- we should certainly hope to avoid the same
> happening for classes.

I'm not sure of the benefits on the whole of implicit 'this' for class  
methods, but isn't it plausible to apply it only to static properties  
and not dynamically inserted ones, so all references continue to be  
bound at compile time and this sort of brittleness does not come up?

Regards,
Maciej

_______________________________________________
Es4-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es4-discuss
Reply | Threaded
Open this post in threaded view
|

Re: How to escape implicit 'with (this)' of a method body

Garrett Smith
On Fri, Aug 1, 2008 at 1:03 PM, Maciej Stachowiak <[hidden email]> wrote:

>
> On Jul 31, 2008, at 5:24 AM, Dave Herman wrote:
>
>>> We should take this problem seriously. ...
>>>
>>> Dynamic scope is very bad.
>>
>> Specifically:
>>
>> - Classes are supposed to provide integrity, but dynamic scope makes
>> the
>> internals of code brittle; any variable reference inside the
>> implementation could be subverted by the seemingly innocuous insertion
>> of a property.
>>
>> - Dynamic dispatch has a reasonably understandable cost model, but
>> only
>> if it's confined to explicit property references. With dynamic scope,
>> any variable reference could potentially be very expensive.
>>
>> - Generally, code within a `with' block is brittle and hard to
>> understand, and as Tucker says, the implicit `this.' means that all
>> code
>> inside class methods is within a `with' block... this means that all
>> code inside class methods is brittle!
>>
>> - In the past, this has been enough for many programmers to deprecate
>> all use of `with' -- we should certainly hope to avoid the same
>> happening for classes.
>
> I'm not sure of the benefits on the whole of implicit 'this' for class
> methods, but isn't it plausible to apply it only to static properties
> and not dynamically inserted ones,

What is dynamically inserted? I guess would mean properties added to
an instance of a non-sealed class.

> so all references continue to be
> bound at compile time and this sort of brittleness does not come up?
>

I think I remember discussion that 'this' in a static context was not valid.

If 'this' in a static context points to the class itself, it allows
for the possibility of the class having a static method, with a
private constructor and a public getInstance method with code
something like:

>> class E { static function f(){ return new this; } }
>> E.f()
[object E]

Works in the RI.

But I there was apparently a reason that that was not good, so that is a bug.

http://bugs.ecmascript.org/ticket/74

Garrett

> Regards,
> Maciej
_______________________________________________
Es4-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es4-discuss
Reply | Threaded
Open this post in threaded view
|

Re: How to escape implicit 'with (this)' of a method body

Brendan Eich-2
On Aug 1, 2008, at 2:43 PM, Garrett Smith wrote:

> What is dynamically inserted? I guess would mean properties added to
> an instance of a non-sealed class.

Right. Those should not be addressable by unqualified names in method  
scope -- you have to use "this".

>> so all references continue to be
>> bound at compile time and this sort of brittleness does not come up?
>
> I think I remember discussion that 'this' in a static context was  
> not valid.

Maciej meant static in the compile-time or lexical sense, not static  
in the class singleton object property sense.

/be
_______________________________________________
Es4-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es4-discuss
Reply | Threaded
Open this post in threaded view
|

Re: How to escape implicit 'with (this)' of a method body

P T Withington
In reply to this post by Peter Hall-4
On 2008-08-01, at 05:13EDT, Peter Hall wrote:

>>>
>>> In AS3, the reference to bar in the zot function would be bound to
>>> this.bar
>>
>> I don't follow.  There is no `this.bar` in the class where zot is  
>> defined.
>>
>
> Sorry, I said that backwards. When class foo is compiled, there is no
> member called bar, so the reference is bound to the global variable.
> Defining a member variable called bar in the subclass does not affect
> that.

I think what everyone is saying is that my model of how references in  
methods are resolved is wrong.  There is no implicit `with (this)` in  
method bodies, the references are resolved lexically, not dynamically.

In either case, though, it seems there is no in-language way to refer  
to a global that is shadowed by an instance variable.  The offered  
solutions assume that the implementation creates a global object that  
can be used to refer to globals.

> I don't know how convention will develop in other environments but, in
> AS3, global variables are almost always declared in packages, and
> strict mode is on by default. The result is that you would always get
> a compiler error in these cases instead of an ambiguous reference.


What is the error?  I don't get an error with this code:

     var free = 'outer';

     class Top {
       function test () { return free; }
     }

     class Sub extends Top {
       var free = 'inner';

       override function test () { return free; }
     }

Perhaps this is just poor practice, but it is confusing that the two  
uses of `free` result in two different bindings.
_______________________________________________
Es4-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es4-discuss