[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.javascript

not "autovivification", but ...?

ram

5/31/2016 11:22:00 AM

If Perl's autovivification would exist in JavaScript, this
would mean that in a new interpreter instance, the evaluation
of the expression

a.b.c = 1;

would implicitly create the object »a« and »a.b«
and then assign »1« to the property »c« of »a.b«.

We do not have this in JavaScript, but we do have

"use strict"; this.b = 1;

. That is, when »this.b« is a assigned to - even in strict mode -
a new property »b« is implicitly created. No declaration (with
»var«, »let«, or »const«) is required.

Is there a name for this »feature« of JavaScript?
Maybe »semivivification«, because it's like
autovivification, but not so strong?

13 Answers

ram

5/31/2016 11:52:00 AM

0

ram@zedat.fu-berlin.de (Stefan Ram) writes:
>"use strict"; this.b = 1;

And I wonder, why in strict mode in the outmost scope, when

b = 1

is forbidden (given that »this.b« does not exist)

this.b = 1

is allowed. What is the rationale for allowing it with »this.«?

Christoph M. Becker

5/31/2016 12:12:00 PM

0

On 31.05.2016 at 13:51, Stefan Ram wrote:

> ram@zedat.fu-berlin.de (Stefan Ram) writes:
>> "use strict"; this.b = 1;
>
> And I wonder, why in strict mode in the outmost scope, when
>
> b = 1
>
> is forbidden (given that »this.b« does not exist)
>
> this.b = 1
>
> is allowed. What is the rationale for allowing it with »this.«?

`this` is not special in this regard; you can assign to undefined
properties of *any* object.

Also consider that accessing undefined properties of an object yield
`undefined` (but not an error), so it appears to be logical to allow
assigning another value to such undefined properties.

--
Christoph M. Becker

Stefan Weiss

5/31/2016 12:38:00 PM

0

Stefan Ram wrote:
> If Perl's autovivification would exist in JavaScript, this
> would mean that in a new interpreter instance, the evaluation
> of the expression
>
> a.b.c = 1;
>
> would implicitly create the object »a« and »a.b«
> and then assign »1« to the property »c« of »a.b«.

Perl's autovivification is a special case. It looks very user-friendly at
first glance, because it can automatically create intermediate structures
when they're needed - but it also does that on access, not just on
assignment. Examining a value can modify it, which is a common source of bugs:

my %hash;
if (exists $hash{foo}{bar}{baz}) {
say "this statement never executes";
}

Looks innocent enough, but %hash has just been changed from `undef` to

( foo => { bar => {} } )

> We do not have this in JavaScript, but we do have
>
> "use strict"; this.b = 1;
>
> . That is, when »this.b« is a assigned to - even in strict mode -
> a new property »b« is implicitly created. No declaration (with
> »var«, »let«, or »const«) is required.
>
> Is there a name for this »feature« of JavaScript?
> Maybe »semivivification«, because it's like
> autovivification, but not so strong?

I would advise against using the name (auto/semi)vivification, if only to
avoid the negative connotations this feature has in Perl (at least for
experienced programmers).

There is a perfectly good description for this behavior in JavaScript, and
you even used it yourself: implicit property creation.

In both languages, there are ways to prevent this implicit creation: the "no
autovivification" pragma in Perl; strict mode and object sealing or freezing
in JS.


- stefan

Thomas 'PointedEars' Lahn

5/31/2016 3:32:00 PM

0

Stefan Ram wrote:

> [â?¦] we do have
>
> "use strict"; this.b = 1;
>
> . That is, when »this.b« is a assigned to - even in strict mode -
> a new property »b« is implicitly created. No declaration (with
> »var«, »let«, or »const«) is required.
>
> Is there a name for this »feature« of JavaScript?

Property write access. It does not only work with the object referred to by
â??thisâ? â?? which, you should keep in mind, does not have to be so particularly
in strict mode â?? but with all objects that have the [[Extensible]] flag set.

Also, you want to be careful here: assigning to a property of â??thisâ? can
result in the creation of the equivalent of a global variable when a
function in which it is used is not called as a constructor, and it results
in a ReferenceError exception thrown in function context in strict mode if
the function is neither called as the method of an object nor as a
constructor.

â??Autovivificationâ? (in C#: null propagation) would certainly be useful at
times (very often you just want to get â??undefinedâ? from x.y.z when x.y
yields â??undefinedâ? instead of typeof-testing the whole shebang, and
x.y.z = 1 when x.y is â??undefinedâ?; consider arrays of objects), and is
available in CoffeeScript as the â??accessor variant of the existential
operatorâ??:

x?.y.z

<http://stackoverflow.com/questions/15260732/does-typescript-support-the-operator-and-whats-it-...

--
PointedEars
FAQ: <http://PointedEars.... | SVN: <http://PointedEars.de...
Twitter: @PointedEars2 | ES Matrix: <http://PointedEars.de/es-...
Please do not cc me. / Bitte keine Kopien per E-Mail.

Michael Haufe (\"TNO\")

6/1/2016 2:51:00 PM

0

On Tuesday, May 31, 2016 at 7:11:39 AM UTC-5, Christoph M. Becker wrote:
> On 31.05.2016 at 13:51, Stefan Ram wrote:
>
> > (Stefan Ram) writes:
> >> "use strict"; this.b = 1;
> >
> > And I wonder, why in strict mode in the outmost scope, when
> >
> > b = 1
> >
> > is forbidden (given that »this.b« does not exist)
> >
> > this.b = 1
> >
> > is allowed. What is the rationale for allowing it with »this.«?
>
> `this` is not special in this regard; you can assign to undefined
> properties of *any* object.

Most, not any. For example: [1]

> Also consider that accessing undefined properties of an object yield
> `undefined` (but not an error), so it appears to be logical to allow
> assigning another value to such undefined properties.

That does not follow. Ex:

//assume this function is defined in a 3rd party library
function getSomeObject(){
return Object.seal({
hello: "world"
})
}

//in your code somewhere:
var someObject = getSomeObject()

typeof someObject.hello // string

typeof someObject.hola // undefined

someObject.hola = "mundo"

typeof someObject.hola // undefined


[1] <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Objec...

Michael Haufe (\"TNO\")

6/1/2016 3:04:00 PM

0

On Tuesday, May 31, 2016 at 7:38:35 AM UTC-5, Stefan Weiss wrote:
> Stefan Ram wrote:
> > If Perl's autovivification would exist in JavaScript, this
> > would mean that in a new interpreter instance, the evaluation
> > of the expression
> >
> > a.b.c = 1;
> >
> > would implicitly create the object »a« and »a.b«
> > and then assign »1« to the property »c« of »a.b«.
>
> Perl's autovivification is a special case. It looks very user-friendly at
> first glance, because it can automatically create intermediate structures
> when they're needed - but it also does that on access, not just on
> assignment. Examining a value can modify it, which is a common source of bugs:
>
> my %hash;
> if (exists $hash{foo}{bar}{baz}) {
> say "this statement never executes";
> }
>
> Looks innocent enough, but %hash has just been changed from `undef` to
>
> ( foo => { bar => {} } )
>
> > We do not have this in JavaScript, but we do have
> >
> > "use strict"; this.b = 1;
> >
> > . That is, when »this.b« is a assigned to - even in strict mode -
> > a new property »b« is implicitly created. No declaration (with
> > »var«, »let«, or »const«) is required.
> >
> > Is there a name for this »feature« of JavaScript?
> > Maybe »semivivification«, because it's like
> > autovivification, but not so strong?
>
> I would advise against using the name (auto/semi)vivification, if only to
> avoid the negative connotations this feature has in Perl (at least for
> experienced programmers).
>
> There is a perfectly good description for this behavior in JavaScript, and
> you even used it yourself: implicit property creation.
>
> In both languages, there are ways to prevent this implicit creation: the "no
> autovivification" pragma in Perl; strict mode and object sealing or freezing
> in JS.

IME, multi-level implicit creation is a sign that something is wrong with your architecture. It makes me ask: "Why were these undefined in the first place?"

The dual issue for implicit creation is accessing a nested structure where one or more of the intermediate members may not exist. My same question above applies there as well: Why don't these already exist?

I think the lack of desire to revisit the architecture of the application leads to some interesting choices in how people code:

var foo = (((a || {}).b || {}).c || {}).d

and then helper functions to make that less awkward and more general:

Object.walk = (o, path)=>path.split('.').reduce((o,k)=>o && o[k], o);

var foo = Object.walk(a,"a.b.c.d")

and then language feature attempts to make it standard:

<https://esdiscuss.org/topic/the-existential-op...

....

Where fundamentally people should take a step back and take a moment to think at a higher level about what they are trying to accomplish.

</end-pseudo-rant>

Christoph M. Becker

6/1/2016 4:47:00 PM

0

On 01.06.2016 at 16:51, Michael Haufe (TNO) wrote:

> On Tuesday, May 31, 2016 at 7:11:39 AM UTC-5, Christoph M. Becker wrote:
>
>> `this` is not special in this regard; you can assign to undefined
>> properties of *any* object.
>
> Most, not any. For example: [1]
>
>> Also consider that accessing undefined properties of an object yield
>> `undefined` (but not an error), so it appears to be logical to allow
>> assigning another value to such undefined properties.
>
> That does not follow. Ex:
>
> //assume this function is defined in a 3rd party library
> function getSomeObject(){
> return Object.seal({
> hello: "world"
> })
> }
>
> [1] <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Objec...

Thanks for pointing that out. I most certainly should catch up with ES
5.1 ASAP. :)

--
Christoph M. Becker

Stefan Weiss

6/1/2016 5:50:00 PM

0

Michael Haufe (TNO) wrote:
> IME, multi-level implicit creation is a sign that something is wrong
> with your architecture. It makes me ask: "Why were these undefined in the first
> place?"
>
> The dual issue for implicit creation is accessing a nested structure
> where one or more of the intermediate members may not exist. My same
> question above applies there as well: Why don't these already exist?
>
> [snip examples of workarounds]
>
> Where fundamentally people should take a step back and take a moment to
> think at a higher level about what they are trying to accomplish.

I sort of agree with this, to a point, but only if I created the data
structure myself (or my application did). In many situations we simply don't
have that level of control over data. Examples for this would be external
APIs, JSON config files, or any other external tree-like structure mapped to
nested objects.

Are you saying that all data exchange formats with optional components are
badly designed, or that at least all known container nodes should be
present? I don't think that's a realistic requirement.


- stefan

Michael Haufe (\"TNO\")

6/1/2016 9:29:00 PM

0

On Wednesday, June 1, 2016 at 12:50:01 PM UTC-5, Stefan Weiss wrote:

> I sort of agree with this, to a point, but only if I created the data
> structure myself (or my application did). In many situations we simply don't
> have that level of control over data. Examples for this would be external
> APIs, JSON config files, or any other external tree-like structure mapped to
> nested objects.

> Are you saying that all data exchange formats with optional components are
> badly designed,

No. Nothing like that at all.

> or that at least all known container nodes should be
> present? I don't think that's a realistic requirement.

Nor this either.

Let me try to approach this another way to try and clarify my meaning:

<script>
var someObject = JSON.parse(foo);
</script>

If I could rely on the structure of someObject, I could use a definite access pattern:

<script>
var target = someObject.left.right.right.left.value
</script>

We know that's unrealistic in reality and we'd want to do some checking.
We could apply one of the patterns in my last message:

<script>
target = Object.walk(someObject,"someObject.left.right.right.left.value")
</script>

or let's assume the elvis operator was available in the language:

<script>
target = someObject?.left?.right?.right?.left?.value
</script>

Another example with the DOM:

<script>
var target2 = document.body.firstChild.nextSibling.lastChild
</script>

and again with the suggested operator as a more robust alternative:

<script>
target2 = document?.body?.firstChild?.nextSibling?.lastChild
</script>

I assume these two examples strike you as ridiculous, or at least suspect in what it is doing In your own applications, and many you've no doubt run across, you see such a thing not all on one line, but instead spread across methods and function calls as a parameter:

<script>
foo(someObject)

function foo(obj) {
if(obj && obj.left) {
// ...
bar(obj.left)
}
}

function bar(obj) {
if(obj && obj.right) {
//...
baz(obj.right)
}
}

function baz(obj) {
if(el && obj.right) {
//etc...
}
}
</script>

It's the same issue, but less obvious as it's spread across the program.

Now let's backup and look at the DOM example.

Instead of the above, you'd no doubt avoid such probing to find the element you want and would instead use a search of the data structure:

<script>
target2 = document.getElementById("targetNode")
</script>

But you generally don't see this being exercised against arbitary objects (with the exception of JSONPath users and such)

Partly this is due to the lack of such a general facility in JS, but also due to a different mindset when it comes to the DOM vs. JS objects.

If you are able to recognize the objects you deal with as being an instance of one of the well known data structures you can leverage such functionality as searching.

Even if you aren't provided such a structure you could use the Decorator Pattern to wrap that 3rd party structure and provide something more useful for your own portion of the application:

<script>
var data = new MyTreeConstructor(
someThirdPartyObject
);

var results = data.find("something")
result.forEach(...)

</script>

For simpler objects you can use the Decorator Pattern to provide sensible defaults just once.

Stefan Weiss

6/1/2016 11:30:00 PM

0

Michael Haufe (TNO) wrote:
> On Wednesday, June 1, 2016 at 12:50:01 PM UTC-5, Stefan Weiss wrote:
>
>> I sort of agree with this, to a point, but only if I created the data
>> structure myself (or my application did). In many situations we simply don't
>> have that level of control over data. Examples for this would be external
>> APIs, JSON config files, or any other external tree-like structure mapped to
>> nested objects.
>
>> Are you saying that all data exchange formats with optional components are
>> badly designed,
>
> No. Nothing like that at all.
>
>> or that at least all known container nodes should be
>> present? I don't think that's a realistic requirement.
>
> Nor this either.
>
> Let me try to approach this another way to try and clarify my meaning:

[summarized ways to access nested properties, if I understood correctly:]

a) rely on the structure: someObject.left.right.right.left.value
b) use a custom walk() method (or similar)
c) use a specialized operator (like `?.`)
d) spread across multiple functions
e) use an alternate identifier (id attributes in the DOM)
f) use something like JSONPath
g) use a decorator to provide the search/path feature

