getter & setter for private objects
On Nov 2, 2009, at 2:34 AM, memolus at googlemail.com wrote:
I like to use getter and setter on private objects (e.g. "var test").
That is very unclear; I'm guessing you mean getters and setters
instead of plain variables in closures used to store private data.
I didn't found any way to do this. I don't need sth. like Object.definePrivateProperty, because I only want to set getter and setter when I define the private object.
Example proposal: var test; get test = function() { [..] }; set test = function(newval) { [..] };
I'll be pleased to hear your feedback.
Defining accessors on an activation object is nasty, it makes
analyzing for effects hard (consider the arguments object, which is an
indirect accessor -- both get and set -- of formal parameter values).
I doubt we'll ever standardize any such thing; Mozilla would not
implement it even experimentally.
If you want private getters and setters, you can put them in an object
denoted by a private var:
function make() { var obj = { get test() /* cheap fetch of x here /, set test(x) / cheap update from x here / }; function validate(x) { / expensive check of x here */ } return { get test() { return obj.test; }, set test(x) { validate(x); obj.test = x; } // etc. }; }
What do getters and setters do around with?
var flipFlop; with ({ get test: function () { return (flipFlop = !flipFlop) ? 'flip' : 'flop'; } }) { for (var i = 0; i < 10; ++i) { alert(test); } }
The with block invokes NewObjectEnvironment with O being the binding object. But I'm unclear on whether line 4 in GetBindingValue below would invoke a getter.
=== start quote === 10.2.2.3 NewObjectEnvironment (O, E) When the abstract operation NewObjectEnvironmentis called with an Object O and a Lexical Environment E (or null) as arguments, the following steps are performed:
- Let env be a new Lexical Environment.
- Let envRec be a new object environment record containing O as the binding object.
- Set env’s environment record to be envRec.
- Set the outer lexical environment reference of env to E.
- Return env.
10.2.1.1.4 GetBindingValue(N,S) The concrete Environment Record method GetBindingValue for declarative environment records simply returns the value of its bound identifier whose name is the value of the argument N. The binding must already exist. If S is true and the binding is an uninitialized immutable binding throw a ReferenceError exception.
- Let envRec be the declarative environment record for which the method was invoked.
- Assert: envRec has a binding for N.
- If the binding for N in envRec is an uninitialized immutable binding, then a. If S is false, return the value undefined, otherwise throw a ReferenceError exception.
- Else, return the value currently bound to N in envRec. === end quote ===
Does 4
2009/11/2 Brendan Eich <brendan at mozilla.com>:
On Nov 2, 2009, at 10:47 AM, Mike Samuel wrote:
What do getters and setters do around with?
var flipFlop; with ({ get test: function () { return (flipFlop = !flipFlop) ? 'flip' : 'flop'; } }) { for (var i = 0; i < 10; ++i) { alert(test); } }
The with block invokes NewObjectEnvironment with O being the binding
object. But I'm unclear on whether line 4 in GetBindingValue below would invoke a getter.
It ought to, because ES3 with anything like getters, including a
native or host object cooperating [[HasProperty]] and [[Get]]
implementations -- but also Mozilla's getter and setter implementation
of ten years' standing, would invoke the getter.
ES3 spec sections are 12.10, 10.1.4, and 11.1.2 which feeds into
GetValue when the Identifier is used as a rvalue; GetValue does call
[[Get]].
Indeed ES5 is correctly compatible with ES3 + getters or internal
[[HasProperty]]/[[Get]] implementations.
10.2.1.1.4 GetBindingValue(N,S) The concrete Environment Record method GetBindingValue for declarative environment records simply returns the value of its bound identifier whose name is the value of the argument N. The binding must already exist. If S is true and the binding is an uninitialized immutable binding throw a ReferenceError exception.
- Let envRec be the declarative environment record for which the method was invoked.
- Assert: envRec has a binding for N.
- If the binding for N in envRec is an uninitialized immutable
binding, then a. If S is false, return the value undefined, otherwise throw a ReferenceError exception.- Else, return the value currently bound to N in envRec. === end quote ===
Wrong section. The concrete type of envRec for a 'with' statement is
an object environment record, so you want:
10.2.1.2.4 GetBindingValue(N,S)
The concrete Environment Record method GetBindingValue for object
environment records returns the value of its associated binding
object‘s property whose name is the String value of the argument
identifier N. The property should already exist but if it does not the
result depends upon the value of the S argument:
- Let envRec be the object environment record for which the method
was invoked. - Let bindings be the binding object for envRec.
- Let value be the result of calling the [[HasProperty]] internal
method of bindings, passing N as the property name. - If value is false, then
a. If S is false, return the value undefined, otherwise throw a
ReferenceError exception. - Return the result of calling the [[Get]] internal method of
bindings, passing N for the argument.
2009/11/2 Brendan Eich <brendan at mozilla.com>:
On Nov 2, 2009, at 10:47 AM, Mike Samuel wrote:
What do getters and setters do around with?
var flipFlop; with ({ get test: function () { return (flipFlop = !flipFlop) ? 'flip' : 'flop'; } }) { for (var i = 0; i < 10; ++i) { alert(test); } }
The with block invokes NewObjectEnvironment with O being the binding object. But I'm unclear on whether line 4 in GetBindingValue below would invoke a getter.
It ought to, because ES3 with anything like getters, including a native or host object cooperating [[HasProperty]] and [[Get]] implementations -- but also Mozilla's getter and setter implementation of ten years' standing, would invoke the getter.
ES3 spec sections are 12.10, 10.1.4, and 11.1.2 which feeds into GetValue when the Identifier is used as a rvalue; GetValue does call [[Get]].
Indeed ES5 is correctly compatible with ES3 + getters or internal [[HasProperty]]/[[Get]] implementations.
10.2.1.1.4 GetBindingValue(N,S) The concrete Environment Record method GetBindingValue for declarative environment records simply returns the value of its bound identifier whose name is the value of the argument N. The binding must already exist. If S is true and the binding is an uninitialized immutable binding throw a ReferenceError exception.
- Let envRec be the declarative environment record for which the method was invoked.
- Assert: envRec has a binding for N.
- If the binding for N in envRec is an uninitialized immutable binding, then a. If S is false, return the value undefined, otherwise throw a ReferenceError exception.
- Else, return the value currently bound to N in envRec. === end quote ===
Wrong section. The concrete type of envRec for a 'with' statement is an object environment record, so you want:
10.2.1.2.4 GetBindingValue(N,S)
Ah thanks.
The upshot for memolus is that with is already a deoptimizer that
introduces non-lexical names onto the scope chain. These can be
gettters and setters and have arbitrary effects. My point remains that
adding getters and setters to activations, which are modeled lexically
in the absence of eval, in strict mode in ES5, and under other such
conditions, is a non-starter.
2009/11/2 Brendan Eich <brendan at mozilla.com>:
Defining accessors on an activation object is nasty, If you want private getters and setters, you can put them in an object denoted by a private var:
So you prefer ugly solutions, because the others are nasty?
The upshot for memolus is that with is already a deoptimizer that introduces non-lexical names onto the scope chain. These can be gettters and setters and have arbitrary effects. My point remains that adding getters and setters to activations, which are modeled lexically in the absence of eval, in strict mode in ES5, and under other such conditions, is a non-starter.
I didn't get how to use "with" in order to use private objects (non-lexical names onto the scope chain). Just ignore my example if it tries to add getter and setter to already activated objects. You don't have to implement it this way.
On Nov 2, 2009, at 3:05 PM, memolus at googlemail.com wrote:
2009/11/2 Brendan Eich <brendan at mozilla.com>:
Defining accessors on an activation object is nasty, If you want private getters and setters, you can put them in an
object denoted by a private var: So you prefer ugly solutions, because the others are nasty?
I don't prefer any of this! You do, but I still am not sure why.
Private variables I understand, and those are doable using closures
(possibly other ways in Harmony).
But private variables defined by var (or let) are not private getters
and setters -- why do you need the latter?
The upshot for memolus is that with is already a deoptimizer that
introduces non-lexical names onto the scope chain. These can be gettters and
setters and have arbitrary effects. My point remains that adding getters
and setters to activations, which are modeled lexically in the absence of eval,
in strict mode in ES5, and under other such conditions, is a non- starter.I didn't get how to use "with" in order to use private objects (non-lexical names onto the scope chain). Just ignore my example if it tries to add getter and setter to already activated objects. You don't have to implement it this way.
How then can they be implemented? Not by interposing a with object,
since that changes |this| binding....
I suggest you try to state concrete use-case examples first, in order
to write down requirements.
2009/11/2 memolus at googlemail.com <memolus at googlemail.com>:
2009/11/2 Brendan Eich <brendan at mozilla.com>:
Defining accessors on an activation object is nasty, If you want private getters and setters, you can put them in an object denoted by a private var: So you prefer ugly solutions, because the others are nasty?
The upshot for memolus is that with is already a deoptimizer that introduces non-lexical names onto the scope chain. These can be gettters and setters and have arbitrary effects. My point remains that adding getters and setters to activations, which are modeled lexically in the absence of eval, in strict mode in ES5, and under other such conditions, is a non-starter.
I didn't get how to use "with" in order to use private objects (non-lexical names onto the scope chain). Just ignore my example if it tries to add getter and setter to already activated objects. You don't have to implement it this way.
What is it that you want? Some use cases would help focus the discussion.
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256
memolus at googlemail.com wrote:
2009/11/2 Brendan Eich <brendan at mozilla.com>:
Defining accessors on an activation object is nasty, If you want private getters and setters, you can put them in an object denoted by a private var:
So you prefer ugly solutions, because the others are nasty?
Yes. Here "ugly" just means "verbose and inelegant", whereas "nasty" means "having poorly understood and subtly error-prone consequences". So ugly beats nasty every time :-)
David-Sarah Hopwood ⚥ davidsarah.livejournal.com -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.12 (MingW32) Comment: Using GnuPG with Mozilla - enigmail.mozdev.org
iF4EAREIAAYFAkrv2VwACgkQWUc8YzyzqAe32wEAhpO3jMN9ocd1byz6tdPEBBCH U9y2ehpsThazZPN+aA4A/2MKGgL1ESuwU7PeOq4HY2jxh18M0GzjWPhWFQA8Tm4/ =wSUQ -----END PGP SIGNATURE-----
So if you agree with me upon the ugliness, you'll also agree with me that it would be better to find a sweeter way.
Use-cases, please -- aesthetics come after functionality and only if
the functionality is there.
You haven't demonstrated why you want accessors on the lexical (i.e.,
private part of the) scope chain.
manager = function(object) { this.init.apply(this, arguments); } manager.prototype = new function() { /* Private Properties */ var gui; var obj;
/* Constructor */
this.init = function(object) {
gui = new Gui();
obj = object;
}
/* Property with both accessor and mutator */
this.__defineGetter__("modus", function() {
[..]
});
this.__defineSetter__("modus", function(modus) {
[..]
});
/* Privileged public method which affords access to private properties */
this.getGui = function() {
return gui;
}
}
Currently I'm able to set accessor and mutator for properties of "this", but not on the lexical scope chain. I want e.g. "modus" to be private.
Anyway I hope you get what I mean. It's an evolutionary step to class support. Other programming languages support
private int foo {
get { [..] }
set { [..] }
}
I like to use getter and setter on private objects (e.g. "var test"). I didn't found any way to do this. I don't need sth. like Object.definePrivateProperty, because I only want to set getter and setter when I define the private object.
Example proposal: var test; get test = function() { [..] }; set test = function(newval) { [..] };
I'll be pleased to hear your feedback.