While this is a very useful list of techniques, I'm even more confused
now... These are all used when we don't know if a certain branch (or path
component) exists in a nested object. I thought your earlier point was that
this situation shouldn't be allowed to occur in a well-designed application,
but I'm probably misunderstanding something here:

Michael Haufe (TNO) wrote:
>>> The dual issue for implicit creation is accessing a nested structure
>>> where one or more of the intermediate members may not exist. My same
>>> question above applies there as well: Why don't these already exist?
>>>
>>> I think the lack of desire to revisit the architecture of the
>>> application leads to some interesting choices in how people code [...]


I'm not trying to make a case for implicitly *creating* multiple levels in a
nested structure - even where that is supported, I usually go out of my way
to avoid it. See the Perl example in my first reply. But accessing such a
structure is very common and often cannot be avoided. Which of the mentioned
techniques is used to solve this is a matter of preference, IMO.


- stefan


PS, a little off-topic: PHP is probably the worst language to work with in
this regard. It will happily allow implicit multi-level creation in arrays -

// ($foo is unused up to this point)
$foo["bar"][13]["baz"] = "qux";

- but will emit E_NOTICE (a type of error) if we try to read a nonexistent
index ($foo["x"]). Only with the relatively recent release of PHP7 did it
get a null-coalescing operator:

$x = $foo["baz"][14]["bar"] ?? "qux";

And when objects are involved... best not to think about it.