Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Error-free deep property access?

260 views
Skip to first unread message

Matt Kruse

unread,
May 11, 2010, 9:44:35 AM5/11/10
to
Does anyone here use a general convenience method for deep property
access that will not throw an error if any property along the chain is
undefined?

For example:

deep(document, "body.firstChild.style.backgroundColor");
or
deep("myElementId.childNodes[3].id");
or
deep( myJsonObject,
"locations.ca.sandiego.directory.people.smith.john.phone");

This would return undefined if any element along the chain is not
there, or index is out of bounds, etc. If the chain gets to the end,
it would return the last-evaluated value. This would be convenient for
accessing deep properties of objects that may or may not exist, and
not having to manually check the chain in your code.

I'm curious to know if anyone uses such an approach, or the cons of
doing so.

Matt Kruse

Scott Sauyet

unread,
May 11, 2010, 10:12:59 AM5/11/10
to
On May 11, 9:44 am, Matt Kruse <m...@thekrusefamily.com> wrote:
> Does anyone here use a general convenience method for deep property
> access that will not throw an error if any property along the chain is
> undefined? [ ... ]

>
> I'm curious to know if anyone uses such an approach, or the cons of
> doing so.

I used such a technique only once. It was easy enough to write,
performed well enough for my uses, and did simplify some code. But as
new developers came aboard the project, it was one more thing that
they hadn't seen before, and it rarely turned out to be useful enough
to justify even the short learning curve.

But then again I don't think I've ever written something as deep as
your third example.

-- Scott

Thomas 'PointedEars' Lahn

unread,
May 11, 2010, 11:29:33 AM5/11/10
to
Matt Kruse wrote:

> Does anyone here use a general convenience method for deep property
> access that will not throw an error if any property along the chain is
> undefined?
>
> For example:
>
> deep(document, "body.firstChild.style.backgroundColor");
> or
> deep("myElementId.childNodes[3].id");
> or
> deep( myJsonObject,
> "locations.ca.sandiego.directory.people.smith.john.phone");

getFeature() and isMethod() in JSX:object.js do a similar thing. They could
be rewritten to support your requirements using dotsToBrackets() in
JSX:types.js. Note that I had opted for several arguments instead because
property names may contain `.', `[', or `]'.

PointedEars
--
Danny Goodman's books are out of date and teach practices that are
positively harmful for cross-browser scripting.
-- Richard Cornford, cljs, <cife6q$253$1$8300...@news.demon.co.uk> (2004)

Matt Kruse

unread,
May 11, 2010, 11:52:49 AM5/11/10
to
On May 11, 8:44 am, Matt Kruse <m...@thekrusefamily.com> wrote:
> Does anyone here use a general convenience method for deep property
> access that will not throw an error if any property along the chain is
> undefined?

Well, here's my stab at it:

/*
Error-Free Deep Property Access!

Returns: Property value, or undefined if any part of the property
chain is undefined

Usage:
$prop( object, 'property_name' )
$prop( 'element_id.property_name' )
$prop( 'element_id.prop1.prop2.prop3' )
$prop( object, 'array_property[0]' )
$prop( object, 'method(arg).property_name.array_property[0]
[1].prop' )
$prop( window, 'document.getElementsByTagName(div)
[0].childNodes[1].style.color' )

Special Usage:
$prop() returns the object last evaluated!
if ($prop("id.style.color")) {
alert( $prop() );
}

JSON Example:

var json = {
'a':'1'
,'b': ['x','y','z']
,'c': {
'array':['1','2','3']
,'property':'prop!'
}
}
$prop(json,'a') ==> 1
$prop(json,'b[1]') ==> y
$prop(json,'c.array[2]') ==> 3
$prop(json,'d.e.f.g') ==> undefined

*/
var $prop = (function() {
var last_match;
return function(a,b) {
// Calls to $property() return the last match
if (typeof a=="undefined") { return last_match; }

var context, props = null, p;
// If first arg is not a string, assume it's an object to
// start from
if (typeof a!="string") {
context = a;
props = b.split(".");
}
// Otherwise it's just a string where the first part is an
// element ID
else {
props = a.split(".");
context = document.getElementById(props.shift());
if (!context) { return; }
}
while (context && props.length>0) {
if (context==null) { return; }
p = props.shift();
// If there is an array index [i] at the end, only
// process the first part and stick the second part
// back on the beginning
if ( p.match(/(.+?)(\[\d+\].*)/) ) {
p = RegExp.$1;
props.unshift(RegExp.$2);
}
// if the first part itself is an array index [i]
// then process it
if ( p.match(/^\[(\d+)\]$/) ) {
if (!context || !context.length) { return; }
context = context[RegExp.$1];
}
// If it's a function(arg) call
else if ( p.match(/(.*)\((.*?)\)/) ) {
context = context[RegExp.$1](RegExp.$2);
}
// Else it's a regular property
else {
context = context[p];
}
if (typeof context=="undefined") { return; }
}
last_match = context;
return context;
}
})();

Matt Kruse

Scott Sauyet

unread,
May 11, 2010, 1:19:12 PM5/11/10
to
Matt Kruse wrote:
> On May 11, 8:44 am, Matt Kruse <m...@thekrusefamily.com> wrote:
>
>> Does anyone here use a general convenience method for deep property
>> access that will not throw an error if any property along the chain is
>> undefined?
>
> Well, here's my stab at it: [ ... ]

So this won't allow, for instance,

$props("myObj.prop1.prop2[current.value]")

Is that right? It needs to have only a single root at the first
token. That will cover a lot of possibilities, but the more general
case is interesting too.

--
Scott

Matt Kruse

unread,
May 11, 2010, 1:31:26 PM5/11/10
to
On May 11, 12:19 pm, Scott Sauyet <scott.sau...@gmail.com> wrote:
> So this won't allow, for instance,
>     $props("myObj.prop1.prop2[current.value]")
> Is that right?  It needs to have only a single root at the first
> token.  That will cover a lot of possibilities, but the more general
> case is interesting too.

True. But since you're passing in a string, couldn't you just do:

$prop("myObj.prop1.prop2."+current.value)
?

Matt

Thomas 'PointedEars' Lahn

unread,
May 11, 2010, 2:03:39 PM5/11/10
to
Matt Kruse wrote:

Generally, no. Think about it. See also the caveats that I have mentioned.


PointedEars
--
Anyone who slaps a 'this page is best viewed with Browser X' label on
a Web page appears to be yearning for the bad old days, before the Web,
when you had very little chance of reading a document written on another
computer, another word processor, or another network. -- Tim Berners-Lee

Scott Sauyet

unread,
May 11, 2010, 2:06:31 PM5/11/10
to

Sure, unless current is undefined, which I think is the original
problem we're trying to solve. :-)

And of course we could want

$props("myObj.prop1.prop2[current.deeply.nested.value]")

as well.

--
Scott

Thomas 'PointedEars' Lahn

unread,
May 11, 2010, 2:39:53 PM5/11/10
to
Scott Sauyet wrote:

> Matt Kruse wrote:
>> On May 11, 12:19 pm, Scott Sauyet <scott.sau...@gmail.com> wrote:
>>> So this won't allow, for instance,
>>> $props("myObj.prop1.prop2[current.value]")
>>> Is that right? It needs to have only a single root at the first
>>> token. That will cover a lot of possibilities, but the more general
>>> case is interesting too.
>>
>> True. But since you're passing in a string, couldn't you just do:
>>
>> $prop("myObj.prop1.prop2."+current.value)
>> ?
>

> Sure, unless current is undefined, [...]

Wrong. Think about what would happen with

current.value = 42;

or

current.value = "foo.bar";

or

current.value = "foo['bar']";

Thomas 'PointedEars' Lahn

unread,
May 11, 2010, 2:45:43 PM5/11/10
to
Matt Kruse wrote:

> if ( p.match(/(.+?)(\[\d+\].*)/) ) {
> p = RegExp.$1;
> props.unshift(RegExp.$2);

Other flaws of this approach that I have already mentioned aside, the `$n'
properties of `RegExp' are deprecated as of JavaScript 1.5 at least. Use
the return values of String.prototype.match() and RegExp.prototype.exec(),
respectively, instead.

<https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Deprecated_Features#RegExp_Properties>

Asen Bozhilov

unread,
May 11, 2010, 3:45:13 PM5/11/10
to
Matt Kruse wrote:

> Does anyone here use a general convenience method for deep property
> access that will not throw an error if any property along the chain is
> undefined?
>
> For example:
>
> deep(document, "body.firstChild.style.backgroundColor");
> or
> deep("myElementId.childNodes[3].id");

Square bracket notation allow to used returned result by expression,
and that result is not bound as Identifiers rules defined by ECMA-262.
With your strategy you would have problems. For example:

var obj = {};
obj['.prop.'] = true;
obj['[prop]'] = true;

print(obj['.prop.']);
print(obj['[prop]'])

Your strategy is too complex and implementation will be terrible any
time. For example you can use evil for your purposes:

eval(properties);

Of course that is not solve the design problems. I will prefer to use
array which contain each property name. For example:

deep(context, ['property1', 'property2', 'propertyN']);


Matt Kruse

unread,
May 11, 2010, 4:59:48 PM5/11/10
to
On May 11, 1:06 pm, Scott Sauyet <scott.sau...@gmail.com> wrote:
> > True. But since you're passing in a string, couldn't you just do:
> > $prop("myObj.prop1.prop2."+current.value)
> > ?
> Sure, unless current is undefined, which I think is the original
> problem we're trying to solve.  :-)

I think it's good to solve the most general case that is reasonable
and useful, but not EVERY general case.

> And of course we could want
>     $props("myObj.prop1.prop2[current.deeply.nested.value]")
> as well.

Sure, you COULD do that, but I don't imagine I ever WOULD. So solving
that case holds little value for me. But using my function, I suppose
you could do:

if ( $prop("current.deeply.nested.value") ) {
$prop("myObj.prop1.prop2."+$prop())
}

Matt Kruse

Matt Kruse

unread,
May 11, 2010, 5:03:28 PM5/11/10
to
On May 11, 2:45 pm, Asen Bozhilov <asen.bozhi...@gmail.com> wrote:
> Square bracket notation allow to used returned result by expression,
> and that result is not bound as Identifiers rules defined by ECMA-262.
> With your strategy you would have problems. For example:
> var obj = {};
> obj['.prop.'] = true;
> obj['[prop]'] = true;
>
> print(obj['.prop.']);
> print(obj['[prop]'])
>
> Your strategy is too complex

But why would you EVER do that? I'm not building this for idiots!

> and implementation will be terrible any
> time.

I don't know, my implementation is pretty straight-forward and works
well.

> For example you can use evil for your purposes:
> eval(properties);

Which will still throw errors.

> I will prefer to use
> array which contain each property name. For example:
> deep(context, ['property1', 'property2', 'propertyN']);

How is that any better than joining the array with "." and passing a
single string?!

Matt Kruse

Garrett Smith

unread,
May 11, 2010, 5:07:38 PM5/11/10
to
Asen Bozhilov wrote:
> Matt Kruse wrote:
>

[...]

> eval(properties);
>
> Of course that is not solve the design problems. I will prefer to use
> array which contain each property name. For example:
>
> deep(context, ['property1', 'property2', 'propertyN']);
>

Does deep check own or prototype?
--
Garrett
comp.lang.javascript FAQ: http://jibbering.com/faq/

Thomas 'PointedEars' Lahn

unread,
May 11, 2010, 5:10:20 PM5/11/10
to
Matt Kruse wrote:

> Asen Bozhilov wrote:
>> Square bracket notation allow to used returned result by expression,
>> and that result is not bound as Identifiers rules defined by ECMA-262.
>> With your strategy you would have problems. For example:
>> var obj = {};
>> obj['.prop.'] = true;
>> obj['[prop]'] = true;
>>
>> print(obj['.prop.']);
>> print(obj['[prop]'])
>>
>> Your strategy is too complex
>
> But why would you EVER do that?

It can be necessary for mapping values that property names contain dots or
brackets.

> I'm not building this for idiots!

ISTM you are not building this for people who do DOM scripting either.
<form>...<input name="foo[]">...</form>

> [...]

>> I will prefer to use array which contain each property name. For example:
>> deep(context, ['property1', 'property2', 'propertyN']);
>
> How is that any better than joining the array with "." and passing a
> single string?!

The property names are clear.


PointedEars
--
var bugRiddenCrashPronePieceOfJunk = (
navigator.userAgent.indexOf('MSIE 5') != -1
&& navigator.userAgent.indexOf('Mac') != -1
) // Plone, register_function.js:16

Thomas 'PointedEars' Lahn

unread,
May 11, 2010, 5:13:00 PM5/11/10
to
Garrett Smith wrote:

> Asen Bozhilov wrote:
>> eval(properties);
>>
>> Of course that is not solve the design problems. I will prefer to use
>> array which contain each property name. For example:
>>
>> deep(context, ['property1', 'property2', 'propertyN']);
>
> Does deep check own or prototype?

You want to re-read the thread and re-think your question.

Scott Sauyet

unread,
May 11, 2010, 5:20:20 PM5/11/10
to

It's more general, not necessarily better. But it does address the
issues Thomas raises, and allows for the generality I was suggesting.
If your simple cases are all you ever need, by all means use a simpler
strategy.

It also has the advantage that you can pass variables holding strings
without manual concatenation. The only thing I would do differently
than the above is that I would remove the array and deal with variable
arguments; this seems cleaner to me:

deep(context, 'property1', 'property2', 'propertyN');

This still does not get at the even more general solution I mentioned,
and which I tried to implement some time ago. But of course that
solution had the problem yours does with property names containing
periods or brackets. I used an escape syntax for those, and that's
where some of the clean API went up in smoke.

I will see if I still have a copy of that code at home. I'm curious
to see how much five-year-old code might make me shudder.

--
Scott

Asen Bozhilov

unread,
May 11, 2010, 5:24:09 PM5/11/10
to
Matt Kruse wrote:
> Asen Bozhilov wrote:


> > I will prefer to use
> > array which contain each property name. For example:
> > deep(context, ['property1', 'property2', 'propertyN']);
>
> How is that any better than joining the array with "." and passing a
> single string?!

At all you miss the point and wrote in arrogant way that reply. Could
you show an implementation which works with:

var obj = {
property : {
'.property.' : {
'[property]' : true
}
}
};

$prop(obj, 'property[.property.][[property]]');

I expect `true' instead of `undefined'. So when you show that
implementation we can again talk about the complex of the problem
which you try to solve.

Matt Kruse

unread,
May 11, 2010, 5:28:21 PM5/11/10
to
On May 11, 4:20 pm, Scott Sauyet <scott.sau...@gmail.com> wrote:
> this seems cleaner to me:
>     deep(context, 'property1', 'property2', 'propertyN');

Would it handle this:

deep(context, 'prop1[0]')

if 'context' has no property named 'prop1'?
And what if 'context' has a property named 'myarray[0]' which is an
array?

deep(context, 'myarray[0][0]')

?

Matt Kruse

Garrett Smith

unread,
May 11, 2010, 5:30:33 PM5/11/10
to
Matt Kruse wrote:
> On May 11, 2:45 pm, Asen Bozhilov <asen.bozhi...@gmail.com> wrote:
>> Square bracket notation allow to used returned result by expression,
>> and that result is not bound as Identifiers rules defined by ECMA-262.
>> With your strategy you would have problems. For example:
>> var obj = {};
>> obj['.prop.'] = true;
>> obj['[prop]'] = true;
>>
>> print(obj['.prop.']);
>> print(obj['[prop]'])
>>
>> Your strategy is too complex
>
> But why would you EVER do that? I'm not building this for idiots!
>

Host:
navigator.plugins["Shockwave Flash 2.0"]?

User defined:
myObject[ prop.toString() ] = val;

[...]

Matt Kruse

unread,
May 11, 2010, 5:31:10 PM5/11/10
to
On May 11, 4:24 pm, Asen Bozhilov <asen.bozhi...@gmail.com> wrote:
> At all you miss the point and wrote in arrogant way that reply.

I don't think the reply was at all arrogant, but we may have a
separation in language.

> Could you show an implementation which works with:
> var obj = {
>   property : {
>     '.property.' : {
>       '[property]' : true
>     }
>   }
>
> };
> $prop(obj, 'property[.property.][[property]]');
> I expect `true' instead of `undefined'. So when you show that
> implementation we can again talk about the complex of the problem
> which you try to solve.

That is a more complex problem, yes. But it's one that _you_ are
proposing to solve, not me ;)

I will gladly limit the potential situations for which my solution
will apply, which for my case will probably cover 99.9% of the cases.
In the rare cases where it doesn't, I'm happier with writing context-
specific code rather than extending my solution to a more general,
obscure case.

Matt Kruse

Garrett Smith

unread,
May 11, 2010, 5:31:44 PM5/11/10
to
Thomas 'PointedEars' Lahn wrote:
> Garrett Smith wrote:
>
>> Asen Bozhilov wrote:

[...]

> You want to re-read the thread and re-think your question.

I want you to stop taking your personal frustrations out on this NG.

Thomas 'PointedEars' Lahn

unread,
May 11, 2010, 5:43:21 PM5/11/10
to
Matt Kruse wrote:

> Scott Sauyet wrote:
>> this seems cleaner to me:
>> deep(context, 'property1', 'property2', 'propertyN');
>
> Would it handle this:
>
> deep(context, 'prop1[0]')
>
> if 'context' has no property named 'prop1'?

No, for it would be looking for a property named `prop1[0]'. To look up the
`0' property of the object referred to by the `prop1' property, you would of
course call it so:

deep(context, 'prop1', 0)

> And what if 'context' has a property named 'myarray[0]' which is an
> array?
>
> deep(context, 'myarray[0][0]')
>
> ?

deep(context, 'myarray[0]', 0)

or

deep(context, ['myarray[0]', 0])

Which one you prefer would depend on the purpose. For example, for
JSX:isMethod/areMethods() I used additional arguments for property names
that are part of the same member expression, and a trailing additional array
argument for names of properties that are properties of the same object,
i.e.

jsx.object.areMethods(foo, 'bar', ['baz', 'bla'])

returns `true' iff both `foo.bar.baz' and `foo.bar.bla' refer to supposedly
callable objects that are referred to by properties of an object (in short:
methods).

Thomas 'PointedEars' Lahn

unread,
May 11, 2010, 5:45:49 PM5/11/10
to
Garrett Smith wrote:

> Thomas 'PointedEars' Lahn wrote:
>> Garrett Smith wrote:
>>> Asen Bozhilov wrote:
> [...]
>> You want to re-read the thread and re-think your question.
>
> I want you to stop taking your personal frustrations out on this NG.

It was merely a hint, stupid, and you managed to miss it.

Garrett Smith

unread,
May 11, 2010, 5:48:19 PM5/11/10
to
Thomas 'PointedEars' Lahn wrote:
> Garrett Smith wrote:
>
>> Thomas 'PointedEars' Lahn wrote:
>>> Garrett Smith wrote:
>>>> Asen Bozhilov wrote:
>> [...]
>>> You want to re-read the thread and re-think your question.
>> I want you to stop taking your personal frustrations out on this NG.
>
> It was merely a hint, stupid, and you managed to miss it.
>
That is exactly what I am talking about.

Thomas 'PointedEars' Lahn

unread,
May 11, 2010, 6:05:14 PM5/11/10
to
Garrett Smith wrote:

> Thomas 'PointedEars' Lahn wrote:
>> Garrett Smith wrote:
>>> Thomas 'PointedEars' Lahn wrote:
>>>> Garrett Smith wrote:
>>>>> Asen Bozhilov wrote:
>>> [...]
>>>> You want to re-read the thread and re-think your question.
>>> I want you to stop taking your personal frustrations out on this NG.
>> It was merely a hint, stupid, and you managed to miss it.
>>
> That is exactly what I am talking about.

Calling you stupid when you do stupid things is a telling a fact, not an
expression of any personal frustration I might have. So the problem is on
your part, not on mine.


PointedEars
--
Use any version of Microsoft Frontpage to create your site.
(This won't prevent people from viewing your source, but no one
will want to steal it.)
-- from <http://www.vortex-webdesign.com/help/hidesource.htm> (404-comp.)

Garrett Smith

unread,
May 11, 2010, 10:20:38 PM5/11/10
to
Thomas 'PointedEars' Lahn wrote:
> Garrett Smith wrote:
>
>> Thomas 'PointedEars' Lahn wrote:
>>> Garrett Smith wrote:
>>>> Thomas 'PointedEars' Lahn wrote:
>>>>> Garrett Smith wrote:
>>>>>> Asen Bozhilov wrote:
>>>> [...]
>>>>> You want to re-read the thread and re-think your question.
>>>> I want you to stop taking your personal frustrations out on this NG.
>>> It was merely a hint, stupid, and you managed to miss it.
>>>
>> That is exactly what I am talking about.
>
> Calling you stupid when you do stupid things is a telling a fact, not an
> expression of any personal frustration I might have. So the problem is on
> your part, not on mine.
>
That's your opinion based on your observations. My observation is that
Asen did not post code; I guess his `deep` does check prototype chain
but it's not something that's been mentioned yet.

Matt Kruse

unread,
May 12, 2010, 7:58:23 AM5/12/10
to
On May 11, 4:10 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> > I'm not building this for idiots!
> ISTM you are not building this for people who do DOM scripting either.
> <form>...<input name="foo[]">...</form>

This already works fine:

$prop(document, "forms[0].foo[].value")

for example.

Matt Kruse

Matt Kruse

unread,
May 12, 2010, 8:01:15 AM5/12/10
to
On May 11, 4:24 pm, Asen Bozhilov <asen.bozhi...@gmail.com> wrote:
> Could you show an implementation which works with:
> var obj = {
>   property : {
>     '.property.' : {
>       '[property]' : true
>     }
>   }
>
> };
> $prop(obj, 'property[.property.][[property]]');
> I expect `true' instead of `undefined'. So when you show that
> implementation we can again talk about the complex of the problem
> which you try to solve.

Easy. I just modified the function to accept an optional last
parameter of delimiter.
So in this case you could just do:

$prop(obj, 'property|.property.|[property]', '|')

Maybe not as straight-forward as passing multiple arguments, but same
difference.

Matt Kruse

Thomas 'PointedEars' Lahn

unread,
May 12, 2010, 8:20:00 AM5/12/10
to
Matt Kruse wrote:

No, by contrast you will not be able to handle property names that contain
`|'.

Thomas 'PointedEars' Lahn

unread,
May 12, 2010, 8:21:13 AM5/12/10
to
Matt Kruse wrote:

> Thomas 'PointedEars' Lahn wrote:
>> > I'm not building this for idiots!
>> ISTM you are not building this for people who do DOM scripting either.
>> <form>...<input name="foo[]">...</form>
>
> This already works fine:
>
> $prop(document, "forms[0].foo[].value")
>
> for example.

You miss the point.

Matt Kruse

unread,
May 12, 2010, 9:26:03 AM5/12/10
to
On May 12, 7:20 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> No, by contrast you will not be able to handle property names that contain
> `|'.

Umm, then you just pick a different delimiter that doesn't conflict
with your property names. Duh.

Matt Kruse

Matt Kruse

unread,
May 12, 2010, 9:26:44 AM5/12/10
to
On May 12, 7:21 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> Matt Kruse wrote:
> > Thomas 'PointedEars' Lahn wrote:
> >> > I'm not building this for idiots!
> >> ISTM you are not building this for people who do DOM scripting either.
> >> <form>...<input name="foo[]">...</form>
> > This already works fine:
> > $prop(document, "forms[0].foo[].value")
> > for example.
> You miss the point.

On the contrary, you fail to make one.

Matt Kruse

David Mark

unread,
May 12, 2010, 9:38:29 AM5/12/10
to

And you still can't see why you are making a colossal design mistake?
Don't parse strings. Pass multiple arguments or an array of strings.
There you go.

David Mark

unread,
May 12, 2010, 9:39:39 AM5/12/10
to

No, as usual, you waste endless amounts of time "debating" when you
could be working. How do you ever get anything done?

Scott Sauyet

unread,
May 12, 2010, 9:52:41 AM5/12/10
to

Right, that is fairly obscure. But Thomas gave an example that is
quite realistic:

| <form>...<input name="foo[]">...</form>

A number of server-side environments might generate something like
that.

The question then is whether you want your solution to work for those
fairly common cases or if you are just as happy writing context-
specific code for them.

I did check for my old code last night and couldn't find anything from
that project. (It's not really mine anyway, but the client would
almost certainly give me permission to share it.) But it was single-
String-based like yours rather than multiple parameters as Thomas and
Asen are suggesting. And I did work with the more complex cases, but
as I did so, the code became more brittle and harder to use.
Eventually we abandoned it altogether.

If you want just the simple cases, then a single string is still okay.

But if you want to handle even reasonably common more complex cases,
then I would suggest that you use a multiple string parameter version,
whether in an array or not.

--
Scott

Asen Bozhilov

unread,
May 12, 2010, 10:08:14 AM5/12/10
to
Garrett Smith wrote:
> Asen Bozhilov wrote:

> > Of course that is not solve the design problems. I will prefer to use
> > array which contain each property name. For example:
>
> > deep(context, ['property1', 'property2', 'propertyN']);
>
> Does deep check own or prototype?

The meaning of _deep_ here is not related with prototype chain. The
deep here is used as deep level of property accessing instead. But if
I should implement that method I will use square bracket notation for
each property and that will lookup in prototype chain. I do not see
any reasons to handle only own properties.

Asen Bozhilov

unread,
May 12, 2010, 10:13:37 AM5/12/10
to
Matt Kruse wrote:

> Asen Bozhilov wrote:
>
> > Could you show an implementation which works with:
> > var obj = {
> >   property : {
> >     '.property.' : {
> >       '[property]' : true
> >     }
> >   }
>
> > };
> > $prop(obj, 'property[.property.][[property]]');

> Easy. I just modified the function to accept an optional last


> parameter of delimiter.
> So in this case you could just do:
>
> $prop(obj, 'property|.property.|[property]', '|')

That produce unreadable and unnatural code. If you want to use string
instead of list with properties, why not use just one notation? For
example you can use only dot notation and do restrictions on property
names cannot hold dot in their names. That will solve your problems,
and allow you to use simple code for parsing property names.

Matt Kruse

unread,
May 12, 2010, 10:19:42 AM5/12/10
to

I wouldn't say it's a colossal design mistake. It's a limitation, in
order to have the convenience of a single string to identify the
property. It's easier to read, and will work just fine almost all
common cases.

I could modify it to take any number of arguments, to support both
ways of accessing the properties - either as a single string with no .
in it, or as multiple strings with no limitations.

Matt Kruse


Scott Sauyet

unread,
May 12, 2010, 10:32:41 AM5/12/10
to
David Mark wrote:
> Matt Kruse wrote:
>> Thomas 'PointedEars' Lahn wrote:
>>> Matt Kruse wrote:
>>>> Thomas 'PointedEars' Lahn wrote:
>>>>>> I'm not building this for idiots!
>>>>> ISTM you are not building this for people who do DOM scripting either.
>>>>> <form>...<input name="foo[]">...</form>
>>>> This already works fine:
>>>> $prop(document, "forms[0].foo[].value")
>>>> for example.
>>> You miss the point.
>> On the contrary, you fail to make one.
> No, as usual, you waste endless amounts of time "debating" when you
> could be working.  How do you ever get anything done?

David,

Matt, who has spend far less time debating here in recent months than
either your or I, came here asking for discussion on an API he was
designing. He has certainly gotten that. He has, unsurprisingly,
been defending the decisions he's made, but he has not shown any signs
of being unwilling to listen to criticism. His only sign of testiness
was in his response to Thomas' bald assertion, "You miss the point."

Thomas has made some positive contributions to this thread. That post
was not among them, and I don't fault Matt for responding in a like
manner. Your only contribution of substance was another bald
assertion that his single-string API is a design mistake. You didn't
justify it at all. While I agree with you, based upon my own
experience with a similar API built some years back, your only posts
in this thread have been argumentative and not at all constructive.

It seems to me that it's you who's wasting time here.

(And now me too. Damn!)

--
Scott

Matt Kruse

unread,
May 12, 2010, 10:58:27 AM5/12/10
to
On May 12, 8:52 am, Scott Sauyet <scott.sau...@gmail.com> wrote:
> Right, that is fairly obscure.  But Thomas gave an example that is
> quite realistic:
> | <form>...<input name="foo[]">...</form>
> A number of server-side environments might generate something like
> that.

As I responded to him, the code in its current form works fine in this
case, or any case where a property has "[]" in it's name. It just
fails if the property has "[\d+]" in its name. I realize this also
happens in cases like:
<input name="person[0].phone">
which can be generated from frameworks like Struts, for example.

It's a limitation, certainly.

But IMO, a limitation does not necessarily mean a bad API or useless
function. It's pro/con.

If you can solve 99% of cases with straight-forward code which fails
on the remaining 1%, then I think it would be a mistake to through
that out just because you can't solve the most general case. That kind
of thinking leads to being less productive and insanity ;) But on the
flip side, I do think it's good to be as generalized as practical, and
that's exactly why I threw it out here. To get feedback and to point
out cons that I hadn't considered. For that, it has been useful
already.

Matt Kruse

Scott Sauyet

unread,
May 12, 2010, 11:01:01 AM5/12/10
to
Matt Kruse <m...@thekrusefamily.com> wrote:
> I could modify it to take any number of arguments, to support both
> ways of accessing the properties - either as a single string with no .
> in it, or as multiple strings with no limitations.

I would suggest you don't. Make your API as clean as possible while
still meeting your requirements and then live with whatever
restrictions that entails. Of all the critiques of jQuery I've seen
here, by far the most compelling is against the re-use of "$" to mean
so many different things.

--
Scott

Garrett Smith

unread,
May 12, 2010, 11:57:40 AM5/12/10
to
Asen Bozhilov wrote:
> Garrett Smith wrote:
>> Asen Bozhilov wrote:
>
>>> Of course that is not solve the design problems. I will prefer to use
>>> array which contain each property name. For example:
>>> deep(context, ['property1', 'property2', 'propertyN']);
>> Does deep check own or prototype?
>
> The meaning of _deep_ here is not related with prototype chain.

Obviously.

The
> deep here is used as deep level of property accessing instead. But if
> I should implement that method I will use square bracket notation for
> each property and that will lookup in prototype chain. I do not see
> any reasons to handle only own properties.
>

Makes sense.

Thomas 'PointedEars' Lahn

unread,
May 12, 2010, 12:32:54 PM5/12/10
to
Matt Kruse wrote:

> Thomas 'PointedEars' Lahn wrote:
>> No, by contrast you will not be able to handle property names that
>> contain `|'.
>
> Umm, then you just pick a different delimiter that doesn't conflict
> with your property names. Duh.

Your shortsightedness blinds you again for the possibilities that await you.
As long as you choose string delimiters for separating parts of the
/MemberExpression/ used to access a property, your implementation will not
be able to deal with objects that have properties with names that contain
those delimiters.

Matt Kruse

unread,
May 12, 2010, 1:06:51 PM5/12/10
to
On May 12, 11:32 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> Your shortsightedness blinds you again for the possibilities that await you.  
> As long as you choose string delimiters for separating parts of the
> /MemberExpression/ used to access a property, your implementation will not
> be able to deal with objects that have properties with names that contain
> those delimiters.

Thank you, Captain Obvious!

Be careful with these astounding leaps of logic. Soon you'll be making
conjectures like "The round ball is round". Sweet hot damn! Genius! :)

Matt "the key to picking a good delimiter is to use one that is not
contained in your string expression" Kruse

Thomas 'PointedEars' Lahn

unread,
May 12, 2010, 1:07:18 PM5/12/10
to
Matt Kruse wrote:

> Thomas 'PointedEars' Lahn wrote:
>> Matt Kruse wrote:
>> > Thomas 'PointedEars' Lahn wrote:
>> >> > I'm not building this for idiots!
>> >> ISTM you are not building this for people who do DOM scripting either.
>> >> <form>...<input name="foo[]">...</form>
>> > This already works fine:
>> > $prop(document, "forms[0].foo[].value")
>> > for example.
>> You miss the point.
>
> On the contrary, you fail to make one.

It is not that hard to miss, see <news:2882225.e...@PointedEars.de>.

Thomas 'PointedEars' Lahn

unread,
May 12, 2010, 1:13:53 PM5/12/10
to
Matt Kruse wrote:

> Thomas 'PointedEars' Lahn wrote:
>> Your shortsightedness blinds you again for the possibilities that await
>> you. As long as you choose string delimiters for separating parts of the
>> /MemberExpression/ used to access a property, your implementation will
>> not be able to deal with objects that have properties with names that
>> contain those delimiters.
>

> [...]


> Matt "the key to picking a good delimiter is to use one that is not
> contained in your string expression" Kruse

How naive are you anyway? *Any* Unicode character may be contained in a
property name. The only way for you to work around that problem is to
provide a way for the user of the function/library to define the
delimiter(s) before or upon the call and to make the provision that property
names of the object do not contain it/them.

However, no such provision is necessary and it it is more efficient, a lot
more simple and compatible not to use a string delimiter that you need to
split on in the first place.

Scott Sauyet

unread,
May 12, 2010, 1:16:42 PM5/12/10
to
Thomas 'PointedEars' Lahn wrote:
> Matt Kruse wrote:
>> Thomas 'PointedEars' Lahn wrote:
>>> No, by contrast you will not be able to handle property names that
>>> contain `|'.
>
>> Umm, then you just pick a different delimiter that doesn't conflict
>> with your property names. Duh.
>
> Your shortsightedness blinds you again for the possibilities that await you.  
> As long as you choose string delimiters for separating parts of the
> /MemberExpression/ used to access a property, your implementation will not
> be able to deal with objects that have properties with names that contain
> those delimiters.

While I agree with what seems to be the majority opinion that strings
with delimiters are not the best solution, I'm not sure I can buy this
objection. Matt said he was passing alternative delimiters as an
additional parameter to the call. Since the presumed use is something
like

var xyz = $prop(document, "forms[0].foo[].value");

or if necessary,

var xyz = $prop(obj, 'property|.property.|[property]', '|');

and not

var xyz = $prop(obj, myStringVar);

it's easy enough to see by inspection that the delimiter is not
included in the string. The point is that this is to be used for
known source code and data structures; it's simply a mechanism to
avoid the nested chains of checking on the existence of intermediate
properties on the chain. It's not, in my understanding, an attempt to
provide a general-purpose property-fetching API for arbitrary data
structures.

If you've used a Java template engine such as Velocity or Freemarker,
it would be an attempt at something similar to the dotted property
access notation that they provide. Instead of code like:

public String fetch(MyClass myObj) {
if (myObj != null) {
SomeClass path = myObj.getPath();
if (myPath != null) {
AnotherClass to = myPath.getTo();
if (to != null) {
String property = to.getProperty();
if (property != null) {
return property;
}
}
}
}
return "";
}


these tools allow access the property like this:

${myObj.path.to.property}


The big difference in ECMASCript is that the period is allowed as part
of property identifiers. If Matt's code allowed you to, if necessary,
use this instead:

$prop(myObj "path~to~property", "~")

I simply don't see the issue.

-- Scott

Thomas 'PointedEars' Lahn

unread,
May 12, 2010, 2:00:17 PM5/12/10
to
Scott Sauyet wrote:

Utter nonsense.

First of all, to $prop() there is exactly no difference with regard to how
the value was passed. That's not only JavaScript 101, it's Programming 101.

Second, without further information the first property access could be the
equivalent of any of the following, with the list not making a claim to be
complete:

document.forms[0].foo.["[]"].value
document.forms[0]["foo[]"].value
document.forms["[0].foo[]"].value
document["forms[0]"]["foo[]"].value
document["forms[0].foo[]"].value
document["forms[0]"]["foo[].value"]
document["forms[0].foo[].value"]

With the second approach, it needs to be clearly defined which delimiter is
used if no delimiter is specified.

Third, with either solution the issue remains that a property name may not
contain the delimiter then, when that would not be necessary had a different
approach been chosen. IOW, it is not possible to access

obj["property"][".property."]["[prop|erty]"]

with

$prop(obj, 'property|.property.|[prop|erty]', '|')

because that would access

obj["property"][".property."]["[prop"]["erty]"]

instead. And if you defined `[' and `]' (or something else) as delimiter
for property names you would could not have property names that contained
them. Or your would have to implement an escape syntax so that those
characters are not considered delimiters, which would exclude those escape
sequences from being part of property names.

But all of this is completely unnecessary if you let the programming
language provide the delimiter, i.e. arguments, Arrays, or a combination
thereof.


PointedEars
--
realism: HTML 4.01 Strict
evangelism: XHTML 1.0 Strict
madness: XHTML 1.1 as application/xhtml+xml
-- Bjoern Hoehrmann

Thomas 'PointedEars' Lahn

unread,
May 12, 2010, 2:10:32 PM5/12/10
to
Thomas 'PointedEars' Lahn wrote:

> Scott Sauyet wrote:
>> var xyz = $prop(document, "forms[0].foo[].value");

>> [...]
>
> [...] without further information the first property access could be the


> equivalent of any of the following, with the list not making a claim to be
> complete:
>
> document.forms[0].foo.["[]"].value

document.forms[0].foo["[]"].value

> document.forms[0]["foo[]"].value
> document.forms["[0].foo[]"].value
> document["forms[0]"]["foo[]"].value
> document["forms[0].foo[]"].value
> document["forms[0]"]["foo[].value"]
> document["forms[0].foo[].value"]

> [...]

Matt Kruse

unread,
May 12, 2010, 2:23:34 PM5/12/10
to
On May 12, 1:00 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> Third, with either solution the issue remains that a property name may not
> contain the delimiter then, when that would not be necessary had a different
> approach been chosen.  IOW, it is not possible to access
>   obj["property"][".property."]["[prop|erty]"]
> with
>   $prop(obj, 'property|.property.|[prop|erty]', '|')
> because that would access
>   obj["property"][".property."]["[prop"]["erty]"]

Are you being intentionally obtuse?

$prop(obj, 'property/.property./[prop|erty]', '/')
or
$prop(obj, 'property#.property.#[prop|erty]', '#')
or
$prop(obj, 'propertySHUTUPTHOMAS.property.SHUTUPTHOMAS[prop|erty]',
'SHUTUPTHOMAS')

Take your pick.

I agree this is not the best syntax. I proposed it as a solution only
to counter your nit-picking about dots in property names.

In reality, if the properties contained such characters, I would
either not use the function or I would modify it, or perhaps make an
alternative version that takes arguments as parameters.

Matt Kruse

Thomas 'PointedEars' Lahn

unread,
May 12, 2010, 2:50:27 PM5/12/10
to
Matt Kruse wrote:

> Thomas 'PointedEars' Lahn wrote:
>> Third, with either solution the issue remains that a property name may
>> not contain the delimiter then, when that would not be necessary had a
>> different approach been chosen. IOW, it is not possible to access
>> obj["property"][".property."]["[prop|erty]"]
>> with
>> $prop(obj, 'property|.property.|[prop|erty]', '|')
>> because that would access
>> obj["property"][".property."]["[prop"]["erty]"]
>
> Are you being intentionally obtuse?

No, you are. The issue is fairly obvious, but you choose to ignore it.



> $prop(obj, 'property/.property./[prop|erty]', '/')
> or
> $prop(obj, 'property#.property.#[prop|erty]', '#')
> or

So property names containing `/' and `#' could not be accessed then, i.e.
neither

$prop(obj, 'property/.property./[prop#/erty]', '/')

nor

$prop(obj, 'property#.property.#[prop#/erty]', '#')

could access e.g.

obj["property#"][".prop/erty."]["#[prop#/erty]"]

aso.

And if you used an array of delimiters instead of only one delimiter, or a
regular expression, the matched characters could not be contained in a
property name.

> $prop(obj, 'propertySHUTUPTHOMAS.property.SHUTUPTHOMAS[prop|erty]',
> 'SHUTUPTHOMAS')

Shut up yourself and power up your brain for a change.

> Take your pick.

I will continue to choose the rational, logical course of action;
so not yours.



> I agree this is not the best syntax.

You are a master of understatement. Your $prop() will be unable to access a
property if any property name along the way contains any designated
delimiter. That way you are limiting its capabilities. Needlessly.


Score adjusted

PointedEars
--
Anyone who slaps a 'this page is best viewed with Browser X' label on
a Web page appears to be yearning for the bad old days, before the Web,
when you had very little chance of reading a document written on another
computer, another word processor, or another network. -- Tim Berners-Lee

Stefan Weiss

unread,
May 12, 2010, 2:52:23 PM5/12/10
to
On 11/05/10 15:44, Matt Kruse wrote:
> Does anyone here use a general convenience method for deep property
> access that will not throw an error if any property along the chain is
> undefined?
>
> For example:
>
> deep(document, "body.firstChild.style.backgroundColor");
> or
> deep("myElementId.childNodes[3].id");
> or
> deep( myJsonObject,
> "locations.ca.sandiego.directory.people.smith.john.phone");
>
> This would return undefined if any element along the chain is not
> there, or index is out of bounds, etc. If the chain gets to the end,
> it would return the last-evaluated value. This would be convenient for
> accessing deep properties of objects that may or may not exist, and
> not having to manually check the chain in your code.

This may be obvious, but did you consider simply catching and ignoring
the ReferenceError?

try { var color = body.firstChild.style.backgroundColor; } catch(e) {}

Maybe it doesn't look as nice as your deep() call, but at least there's
no custom syntax involved, and you can use arbitrary property names,
including all the counter examples mentioned by Thomas, and even
expressions like childNodes[i+1].


--
stefan

Scott Sauyet

unread,
May 12, 2010, 3:05:03 PM5/12/10
to
Thomas 'PointedEars' Lahn wrote:
> Scott Sauyet wrote:
>> Since the presumed use is something like
>>     var xyz = $prop(document, "forms[0].foo[].value");
>> or if necessary,
>>     var xyz = $prop(obj, 'property|.property.|[property]', '|');
>> and not
>>     var xyz = $prop(obj, myStringVar);
>> it's easy enough to see by inspection that the delimiter is not
>> included in the string.
>
> Utter nonsense.
>
> First of all, to $prop() there is exactly no difference with regard to how
> the value was passed.  That's not only JavaScript 101, it's Programming 101.

That's correct. And similarly, an API like
document.getElementById(value) does not prohibit you from supplying a
number or the window object as the value parameter. But those are
still not good ideas. To me an API like this is something more like a
macro than a function call. Of course someone could misuse it. But
that's not enough of a reason for discarding it. The only reason I
would have for using it would be to make my code simpler. I would
never use it with anything other than a string literal. If the
language had a facility to prevent the user from passing something
else, I would take advantage of it; as it stands, its limitations
would have to be documented.

Perhaps it was later in Programming 101 that students learn that not
everything you might want to do is supplied by the language or the
rest of the programming environment, that you might have to extend
that environment with your own code, and that sometimes that code has
to make compromises between simplicity and completeness.


> [ ... ]


> But all of this is completely unnecessary if you let the programming
> language provide the delimiter, i.e. arguments, Arrays, or a combination
> thereof.

It's not that I disagree. But I think your arguments are overstated.
If Matt is going to publish this and promote it as an amazing tool
that will drastically increase the productivity of any web developer,
then he really should skip the string parsing and go with the more
complete API. But if he is going to use this on a few projects with a
half-dozen other coders, I would suggest that simplicity should rule.

--
Scott

Matt Kruse

unread,
May 12, 2010, 3:37:12 PM5/12/10
to
On May 12, 1:50 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> So property names containing `/' and `#' could not be accessed then, i.e.
> neither
>    $prop(obj, 'property/.property./[prop#/erty]', '/')
> nor
>   $prop(obj, 'property#.property.#[prop#/erty]', '#')
> could access e.g.
>   obj["property#"][".prop/erty."]["#[prop#/erty]"]

Are you missing the basic point that you PICK the delimiter based on
the string you are passing in?

1. Pick your property string to evaluate
2. If the properties contain . or [ or ], then pick a delimiter
3. Choose the delimiter to be a character or sequence of characters
that does not exist in your property string

Is that so hard to understand?

Similar to perl, where you can do:

$var =~ s/a/b/;
or
$var =~ s|a/b|c/d|;
or
$var =~ s#a/b#c/d#;

Nevertheless, your examples are sufficiently insane to not warrant
consideration in any real case that I will ever expect to encounter.

Matt Kruse

Matt Kruse

unread,
May 12, 2010, 3:38:52 PM5/12/10
to
On May 12, 1:52 pm, Stefan Weiss <krewech...@gmail.com> wrote:
> This may be obvious, but did you consider simply catching and ignoring
> the ReferenceError?
>   try { var color = body.firstChild.style.backgroundColor; } catch(e) {}
> Maybe it doesn't look as nice as your deep() call, but at least there's
> no custom syntax involved, and you can use arbitrary property names,
> including all the counter examples mentioned by Thomas, and even
> expressions like childNodes[i+1].

Yes indeed, in fact some of the code I have has that littered all
over. It makes it harder to read, IMO. But it certainly has the
benefits you describe.

I'm also not familiar enough with the performance hit of try/catch to
know if that's even a factor. In some versions of some languages, it
can be quite costly to enter a try/catch block.

Matt Kruse

Thomas 'PointedEars' Lahn

unread,
May 12, 2010, 3:55:16 PM5/12/10
to
Scott Sauyet wrote:

> Thomas 'PointedEars' Lahn wrote:
>> [...]


>> But all of this is completely unnecessary if you let the programming
>> language provide the delimiter, i.e. arguments, Arrays, or a combination
>> thereof.
>
> It's not that I disagree. But I think your arguments are overstated.
> If Matt is going to publish this and promote it as an amazing tool
> that will drastically increase the productivity of any web developer,
> then he really should skip the string parsing and go with the more
> complete API. But if he is going to use this on a few projects with a
> half-dozen other coders, I would suggest that simplicity should rule.

And exactly therefore string parsing is a really bad idea here, for it
*complicates* matters *needlessly*. It requires the caller to think hard
about what delimiter can be used, in fact it requires them to parse the
argument by *themselves*, instead of just passing the arguments and let the
function do all the work. I fail to see why it should be simpler to call

$prop(obj, 'prop/erty..prop#erty..[prop|erty]')

no, wait, the dot is already used, must be

$prop(obj, 'prop/erty|.prop#erty.|[prop|erty]', '|')

no, wait, there's a pipe in a name, so must be

$prop(obj, 'prop/erty#.prop#erty.#[prop|erty]', '#')

no, wait, that darn hash is also used, must be

$prop(obj, 'prop/erty/.prop#erty./[prop|erty]', '/')

no, wait, that f***ing slash is already used, too, so must be

$prop(obj, 'prop/erty%.prop#erty.%[prop|erty]', '%')

-- and let's hope that we don't have overlooked a cursed `%' somewhere in
the real case -- instead of simply

$prop(obj, 'prop/erty', '.prop#erty.', '[prop|erty]')

or

$prop(obj, ['prop/erty', '.prop#erty.', '[prop|erty]'])

or a combination thereof.

So please forgive me if I really fail to see that kind of simplicity you are
talking about with the string-parsing approach.

Garrett Smith

unread,
May 12, 2010, 3:57:53 PM5/12/10
to
Stefan Weiss wrote:
> On 11/05/10 15:44, Matt Kruse wrote:
>> Does anyone here use a general convenience method for deep property

[...]

> This may be obvious, but did you consider simply catching and ignoring
> the ReferenceError?
>
> try { var color = body.firstChild.style.backgroundColor; } catch(e) {}
>
> Maybe it doesn't look as nice as your deep() call, but at least there's
> no custom syntax involved, and you can use arbitrary property names,
> including all the counter examples mentioned by Thomas, and even
> expressions like childNodes[i+1].

Starting a statement that way isn't "not as nice" it is a failure of the
code to express its intent. The try statement misleads the reader. Why
is it there? Can anyone know? You could put a comment:

// Use try catch in case body.firstChild does not have a style property.


try { var color = body.firstChild.style.backgroundColor; } catch(e) {}

That's worse, because now the code comment has to explain the failure of
the code to explain itself -- and for something so trivial and basic as
getting a simple property.

Promoting the idea of try-catch for everything, as Google does, putting
FunctionDeclaration where only statement may appear is the next obvious
mistake, as Google does.

Someone may also mention that using try/catch is inefficient, and it is,
but that is the least of the problems.

Thomas 'PointedEars' Lahn

unread,
May 12, 2010, 3:58:28 PM5/12/10
to
Matt Kruse wrote:

> Thomas 'PointedEars' Lahn wrote:
>> So property names containing `/' and `#' could not be accessed then, i.e.
>> neither $prop(obj, 'property/.property./[prop#/erty]', '/')
>> nor $prop(obj, 'property#.property.#[prop#/erty]', '#')
>> could access e.g.
>> obj["property#"][".prop/erty."]["#[prop#/erty]"]
>
> Are you missing the basic point that you PICK the delimiter based on
> the string you are passing in?

No, you are missing the point that this requires the caller to determine the
delimiter, i.e. parse the argument themselves, and the callee to parse it
again, when that is not necessary otherwise.


PointedEars
--
Danny Goodman's books are out of date and teach practices that are
positively harmful for cross-browser scripting.
-- Richard Cornford, cljs, <cife6q$253$1$8300...@news.demon.co.uk> (2004)

Garrett Smith

unread,
May 12, 2010, 4:10:08 PM5/12/10
to
Thomas 'PointedEars' Lahn wrote:
> Scott Sauyet wrote:
>
>> Thomas 'PointedEars' Lahn wrote:
>>> [...]
>>> But all of this is completely unnecessary if you let the programming
>>> language provide the delimiter, i.e. arguments, Arrays, or a combination
>>> thereof.
>> It's not that I disagree. But I think your arguments are overstated.
>> If Matt is going to publish this and promote it as an amazing tool
>> that will drastically increase the productivity of any web developer,
>> then he really should skip the string parsing and go with the more
>> complete API. But if he is going to use this on a few projects with a
>> half-dozen other coders, I would suggest that simplicity should rule.
>
> And exactly therefore string parsing is a really bad idea here, for it
> *complicates* matters *needlessly*.

Yep. Matt's is needlessly complex and burdens the caller with dealing
with the delimiter.

deepMatt(obj, "p1.p2", ".");
deepAsen(obj, ["p1", "p2"]);

Both create an array.

`deepMatt`
- parses the string, splitting on delimiter
- requires caller to supply delimiter as a third argument.
- can fail with unknown property name (which may contain delimiter).

`deepAsen`
- requires caller to supply an array.

One benefit for Matt's is that it looks more like a normal property
access when only "." is used.

The deepAsen function is simpler and easier to use. This is a big
advantage over deepMatt. Having the flexibility of dynamic property name
might be an advantage in some cases, such as seen with square-bracket
property accessors, so that might be another benefit realized later.

VK

unread,
May 12, 2010, 4:30:59 PM5/12/10
to
On May 11, 7:52 pm, Matt Kruse <m...@thekrusefamily.com> wrote:
> > Does anyone here use a general convenience method for deep property
> > access that will not throw an error if any property along the chain is
> > undefined?

And what is wrong with throwing errors if they are properly caught and
handled?

try {
prop = window.document.foo.bar;
}
catch (e) {
/* NOP */
}

I assume NN4/IE4 issue is not an issue anymore.

It can be also used "Guard AND" as Crockford calls it. It is much
longer but fully reliable as well:

prop = (window && window.document &&
window.document.foo && window.document.foo.bar);

I am using the first, you may use either one.

There are also situations when a property exists but named differently
in different UAs, like "innerText" (IE) and "textContent" (many
others). Here bracket property access comes handy, i.e.:

var text = (/*@cc_on true || @*/ false) ? 'innerText' : 'textContent';
// ...
var t = document.getElementById('elm')[text];

A very particular case is document.all collection in Firefox. It is
always undefined, but in quirk (backCompat) mode it does exists and
can be used just like in IE, so

if (document.all) { // always false
}

but

if (document.compatMode == 'BackCompat') {
var foo = document.all.SomeElement;
// will be fine
}

Obviously in this case the "guard AND" will not do the trick, try-
catch is always reliable. The issue has a very little practical
importance, just to mention for the completeness.

Stefan Weiss

unread,
May 12, 2010, 4:34:07 PM5/12/10
to
On 12/05/10 21:57, Garrett Smith wrote:
> Stefan Weiss wrote:
>> On 11/05/10 15:44, Matt Kruse wrote:
>>> Does anyone here use a general convenience method for deep property
>
> [...]
>
>> This may be obvious, but did you consider simply catching and ignoring
>> the ReferenceError?
>>
>> try { var color = body.firstChild.style.backgroundColor; } catch(e) {}
>>
>> Maybe it doesn't look as nice as your deep() call, but at least there's
>> no custom syntax involved, and you can use arbitrary property names,
>> including all the counter examples mentioned by Thomas, and even
>> expressions like childNodes[i+1].
>
> Starting a statement that way isn't "not as nice" it is a failure of the
> code to express its intent. The try statement misleads the reader. Why
> is it there? Can anyone know?

Anyone who knows what the code they're reading is supposed to do should
have a pretty good idea. I agree that it's not pretty, but it becomes
more obvious if you write it like this:

try {
var color = body.firstChild.style.backgroundColor;
} catch (e) {

color = someDefaultValue;
}

I don't think I'd need any additional explanations when I read this,
except in unusual situations, and those should always be commented.
Anyway, you can always write

if (body
&& body.firstChild
&& body.firstChild.style
&& body.firstChild.style.backgroundColor)
{
var color = body.firstChild.style.backgroundColor;
} else {
color = someDefaultValue;
}

if you think that's more readable. To each their own.

> Promoting the idea of try-catch for everything, as Google does, putting
> FunctionDeclaration where only statement may appear is the next obvious
> mistake, as Google does.

I'm not Google.

> Someone may also mention that using try/catch is inefficient, and it is,
> but that is the least of the problems.

Especially when you're afraid to use it because you think it *might* be
slower than a function like $prop, but don't bother testing it first.

In Firefox 3.0, try/catch is 3-4 times faster than $prop, in IE 6 and IE
7 it's about 7 times faster, it's about the same speed in Opera 9.64,
and over 10 times faster in Opera 10.53. I didn't bother with the other
browsers because the notion that try/catch is always inefficient
compared to the $prop function is obviously not correct.


____________________________________

// using Matt's tests

var json = {
'a':'1'
,'b': ['x','y','z']
,'c': {
'array':['1','2','3']
,'property':'prop!'
}
};

JSLitmus.test('prop', function (count) {
while (count--) {
var a = $prop(json, "a");
var b = $prop(json, "b[1]");
var c = $prop(json, "c.array[2]");
var d = $prop(json, "d.e.f.g");
//check(a, b, c, d);
}
});

JSLitmus.test('try', function (count) {
while (count--) {
try { var a = json.a; } catch (e) {}
try { var b = json.b[1]; } catch (e) {}
try { var c = json.c.array[2]; } catch (e) {}
try { var d = json.d.e.f.g; } catch (e) {}
//check(a, b, c, d);
}
});

function check (a, b, c, d) {
if (a !== "1" || b !== "y" || c !== "3" || d !== undefined) {
throw new Error("whoops");
}
}


--
stefan

Thomas 'PointedEars' Lahn

unread,
May 12, 2010, 5:03:29 PM5/12/10
to
Stefan Weiss wrote:

That would imply that you would need to use try-catch block for each single
property access. And you could still not know for sure what it was that
threw the exception. You really don't want to do that.

> Anyway, you can always write
>
> if (body
> && body.firstChild
> && body.firstChild.style
> && body.firstChild.style.backgroundColor)
> {
> var color = body.firstChild.style.backgroundColor;
> } else {
> color = someDefaultValue;
> }
>
> if you think that's more readable. To each their own.

You miss the point. The purpose of a property-accessor function is to avoid
those maintenance-hardening Guard-ANDs and to make code more readable:

if (isFeature(body, "firstChild", "style", "backgroundColor"))


{
var color = body.firstChild.style.backgroundColor;
} else {
color = someDefaultValue;
}

or even

var color = getProperty(body, "firstChild", "style", "backgroundColor")
|| someDefaultValue;



>> Promoting the idea of try-catch for everything, as Google does, putting
>> FunctionDeclaration where only statement may appear is the next obvious
>> mistake, as Google does.
>
> I'm not Google.

But you seem to think like them.



>> Someone may also mention that using try/catch is inefficient, and it is,
>> but that is the least of the problems.
>
> Especially when you're afraid to use it because you think it *might* be
> slower than a function like $prop, but don't bother testing it first.
>
> In Firefox 3.0, try/catch is 3-4 times faster than $prop,

Depends on what $prop() is. As posted, it is unnecessarily inefficient.

> JSLitmus.test('prop', function (count) {

Don't get me started on that.

Stefan Weiss

unread,
May 12, 2010, 5:56:26 PM5/12/10
to
On 12/05/10 23:03, Thomas 'PointedEars' Lahn wrote:

> Stefan Weiss wrote:
>> try {
>> var color = body.firstChild.style.backgroundColor;
>> } catch (e) {
>> color = someDefaultValue;
>> }
>>
>> I don't think I'd need any additional explanations when I read this,
>> except in unusual situations, and those should always be commented.
>
> That would imply that you would need to use try-catch block for each single
> property access.

That's correct.

> And you could still not know for sure what it was that
> threw the exception. You really don't want to do that.

I might, if I'm not interested in the details of any exceptions this
might throw. I will get my property value or my default value; that's
what counts. YMMV.

Anyway, I don't use try/catch here myself at all, I only suggested it as
a possible alternative to deep() / $prop(). The cases where I want to
access some deeply nested property whose parents may not exists just
don't come up very often. I usually know what's there to read, because
I'm usually involved in creating the HTML/XML/JSON/etc tree structure.
In the rare cases when I'm not, I use the guard-AND form mentioned below.

> You miss the point. The purpose of a property-accessor function is to avoid
> those maintenance-hardening Guard-ANDs and to make code more readable:
>
> if (isFeature(body, "firstChild", "style", "backgroundColor"))
> {
> var color = body.firstChild.style.backgroundColor;
> } else {
> color = someDefaultValue;
> }
>
> or even
>
> var color = getProperty(body, "firstChild", "style", "backgroundColor")
> || someDefaultValue;

Looks good to me. I definitively like it a lot better than parsing a
"string.of.property.names". As for readability... your version requires
the reader to know what two vaguely named functions do, whereas
try/catch only uses standard JS features that should be familiar to
everybody.

If this works for you, great. I just don't need it often enough to add
functions like deep() or getProperty().

>> I'm not Google.
>
> But you seem to think like them.

You are wrong about that. Please don't make assumptions about how I
think. If you absolutely have to, please keep them to yourself.

>> In Firefox 3.0, try/catch is 3-4 times faster than $prop,
>
> Depends on what $prop() is.

The definition of $prop() was posted in this thread.

> As posted, it is unnecessarily inefficient.

True. An array- or arguments-based approach will be faster as well as safer.

>> JSLitmus.test('prop', function (count) {
>
> Don't get me started on that.

It's just a litmus test, not an exact measurement. It's sufficient to
get a general idea. If you doubt the results, you can easily verify them
without JSLitmus. But yeah, I don't really want to start about JSLitmus
either; it's been discussed before.


--
stefan

Dr J R Stockton

unread,
May 12, 2010, 2:25:12 PM5/12/10
to
In comp.lang.javascript message <083890c5-1c81-48db-ac47-adced2d307e8@b2
1g2000vbh.googlegroups.com>, Tue, 11 May 2010 06:44:35, Matt Kruse
<ma...@thekrusefamily.com> posted:

>Does anyone here use a general convenience method for deep property

>access that will not throw an error if any property along the chain is
>undefined?
>

>For example:
>
>deep(document, "body.firstChild.style.backgroundColor");


Something on the general lines of this might resemble the answer to what
seems to be your question ; a little rearrangement could eliminate the
expectation that the first part exists. UNTESTED.

function deep(T, A) { var B = A.split("."), J = 0, U
while (J < B.length) if ( ( T = T[ B[J++] ] ) == U ) break
return T }

--
(c) John Stockton, near London. *@merlyn.demon.co.uk/?.?.Stockton@physics.org
Web <URL:http://www.merlyn.demon.co.uk/> - FAQish topics, acronyms, & links.
Correct <= 4-line sig. separator as above, a line precisely "-- " (RFC5536/7)
Do not Mail News to me. Before a reply, quote with ">" or "> " (RFC5536/7)

Garrett Smith

unread,
May 12, 2010, 7:00:31 PM5/12/10
to
Stefan Weiss wrote:
> On 12/05/10 21:57, Garrett Smith wrote:
>> Stefan Weiss wrote:
>>> On 11/05/10 15:44, Matt Kruse wrote:
>>>> Does anyone here use a general convenience method for deep property
>> [...]
>>
>>> This may be obvious, but did you consider simply catching and ignoring
>>> the ReferenceError?
>>>
>>> try { var color = body.firstChild.style.backgroundColor; } catch(e) {}
>>>
>>> Maybe it doesn't look as nice as your deep() call, but at least there's
>>> no custom syntax involved, and you can use arbitrary property names,
>>> including all the counter examples mentioned by Thomas, and even
>>> expressions like childNodes[i+1].
>> Starting a statement that way isn't "not as nice" it is a failure of the
>> code to express its intent. The try statement misleads the reader. Why
>> is it there? Can anyone know?
>
> Anyone who knows what the code they're reading is supposed to do should
> have a pretty good idea. I agree that it's not pretty, but it becomes
> more obvious if you write it like this:
>
> try {
> var color = body.firstChild.style.backgroundColor;
> } catch (e) {
> color = someDefaultValue;
> }
>

What the code tries to do is apparent; why it needs to try is not. Was
body.firstChild throwing errors? Which errors? And which browsers?

A reason for adding try catch is to handle an error that the code does
not have control over. It might be a host object related issue or it
could be that the caller passed in a function, where calling that
function may result in an error that could be handled by the program,
rather than terminating it.

In this case, the only known error was caused by the code itself, and so
not doing that would seem like a much more obvious choice.

The other thing I don't like about that construct is that the color
variable is declared inside the try. We know it is is going to be
hoisted to the VO and used either there.

var color;


try {
var color = body.firstChild.style.backgroundColor;
} catch (e) {
color = someDefaultValue;
}

If the try catch were really justified, and it isn't, it could be moved
to a separate function making the code a lot easier to understand as:

var color = getColor();

> I don't think I'd need any additional explanations when I read this,
> except in unusual situations, and those should always be commented.
> Anyway, you can always write
>
> if (body
> && body.firstChild
> && body.firstChild.style
> && body.firstChild.style.backgroundColor)
> {

Plain as day.

> var color = body.firstChild.style.backgroundColor;
> } else {
> color = someDefaultValue;
> }
>
> if you think that's more readable. To each their own.
>

Property existence checks like that are self documenting.

Try catch is not. There is no obvious reason why the try catch is there,
only. It appears to be used to catch an error but what sort of error?
Who can know, but looking at the code? Not including the author.

[...]

>> Someone may also mention that using try/catch is inefficient, and it is,
>> but that is the least of the problems.
>
> Especially when you're afraid to use it because you think it *might* be
> slower than a function like $prop, but don't bother testing it first.
>
> In Firefox 3.0, try/catch is 3-4 times faster than $prop, in IE 6 and IE
> 7 it's about 7 times faster, it's about the same speed in Opera 9.64,
> and over 10 times faster in Opera 10.53. I didn't bother with the other
> browsers because the notion that try/catch is always inefficient
> compared to the $prop function is obviously not correct.
>

I considering try/catch vs property existence check.

What if there was a way to do it in native code?

var prop = document[?"body"][?"style"]["color"] || "green";

David Mark

unread,
May 12, 2010, 7:33:41 PM5/12/10
to
Scott Sauyet wrote:
> David Mark wrote:

>> Matt Kruse wrote:
>>> Thomas 'PointedEars' Lahn wrote:
>>>> Matt Kruse wrote:
>>>>> Thomas 'PointedEars' Lahn wrote:
>>>>>>> I'm not building this for idiots!
>>>>>> ISTM you are not building this for people who do DOM scripting either.
>>>>>> <form>...<input name="foo[]">...</form>
>>>>> This already works fine:
>>>>> $prop(document, "forms[0].foo[].value")
>>>>> for example.
>>>> You miss the point.
>>> On the contrary, you fail to make one.
>> No, as usual, you waste endless amounts of time "debating" when you
>> could be working. How do you ever get anything done?
>
> David,
>
> Matt, who has spend far less time debating here in recent months than
> either your or I, came here asking for discussion on an API he was
> designing. He has certainly gotten that. He has, unsurprisingly,
> been defending the decisions he's made, but he has not shown any signs
> of being unwilling to listen to criticism. His only sign of testiness
> was in his response to Thomas' bald assertion, "You miss the point."

Yes, thanks for the play-by-play. :)

>
> Thomas has made some positive contributions to this thread. That post
> was not among them, and I don't fault Matt for responding in a like
> manner.

Who cares?

> Your only contribution of substance was another bald
> assertion that his single-string API is a design mistake.

Another? I only made one post of that sort.

> You didn't
> justify it at all.

It had already been discussed _to death_. Hence my post.

> While I agree with you, based upon my own
> experience with a similar API built some years back, your only posts
> in this thread have been argumentative and not at all constructive.

You don't seem to realize that my post came after yours (and others who
recommended the same thing). I was agreeing with you (not the other way
around). And there was no need to revisit everything that had led up to
it, was there?

>
> It seems to me that it's you who's wasting time here.

No, now it is you that is perpetuating the futility of this discussion.
God knows, I tried to head it off.

>
> (And now me too. Damn!)

That's the first sensible thing you said. ;)

David Mark

unread,
May 12, 2010, 7:49:30 PM5/12/10
to
Scott Sauyet wrote:
> Matt Kruse <m...@thekrusefamily.com> wrote:
>> I could modify it to take any number of arguments, to support both
>> ways of accessing the properties - either as a single string with no .
>> in it, or as multiple strings with no limitations.
>
> I would suggest you don't. Make your API as clean as possible while
> still meeting your requirements and then live with whatever
> restrictions that entails. Of all the critiques of jQuery I've seen
> here, by far the most compelling is against the re-use of "$" to mean
> so many different things.

Not to mention its inability to read/write/remove attributes straight,
which is akin to a calculator that can't add/subtract straight. Then
there is the broken query engine. I sometimes wonder if people see the
results of my tests as some sort of inconvenient mirage? They
demonstrate zero consistency (over the course of years) between library
versions, as well as browser versions. Not to mention that they slapped
QSA on top of their old mess, knowing that it would do lots of things
right that the old stuff did wrong. So you get applications that appear
to work in the very latest desktop browsers, but fail completely in
everything else. No wonder jQuery developers refuse to test their
creations in anything but the latest desktop browsers. ;)

The "$" thing is only notable in that they foolishly chose the one (out
of about six billion) variable names that was known to be used by
similar scripts (e.g. Prototype). And yes, they use it for different
purposes.

Or perhaps you mean the awkward metaphor of treating everything as a
collection. That's certainly the sign of an ill-fitting API. Every
single thing is not multiple things. It's even awkward trying to
explain its awkwardness. :)

Scott Sauyet

unread,
May 13, 2010, 2:22:52 PM5/13/10
to
David Mark wrote:

> Scott Sauyet wrote:
>> Of all the critiques of jQuery I've seen
>> here, by far the most compelling is against the re-use of "$" to mean
>> so many different things.
>
> Not to mention its inability to read/write/remove attributes straight,

No, I've read your comments on that ad infinitum. While you are
probably right, it's not something that bothers me nearly as much as
it seems to bother you.


> The "$" thing is only notable in that they foolishly chose the one (out
> of about six billion) variable names that was known to be used by
> similar scripts (e.g. Prototype).  And yes, they use it for different
> purposes.

As a new library, they did not have to be bound by the conventions the
Prototype used. Granted, their use makes it somewhat more difficult
to move between these libraries, but that's at most a minor issue.
The symbol is not the issue. I have the same problem with the
'jquery' function for which '$' is an alias.


> Or perhaps you mean the awkward metaphor of treating everything as a
> collection.  That's certainly the sign of an ill-fitting API. Every
> single thing is not multiple things.  It's even awkward trying to
> explain its awkwardness.  :)

No, I actually think they got this right. Acting on a group, whether
it contains one element, no elements, or many elements, is to me very
useful. And it still works as an array if you want the underlying DOM
elements instead.

No, my problem is with the different meaning that $/jQuery takes on
depending upon the parameters supplied.

This is from their documentation:

1. jQuery( selector, [ context ] )
2. jQuery( element )
3. jQuery( elementArray )
4. jQuery( jQuery object )
5. jQuery()
6. jQuery( html, [ ownerDocument ] )
7. jQuery( html, props )
8. jQuery( callback )


The first five essentially create jQuery wrappers around existing DOM
elements. The next two create new DOM elements from scratch and wrap
them in a jQuery wrapper. The final one runs a function when the DOM
is ready.

That's two things too many that this one function should try to do.

That's the issue I object to.

-- Scott

Thomas 'PointedEars' Lahn

unread,
May 13, 2010, 2:56:11 PM5/13/10
to
Scott Sauyet wrote:

> David Mark wrote:
>> Scott Sauyet wrote:
>>> Of all the critiques of jQuery I've seen
>>> here, by far the most compelling is against the re-use of "$" to mean
>>> so many different things.
>> Not to mention its inability to read/write/remove attributes straight,
>
> No, I've read your comments on that ad infinitum. While you are
> probably right, it's not something that bothers me nearly as much as
> it seems to bother you.

That method is being referred six times in jquery-1.4.2.js, including in the
pivotal jQuery() function, and used extensively by so-called jQuery plugins.
So it really should bother you a little bit that it does not work properly,
if at all (there are faulty feature tests and inferences everywhere, earlier
versions had browser sniffing added on top of that).

Scott Sauyet

unread,
May 13, 2010, 3:34:10 PM5/13/10
to
Thomas 'PointedEars' Lahn wrote:
> Scott Sauyet wrote:
>> [ ... ] I think your arguments are overstated.

>> If Matt is going to publish this and promote it as an amazing tool
>> that will drastically increase the productivity of any web developer,
>> then he really should skip the string parsing and go with the more
>> complete API.  But if he is going to use this on a few projects with a
>> half-dozen other coders, I would suggest that simplicity should rule.
>
> And exactly therefore string parsing is a really bad idea here, for it
> *complicates* matters *needlessly*.  It requires the caller to think hard
> about what delimiter can be used, in fact it requires them to parse the
> argument by *themselves*, instead of just passing the arguments and let the
> function do all the work.  I fail to see why it should be simpler to call
>
>   $prop(obj, 'prop/erty..prop#erty..[prop|erty]')
> [ ... ]

> So please forgive me if I really fail to see that kind of simplicity you are
> talking about with the string-parsing approach.

I think you're setting up a straw man here. Considering that when I
did my equivalent, I only once found the need for a delimiter other
than the default ".", I'd be surprised if others have so many such
strange strings used to identify data in their objects.

If almost all the cases you have look like:

$prop(obj, "path.to.property")

or

$prop(obj, "longer.path.with.some[0].brackets.included");

and it's only the rarest time when you need

$prop(obj, "geo|lat38.900318|long-77.036562, "|");

then this syntax seems much cleaner than

$prop(obj, "path", "to", "property")

or

$prop(obj, ["path", "to", "property"])

Of course _de gustibus non disputandum est_, but that's my take.

And I still suggest that if he wants to handle DOM elements that might
have brackets in their ids or the more complicated cases I mentioned,
that he does go with the multiple strings. But it's not that the
alternative choice is so bad.

-- Scott

Thomas 'PointedEars' Lahn

unread,
May 13, 2010, 4:41:14 PM5/13/10
to
Scott Sauyet wrote:

> Thomas 'PointedEars' Lahn wrote:
>> Scott Sauyet wrote:
>>> [ ... ] I think your arguments are overstated.
>>> If Matt is going to publish this and promote it as an amazing tool
>>> that will drastically increase the productivity of any web developer,
>>> then he really should skip the string parsing and go with the more
>>> complete API. But if he is going to use this on a few projects with a
>>> half-dozen other coders, I would suggest that simplicity should rule.
>>
>> And exactly therefore string parsing is a really bad idea here, for it
>> *complicates* matters *needlessly*. It requires the caller to think hard
>> about what delimiter can be used, in fact it requires them to parse the
>> argument by *themselves*, instead of just passing the arguments and let
>> the function do all the work. I fail to see why it should be simpler to
>> call
>>
>> $prop(obj, 'prop/erty..prop#erty..[prop|erty]')
>> [ ... ]
>> So please forgive me if I really fail to see that kind of simplicity you
>> are talking about with the string-parsing approach.
>

> I think you're setting up a straw man here. [...]

I think you don't know what that is.

> If almost all the cases you have look like:
>
> $prop(obj, "path.to.property")
>
> or
>
> $prop(obj, "longer.path.with.some[0].brackets.included");

So, is `some' the property name or is it `some[0]', which is entirely
possible and realistic with DOM scripting?



> and it's only the rarest time when you need
>
> $prop(obj, "geo|lat38.900318|long-77.036562, "|");
>
> then this syntax seems much cleaner than
>
> $prop(obj, "path", "to", "property")
>
> or
>
> $prop(obj, ["path", "to", "property"])
>
> Of course _de gustibus non disputandum est_, but that's my take.

As has been pointed out already, it is not just a matter of taste, but of
code quality, of efficiency and reusability. You will have quite a hard
time using variable property accesses with string parsing. You will also
be unable to simply copy-paste calls if any new call contains the previous
delimiter in a property name.

You will not have those issues with separate arguments or array elements
because you do not have to care about delimiters; you will not have to split
the string before, you will not have to parse anything, and you will not
have to create a number of extra objects in the process.

Scott Sauyet

unread,
May 13, 2010, 5:07:15 PM5/13/10
to
Thomas 'PointedEars' Lahn wrote:
> Scott Sauyet wrote:
>> Thomas 'PointedEars' Lahn wrote:

>>> $prop(obj, 'prop/erty..prop#erty..[prop|erty]')
>>> [ ... ]
>>> So please forgive me if I really fail to see that kind of simplicity you
>>> are talking about with the string-parsing approach.
>
>> I think you're setting up a straw man here. [...]
>
> I think you don't know what that is.

I do. I simply refuse to believe you're ridiculous enough to think
that the example above is a reasonable use of this sort of convenience
API. If you really do, then you're right, it's not a straw man, it's
plain idiocy.

-- Scott

David Mark

unread,
May 13, 2010, 6:43:28 PM5/13/10
to
Thomas 'PointedEars' Lahn wrote:
> Scott Sauyet wrote:
>
>> David Mark wrote:
>>> Scott Sauyet wrote:
>>>> Of all the critiques of jQuery I've seen
>>>> here, by far the most compelling is against the re-use of "$" to mean
>>>> so many different things.
>>> Not to mention its inability to read/write/remove attributes straight,
>> No, I've read your comments on that ad infinitum. While you are
>> probably right, it's not something that bothers me nearly as much as
>> it seems to bother you.
>
> That method is being referred six times in jquery-1.4.2.js, including in the
> pivotal jQuery() function, and used extensively by so-called jQuery plugins.
> So it really should bother you a little bit that it does not work properly,
> if at all (there are faulty feature tests and inferences everywhere, earlier
> versions had browser sniffing added on top of that).
>
>

Exactly. I can't imagine where the "probably" qualification came from.
Demonstrably right would seem to be more appropriate. The SlickSpeed
tests demonstrate that the queries have been an ever-shifting and
inaccurate mess for years as well. It's like new readers don't believe
their eyes and those who have been here for more than one cycle of
criticism complain that they've already seen it. Probably?! I say
definitely (for anyone with a brain). An exception would be those
apologists that see the ever-changing array of errors and miscounts as a
checklist of things they don't "care" about. Of course, they likely
didn't know they existed before I demonstrated the issues, so I wonder
how they decided on that stance. :) It's more like they are defending
past assertions that have been clearly proven wrong (e.g. jQuery doesn't
sniff browsers, jQuery isn't full of mistakes, jQuery isn't bad code,
etc., etc.)

Then there are those who see jQuery and the rest as some sort of single
connected entity called "open source". In other words, any criticism of
any of them is evil as so many people have put in so many hours for so
little... I don't know what those people are thinking either. The
jQuery bunch (for one) exist to sell dubious books. They aren't helping
anything with their incompetent coding and wrongheaded blog entries.
How could they be?

Thomas 'PointedEars' Lahn

unread,
May 13, 2010, 7:32:56 PM5/13/10
to
Scott Sauyet wrote:

You miss the point. The example was chosen because it points out the
inherent flaw of this approach. You can create a better, IYHO less idiotic,
example to demonstrate the issue. Neither changes the fact that this issue
exists and that it creates a problem and complexity in the field in which it
is supposed to be used, and which it is supposed to simplify.

A helper function that by design makes it hard for it to be reused, that
makes code less legible and less reliable than if it was not used, a
function that is not generally applicable, is not a goal to be attained.

Scott Sauyet

unread,
May 14, 2010, 11:16:20 AM5/14/10
to
Thomas 'PointedEars' Lahn wrote:
> A helper function that by design makes it hard for it to be reused, that
> makes code less legible and less reliable than if it was not used, a
> function that is not generally applicable, is not a goal to be attained.

I can buy this: "A helper function that by design makes it hard for


it to be reused, that makes code less legible and less reliable than

if it was not used, is not a goal to be attained." But I'm not buying
your "generally applicable" clause. Code needs to have an reasonable
domain. It should be clear as to what it accepts and handle errors
consistently, but it does not have to be able to give reasonable
results for unreasonable input. Defining what is and is not
reasonable is a large part of designing an API.


But I find myself in an odd position here. I'm defending something I
don't really support, only to say that the problems aren't as bad as
stated. I think that Matt probably should use a multiple-string API,
with the main reason being the sort of problems many of us have
pointed out, but may best be seen in your response to one of my code
snippets:

|> $prop(obj, "longer.path.with.some[0].brackets.included");
| So, is `some' the property name or is it `some[0]', which is
entirely
| possible and realistic with DOM scripting?

Matt made it clear that he wants to use his function for searching DOM
nodes. Simply because of that, I find it reasonable to complicate the
API with multiple strings.


But still I see issues. The technique I used when I did this was to
search first using the entire string ("some[0]") for a property name,
and if that wasn't found to try "some", then 0 on the results. It
worked and it never turned around and bit us. But I was never happy
with it. When we found this need (when we switched server framework
and now had to deal with brackets as attribute values) we were already
invested in the single-string API. We never did have to introduce a
delimiter, but we did have a slightly more complex API that allows
brackets to contain additional hierarchies:

$prop(obj, "prop1.prop2[current.left.size].color");

I suppose the way to do that with the multiple string array would be
something like this:

$prop(obj, "prop1", "prop2", $prop(current, "left", "size"),
"color");

But that clearly is neither as convenient nor as legible as the
original. So again I want to argue both sides of this issue. I think
I'd better just stop here! :-)

--
Scott

Thomas 'PointedEars' Lahn

unread,
May 14, 2010, 4:46:46 PM5/14/10
to
Scott Sauyet wrote:

> Thomas 'PointedEars' Lahn wrote:
>> A helper function that by design makes it hard for it to be reused, that
>> makes code less legible and less reliable than if it was not used, a
>> function that is not generally applicable, is not a goal to be attained.
>
> I can buy this: "A helper function that by design makes it hard for
> it to be reused, that makes code less legible and less reliable than
> if it was not used, is not a goal to be attained." But I'm not buying
> your "generally applicable" clause.

Perhaps you are misunderstanding, then.

> Code needs to have an reasonable domain.

The domain is property access.

> It should be clear as to what it accepts and handle errors
> consistently, but it does not have to be able to give reasonable
> results for unreasonable input. Defining what is and is not
> reasonable is a large part of designing an API.

Property names that contain what property names may contain are not
unreasonable input.

> But I find myself in an odd position here. I'm defending something I
> don't really support, only to say that the problems aren't as bad as
> stated.

Without giving a good reason for your opinion that they are not, so you
should ask yourself if you are trying to defend something that is worth
defending.

nick

unread,
May 14, 2010, 8:30:48 PM5/14/10
to
On May 12, 3:57 pm, Garrett Smith <dhtmlkitc...@gmail.com> wrote:
> Stefan Weiss wrote:

> > This may be obvious, but did you consider simply catching and ignoring
> > the ReferenceError?

> >   try { var color = body.firstChild.style.backgroundColor; } catch(e) {}

This seems like the most obvious way to do it.

> Starting a statement that way isn't "not as nice" it is a failure of the
> code to express its intent. The try statement misleads the reader.

True, it would be nice if we could wrap it in a function.

> Someone may also mention that using try/catch is inefficient, and it is,
> but that is the least of the problems.

It's probably at least as efficient as executing a bunch of other code
to get around it as in the OP...

Matt, I've been using a build script and putting C++ preprocessor
directives in my js source to keep things manageable (initially just
for includes and ifdefs). I've been playing with a header file
containing some function macros; they can be useful for inlining and
doing things you can't do with normal functions (like pass in a non-
existing variable). "Error-free deep property access" might make a
good candidate for that header file:

#define CAN_ACCESS(v) \
(function(){ \
try{void(v); return true;} \
catch(e){return false;}})();

You can use it in your source something like this:

if (CAN_ACCESS(document.forms[2]))
document.forms[2].submit();
else
notifyUser("Swing and a miss.");

...And it will expand to... well, something fairly ugly. But, your
source code is still plenty readable, and you have less code to
support :)

David Mark

unread,
May 14, 2010, 9:20:33 PM5/14/10
to
nick wrote:
> On May 12, 3:57 pm, Garrett Smith <dhtmlkitc...@gmail.com> wrote:
>> Stefan Weiss wrote:
>
>>> This may be obvious, but did you consider simply catching and ignoring
>>> the ReferenceError?
>
>>> try { var color = body.firstChild.style.backgroundColor; } catch(e) {}
>
> This seems like the most obvious way to do it.

The trouble is that it is ham-fisted. You will have no idea why the
exception is thrown, so the pattern has very limited potential in
anything but the simplest of contexts.

Scott Sauyet

unread,
May 14, 2010, 9:57:10 PM5/14/10
to
Thomas 'PointedEars' Lahn wrote:
> Scott Sauyet wrote:
>> Thomas 'PointedEars' Lahn wrote:
>>> A helper function that by design makes it hard for it to be reused, that
>>> makes code less legible and less reliable than if it was not used, a
>>> function that is not generally applicable, is not a goal to be attained.
>
>> I can buy this:  "A helper function that by design makes it hard for
>> it to be reused, that makes code less legible and less reliable than
>> if it was not used, is not a goal to be attained."  But I'm not buying
>> your "generally applicable" clause.
>
> Perhaps you are misunderstanding, then.

Maybe, but I think it's more that I disagree.


>> Code needs to have an reasonable domain.
>
> The domain is property access.

Not to my mind. And perhaps that is the crux of the matter. The
language already has '[]' for property access, and a shortcut for some
simpler cases: '.'. I have little need to use a function that has the
same domain as those language constructs.

The reason I created my version -- and I really wish I still had it
available -- was that doing all the error checking on something that
would otherwise be very simple made the source code much harder to
read. The goal of the function was to make the source code simpler to
read without actually sacrificing safety.

So the domain was limited to replacing the sorts of source code that I
would like to use except that it wasn't safe, something like

obj.prop1.[key1.prop2.prop3].prop4

with a similar looking construct that gained the required safety.
Part of the goal of my code was the very similarity to the desired
source code above. If I remember correctly, unlike Matt, I didn't
separate out the initial object, so mine looked something like

fetch('obj.prop1[key1.prop2.prop3].prop4');

The whole point of mine was to make it look like as much as possible
like the desired source code.


>> It should be clear as to what it accepts and handle errors
>> consistently, but it does not have to be able to give reasonable
>> results for unreasonable input.  Defining what is and is not
>> reasonable is a large part of designing an API.
>
> Property names that contain what property names may contain are not
> unreasonable input.

So are you saying that all functions should be written to work
seamlessly with any values of their parameters that the language might
allow? Or are we allowed to write functions whose behavior is only
well-defined for some specified subset of the allowed values? I've
have always believed the latter. Do you really believe the former?
That's got to be hard to do in a loosely typed language.


>> But I find myself in an odd position here.  I'm defending something I
>> don't really support, only to say that the problems aren't as bad as
>> stated.
>
> Without giving a good reason for your opinion that they are not, so you
> should ask yourself if you are trying to defend something that is worth
> defending.

My code was not originally intended to work with DOM nodes. The data
structures I used were built in other JS code, and I'm quite certain
they never contained property names that wouldn't be allowed as an
identifier. When I had to support "[]" as well, it was not a hard
extension. Had my requirements grown further, I might have had to
abandon some of the initial simplicity. But I wouldn't do so unless
circumstances forced it on me. The overriding goal was to simplify my
code and make it more readable.

It's easy enough to defend the decisions I made. But Matt seems to
have somewhat different requirements, and I don't think my approach
would suit those requirements as well. I have stated the reasons for
both sides of this argument several times. I think the categorical
statements that string parsing is wrong here are overblown. But if I
were writing the code for him under my understanding of his
requirements, I probably would use the multiple parameter approach.
For my own requirements, I think string parsing is clearly better.
It's all about the simplicity of the API.

--
Scott

Thomas 'PointedEars' Lahn

unread,
May 15, 2010, 11:45:04 AM5/15/10
to
Scott Sauyet wrote:

> Thomas 'PointedEars' Lahn wrote:
>> Scott Sauyet wrote:
>>> Thomas 'PointedEars' Lahn wrote:
>>>> A helper function that by design makes it hard for it to be reused,
>>>> that makes code less legible and less reliable than if it was not used,
>>>> a function that is not generally applicable, is not a goal to be
>>>> attained.
>>> I can buy this: "A helper function that by design makes it hard for
>>> it to be reused, that makes code less legible and less reliable than
>>> if it was not used, is not a goal to be attained." But I'm not buying
>>> your "generally applicable" clause.
>> Perhaps you are misunderstanding, then.
>
> Maybe, but I think it's more that I disagree.

ISTM you do not know what you are disagreeing with.

>>> Code needs to have an reasonable domain.
>>
>> The domain is property access.
>
> Not to my mind. And perhaps that is the crux of the matter.

Yes, perhaps you do not read what you are discussing about. The whole point
of this was guarded property access. Read the Subject, for goodness' sake!

> The language already has '[]' for property access, and a shortcut for some
> simpler cases: '.'. I have little need to use a function that has the
> same domain as those language constructs.

Then you are in the wrong thread. The problem was that the property access
`foo.bar.baz' would fail if `foo.bar' did not store a value that can have
properties. As a solution, a function was suggested that does the property
access instead and returned `undefined' or `null' instead of throwing an
exception then.



>>> It should be clear as to what it accepts and handle errors
>>> consistently, but it does not have to be able to give reasonable
>>> results for unreasonable input. Defining what is and is not
>>> reasonable is a large part of designing an API.
>>
>> Property names that contain what property names may contain are not
>> unreasonable input.
>
> So are you saying that all functions should be written to work
> seamlessly with any values of their parameters that the language might

> allow? [...]

No, I am saying that such a property-accessing function should allow access
to all properties. And I am really getting tired of explaining that to you.

>>> But I find myself in an odd position here. I'm defending something I
>>> don't really support, only to say that the problems aren't as bad as
>>> stated.
>>
>> Without giving a good reason for your opinion that they are not, so you
>> should ask yourself if you are trying to defend something that is worth
>> defending.
>

> My code was not originally intended to work with DOM nodes [...]

Irrelevant.

Scott Sauyet

unread,
May 15, 2010, 12:34:03 PM5/15/10
to
Thomas 'PointedEars' Lahn wrote:
> Scott Sauyet wrote:
>> Thomas 'PointedEars' Lahn wrote:
>>> Scott Sauyet wrote:
>>>> Thomas 'PointedEars' Lahn wrote:
>>>>> A helper function that by design makes it hard for it to be reused,
>>>>> that makes code less legible and less reliable than if it was not used,
>>>>> a function that is not generally applicable, is not a goal to be
>>>>> attained.
>>>> I can buy this:  "A helper function that by design makes it hard for
>>>> it to be reused, that makes code less legible and less reliable than
>>>> if it was not used, is not a goal to be attained."  But I'm not buying
>>>> your "generally applicable" clause.
>>> Perhaps you are misunderstanding, then.
>
>> Maybe, but I think it's more that I disagree.
>
> ISTM you do not know what you are disagreeing with.

And ISTM that you are trying to solve a different problem than I am.
Matt hasn't chimed in here lately so it's not clear which approach is
closer to his needs. I've explained clearly what my goals from the
code are. You've explained what yours are. Your approach does not
meet my requirements. Obviously mine does not meet yours. This is
not a sign of misunderstanding, only of different requirements.

>>>> Code needs to have an reasonable domain.
>
>>> The domain is property access.
>
>> Not to my mind.  And perhaps that is the crux of the matter.
>
> Yes, perhaps you do not read what you are discussing about.  The whole point
> of this was guarded property access.  Read the Subject, for goodness' sake!

So the subject line in a USENET posting is supposed to be more
important than the direction of the subsequent conversation?


>> The language already has '[]' for property access, and a shortcut for some
>> simpler cases: '.'.  I have little need to use a function that has the
>> same domain as those language constructs.
>
> Then you are in the wrong thread.  The problem was that the property access
> `foo.bar.baz' would fail if `foo.bar' did not store a value that can have
> properties.  As a solution, a function was suggested that does the property
> access instead and returned `undefined' or `null' instead of throwing an
> exception then.

Right, the goal was to get the value of "foo.bar.baz" if "foo" exists
and has a property "bar", which in turn has a property "baz". But
that does not seem to be the only requirement. You would like it to
work for any legal values of property names. I would like it to be as
transparent as possible on reading the code. You're willing to
sacrifice some API simplicity for your goal. I'm willing to sacrifice
some completeness for mine.

>>>> It should be clear as to what it accepts and handle errors
>>>> consistently, but it does not have to be able to give reasonable
>>>> results for unreasonable input.  Defining what is and is not
>>>> reasonable is a large part of designing an API.
>
>>> Property names that contain what property names may contain are not
>>> unreasonable input.
>
>> So are you saying that all functions should be written to work
>> seamlessly with any values of their parameters that the language might
>> allow? [...]
>
> No, I am saying that such a property-accessing function should allow access
> to all properties.

First of all, if you disagree with my more general statement, why is
property access a special case?

Secondly, you're willing to sacrifice what is clearly a more
transparent API for that ability. For my uses, I found the simple API
more important than this completeness. The language already allows us
to check if the properties are defined. We can always write

var val = (foo && foo.bar && foo.bar.baz) ? foo.bar.baz :
defaultValue;

For me the entire reason to create such a function is that this is
easier to comprehend on reading the code:

var val = fetch("foo.bar.baz");


> And I am really getting tired of explaining that to you.

Feel free to stop any time you like.

>>>> But I find myself in an odd position here.  I'm defending something I
>>>> don't really support, only to say that the problems aren't as bad as
>>>> stated.
>
>>> Without giving a good reason for your opinion that they are not, so you
>>> should ask yourself if you are trying to defend something that is worth
>>> defending.
>
>> My code was not originally intended to work with DOM nodes [...]
>
> Irrelevant.

The requirements I had for my version of this are irrelevant, but your
fantasies of cases like this are relevant?:

| $prop(obj, 'prop/erty%.prop#erty.%[prop|erty]', '%')

Perhaps we inhabit different parts of the development world. Are you
in academia by any chance? In the business community I work in, we
write code to solve business needs. We try to keep it as simple as
possible, sacrificing simplicity for completeness only when real-world
considerations force us to. Is your experience very different?

--
Scott

Andrew Poulos

unread,
May 15, 2010, 5:33:07 PM5/15/10
to

It reads like your saying that improper, or incomplete, testing is
important for solving business needs?

Andrew Poulos

VK

unread,
May 15, 2010, 8:15:07 PM5/15/10
to
> > On 16/05/2010 2:34 AM, Scott Sauyet wrote:
> > In the business community I work in, we
> > write code to solve business needs.  We try to keep it as simple as
> > possible, sacrificing simplicity for completeness only when real-world
> > considerations force us to.  Is your experience very different?

> On May 16, 1:33 am, Andrew Poulos <ap_p...@hotmail.com> wrote:
> It reads like your saying that improper, or incomplete, testing is
> important for solving business needs?

Absolutely right. Just in a bit different wording: "In the applied
(business) programming the code is never perfect nor it is fully
AID'ed. A perfect code with the full Anti-Idiot Defense set for any
possible occasion cannot be applied for practical needs during the
lifetime of the generation that expresses these needs and willing to
pay for their satisfaction". :-) :-|

From here a simple decision to make: i) go to business and write
imperfect and potentially always failure prone code, ii) go to a
university and teach 1st-3rd grade students the Theory of Perfect
Coding. From the 4th grade and first preliminary job offers they will
loose any interest in such course so the attendance would be a
perpetual problem.

--
Real life is, to most men, a long second-best, a perpetual compromise
between the ideal and the possible.
Bertrand Russell


Scott Sauyet

unread,
May 15, 2010, 11:06:05 PM5/15/10
to

I think you need to re-read the thread, or even the section you
quoted.

I was discussing API design and the relative benefits of API
simplicity and API completeness. Thorough testing is quite important
in this environment. But it's also common to document the limited set
of values that a system can handle and not try to make it especially
graceful if values outside that range are supplied. The environment
that Thomas seems to be operating in requires that much more weight be
given to completeness; you couldn't simply document that your function
will not handle negative numbers. You would have to gracefully handle
this illegitimate input (hopefully with at least a useful warning
message!)

This is a balancing act. The simplest APIs are generally less
complete; The most complete ones are generally less simple. I'm
afraid you can't have it all.

--
Scott.

Garrett Smith

unread,
May 16, 2010, 3:02:55 AM5/16/10
to
Scott Sauyet wrote:
> Andrew Poulos wrote:
>> On 16/05/2010 2:34 AM, Scott Sauyet wrote:
>>> Thomas 'PointedEars' Lahn wrote:
>>>> Irrelevant.
>>> The requirements I had for my version of this are irrelevant, but your
>>> fantasies of cases like this are relevant?:
>>> | $prop(obj, 'prop/erty%.prop#erty.%[prop|erty]', '%')
>>> Perhaps we inhabit different parts of the development world. Are you
>>> in academia by any chance? In the business community I work in, we
>>> write code to solve business needs. We try to keep it as simple as
>>> possible, sacrificing simplicity for completeness only when real-world
>>> considerations force us to. Is your experience very different?

I do not believe that the business is in need of a property access
function. It is a programmer decision to create the abstraction which
provides little apparent value, other than convenience.

>> It reads like your saying that improper, or incomplete, testing is
>> important for solving business needs?
>
> I think you need to re-read the thread, or even the section you
> quoted.
>
> I was discussing API design and the relative benefits of API
> simplicity and API completeness. Thorough testing is quite important
> in this environment. But it's also common to document the limited set
> of values that a system can handle and not try to make it especially
> graceful if values outside that range are supplied. The environment
> that Thomas seems to be operating in requires that much more weight be
> given to completeness; you couldn't simply document that your function
> will not handle negative numbers. You would have to gracefully handle
> this illegitimate input (hopefully with at least a useful warning
> message!)
>
> This is a balancing act. The simplest APIs are generally less
> complete; The most complete ones are generally less simple. I'm
> afraid you can't have it all.
>

Matt's three-parameter solution is more complex and less complete than
the two parameter approach that uses an array as the second parameter.

The idea to add documentation for the added complexity is not justified.
It seems to be an indication of poor design.

With the array-based solution, documentation should not be needed at all.

Matt's solution should be marginally less efficient (though not
measurably so under normal circumstances). The string value is used with
property access operator, getting a `split` property, resulting in the
creation of a String object (via [[ToObject]]). The property name
`split` is then resolved on `String.prototype` and called as a function
call. If the character to split on was not present in one of the
properties, the result is the desired array of string values to search.

Instead, the desired array of string values to search could be passed in.

The only advantage Matt's solution has is that it looks closer to a
normal property access.

That advantage is nice, but outweighed by complexity it introduces.

If having something that looks like the property access operator is more
desirable, then the property access operator fits that perfectly.

The property access operator is easy to understand. It is more
efficient. It is documented in the ECMA-262 specification.

Matt's initial solution is more complicated than the others, it can
fail, it is slightly less efficient, and now you are suggesting that it
needs documentation.

Thomas 'PointedEars' Lahn

unread,
May 16, 2010, 7:56:29 AM5/16/10
to
Scott Sauyet wrote:

> Thomas 'PointedEars' Lahn wrote:
>> Scott Sauyet wrote:
>>> Thomas 'PointedEars' Lahn wrote:
>>>> Scott Sauyet wrote:
>>>>> Thomas 'PointedEars' Lahn wrote:
>>>>>> A helper function that by design makes it hard for it to be reused,
>>>>>> that makes code less legible and less reliable than if it was not
>>>>>> used, a function that is not generally applicable, is not a goal to
>>>>>> be attained.
>>>>> I can buy this: "A helper function that by design makes it hard for
>>>>> it to be reused, that makes code less legible and less reliable than
>>>>> if it was not used, is not a goal to be attained." But I'm not buying
>>>>> your "generally applicable" clause.
>>>> Perhaps you are misunderstanding, then.
>>> Maybe, but I think it's more that I disagree.
>> ISTM you do not know what you are disagreeing with.
>
> And ISTM that you are trying to solve a different problem than I am.
> Matt hasn't chimed in here lately

Correct. He has specified the problem and his suggestion to it right from
the start. He has provided his implementation in a followup to his OP then,
which was then subject to further discussion.

> so it's not clear which approach is closer to his needs.

Yes, it is.

> I've explained clearly what my goals from the code are. You've explained
> what yours are.

Mine are the same as Matt's: Error-free deep property access. Matt is
willing to accept that either certain properties cannot be accessed with it
or that the caller is required to specify a delimiter that is not contained
in a property name. I am not, for the reasons already given.

> [...]


>>>>> Code needs to have an reasonable domain.
>>>> The domain is property access.
>>> Not to my mind. And perhaps that is the crux of the matter.
>> Yes, perhaps you do not read what you are discussing about. The whole
>> point of this was guarded property access. Read the Subject, for
>> goodness' sake!
>
> So the subject line in a USENET posting is supposed to be more
> important than the direction of the subsequent conversation?

Are you being intentionally obtuse? The Subject of the postings of this
thread are continuing to describe the problem to be solved in this case!

>>> The language already has '[]' for property access, and a shortcut for
>>> some simpler cases: '.'. I have little need to use a function that has
>>> the same domain as those language constructs.
>>
>> Then you are in the wrong thread. The problem was that the property
>> access `foo.bar.baz' would fail if `foo.bar' did not store a value that
>> can have properties. As a solution, a function was suggested that does
>> the property access instead and returned `undefined' or `null' instead of
>> throwing an exception then.
>
> Right, the goal was to get the value of "foo.bar.baz" if "foo" exists
> and has a property "bar", which in turn has a property "baz".

No, it was not.

.-<news:083890c5-1c81-48db...@b21g2000vbh.googlegroups.com>


|
| Does anyone here use a general convenience method for deep property

| access that will not throw an error if any property along the chain is
| undefined?
|
| For example:
|
| deep(document, "body.firstChild.style.backgroundColor");

| or
| deep("myElementId.childNodes[3].id");
| or
| deep( myJsonObject,
| "locations.ca.sandiego.directory.people.smith.john.phone");
|
| This would return undefined if any element along the chain is not
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| there, or index is out of bounds, etc. If the chain gets to the end,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| it would return the last-evaluated value. This would be convenient for
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| accessing deep properties of objects that may or may not exist, and
| not having to manually check the chain in your code. [...]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Since you are apparently not paying attention, it does not make sense for me
to continue discussing this with you.

Scott Sauyet

unread,
May 17, 2010, 9:12:34 AM5/17/10
to
On May 16, 3:02 am, Garrett Smith <dhtmlkitc...@gmail.com> wrote:
> Scott Sauyet wrote:
>> Andrew Poulos wrote:
>>> On 16/05/2010 2:34 AM, Scott Sauyet wrote:
>>>> Thomas 'PointedEars' Lahn wrote:
>>>>> Irrelevant.
>>>> The requirements I had for my version of this are irrelevant, but your
>>>> fantasies of cases like this are relevant?:
>>>> |  $prop(obj, 'prop/erty%.prop#erty.%[prop|erty]', '%')
>>>> Perhaps we inhabit different parts of the development world.  Are you
>>>> in academia by any chance?  In the business community I work in, we
>>>> write code to solve business needs.  We try to keep it as simple as
>>>> possible, sacrificing simplicity for completeness only when real-world
>>>> considerations force us to.  Is your experience very different?
>
> I do not believe that the business is in need of a property access
> function. It is a programmer decision to create the abstraction which
> provides little apparent value, other than convenience.

You're right. It's not a business need, but a programmer
convenience. But when programming in a business environment, it's
often the concerns about simplicity that trump those of convenience.


>> This is a balancing act.  The simplest APIs are generally less
>> complete;  The most complete ones are generally less simple.  I'm
>> afraid you can't have it all.
>
> Matt's three-parameter solution is more complex and less complete than
> the two parameter approach that uses an array as the second parameter.

Do you think it's more complex to implement or a more complex API?
The former might well be true. But I don't buy the latter at all.

$prop(obj, "foo.bar.baz")

vs.

$prop(obj, ["foo", "bar", "baz"]);

Even in those rare cases where a delimiter is needed, I would argue
that the first is simpler to read and understand that the latter. And
mine went one step further, eliminating the first parameter, so it
looked just like

fetch("obj.foo.bar.baz");


> The idea to add documentation for the added complexity is not justified.
>   It seems to be an indication of poor design.
>
> With the array-based solution, documentation should not be needed at all.

How much more documentation is needed for the string version than the
array version?


> Matt's solution should be marginally less efficient (though not
> measurably so under normal circumstances). The string value is used with
> property access operator, getting a `split` property, resulting in the
> creation of a String object (via [[ToObject]]). The property name
> `split` is then resolved on `String.prototype` and called as a function
> call. If the character to split on was not present in one of the
> properties, the result is the desired array of string values to search.

Yes, but if this sort of micro-efficiency is important, you probably
shouldn't be adding such a function call in the first place, just do
the "if (obj && obj.foo && obj.foo.bar && obj.foo.bar.baz)" bit
yourself.

Remember also that mine was solving a somewhat broader problem than
Matt's:

fetch("obj.prop1.prop2[current.left.size].color");

which seems much clearer to me than

$prop(obj,"prop1","prop2",$prop(current,"left","size"),"color");


> Instead, the desired array of string values to search could be passed in.
>
> The only advantage Matt's solution has is that it looks closer to a
> normal property access.
>
> That advantage is nice, but outweighed by complexity it introduces.

That's where I disagree. The whole point in my version was to reduce
the complexity of the code by pulling the checks for undefined/null/
whatever out of the main code and into a function, leaving clear the
intent of the call. The complexity was in implementation, which
bothers me little, and not in API, where it bothers me much more.


> If having something that looks like the property access operator is more
> desirable, then the property access operator fits that perfectly.
>
> The property access operator is easy to understand. It is more
> efficient. It is documented in the ECMA-262 specification.

Right. But then you need to do all the intermediate checks for bad
values in your main code. Often that's no big deal. But sometimes it
can become a distraction. That distraction is what this code is meant
to avoid.


> Matt's initial solution is more complicated than the others, it can
> fail, it is slightly less efficient, and now you are suggesting that it
> needs documentation.

In fact, I've said all along that given the requirements that Matt
seems to have, he should do a multiple parameter version instead of a
single string. But I've also been arguing against the categorical
statements that a single-parameter approach is inherently wrong.

--
Scott

Scott Sauyet

unread,
May 17, 2010, 9:38:39 AM5/17/10
to

And so Matt has made it clear that that the completeness that you're
promoting is not as important to him as it is to you. That is central
to the difference between your proposal and mine. I find the simpler
API more important than the ability to use if for any legal property
value. It's seems pretty arrogant to say that you know Matt's goals
well enough to claim them as aligned with yours while simultaneously
explaining the difference between you in what you will accept in a
solution.


>>>>>> Code needs to have an reasonable domain.
>>>>> The domain is property access.
>>>> Not to my mind.  And perhaps that is the crux of the matter.
>>> Yes, perhaps you do not read what you are discussing about.  The whole
>>> point of this was guarded property access.  Read the Subject, for
>>> goodness' sake!
>
>> So the subject line in a USENET posting is supposed to be more
>> important than the direction of the subsequent conversation?
>
> Are you being intentionally obtuse?  The Subject of the postings of this
> thread are continuing to describe the problem to be solved in this case!

As already made clear, the language already property access built in
and ways to check for errors in the process. Why are you not
promoting something along the lines of

var result = (obj && obj.foo && obj.foo.bar) ? obj.foo.bar :
undefined;

or some more complete variant of it if there is no other goal than
error-free property access? It will be at least marginally faster
than any function that we create.

No, I take as a major goal the convenience, as Matt suggested:

| This would be convenient for accessing deep properties of objects


| that may or may not exist, and not having to manually check the
| chain in your code.

So then the question of what API is most convenient for the day-to-day
work of a developer becomes much more important to me than the
possibility that she will one day want to use it to access a property
chain with elements containing unusual characters.

I know you see it differently. That's clear because I have been
paying attention, whether you think so or not:

> [ ... ]


> Since you are apparently not paying attention, it does not make sense for me
> to continue discussing this with you.

Just as well, I was getting tired of your unwillingness to hear
anything that might disagree with you.

BTW, your signature is borken.

--
Scott

Matt Kruse

unread,
May 17, 2010, 10:27:53 AM5/17/10
to
On May 15, 10:45 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> No, I am saying that such a property-accessing function should allow access
> to all properties.

Your quest for completeness is cute, but ultimately futile.

A string delimited with '.' works in probably at least 99% of the
cases in which I wish to use it, and probably the same for most
people. Solving for the remaining <1% of cases requires a syntax that
is less concise and convenient, and more prone to error (matching up
quotes, etc).

There is simply no compelling need to solve for the general case. I
realize this probably bugs you to the core, but that is your personal
problem.

Just to diverge a bit... this obsessive need to solve the general case
is not necessarily the better approach. We live in a world of
approximations, where the solution needed depends on the resolution at
which you need an answer. Newton's theory of gravity is wonderful. The
equations work for all practical cases that a typical person would
ever encounter. If you want to calculate the trajectory of a pumpkin
launched via catapult, the classical gravity laws work well. But they
are NOT correct. We know this because of relativity. When we calculate
more complex systems, we need to use more complicated (and more
correct, but still not perfect) equations.

So, are Newton's laws "wrong"? If you want 100% completeness for the
general case, then yes, they are. However, they work perfectly well
for most cases. Given the resolution of solution needed, a simpler -
though less "correct" - solution is better.

Computer Programming is a science, and similar logic still applies. It
is not always practical to solve the general case. If you can find a
solution that works well for a subset of the general case, and meets
your needs, and solves that subset correctly, then it is perfectly
acceptable to use it. It is also great to ponder the general case and
consider alternative solutions, but that may be more of an academic
exercise than a practical one. Between the two ends lies a sliding
scale of pros and cons, and it is up to the individual developer to
consider other factors (business requirements, execution efficiency,
code maintenance, cost, reusability, etc) and decide where on that
sliding scale he feels most comfortable.

This is what I have done with my approach of a '.' delimited string.

Pros:
- Simple, concise syntax
- Works for the vast majority of common cases
- Handles arrays[0], methods(), nested arrays[0][0], and even
property names with empty brackets[]

Cons:
- Fails for property names containing the delimiter
- String splitting is slightly less efficient than passing multiple
args

I'm perfectly happy with that balance, while still being interested in
and seeing the benefits of solving the more general case.

Matt Kruse

David Mark

unread,
May 17, 2010, 10:51:12 AM5/17/10
to
Matt Kruse wrote:
> On May 15, 10:45 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
> wrote:
>> No, I am saying that such a property-accessing function should allow access
>> to all properties.
>
> Your quest for completeness is cute, but ultimately futile.
>

[snip a heap of blithering]

I suppose you still use jQuery as well. :)

http://www.urbandictionary.com/define.php?term=pseudo-intellectual

Matt Kruse

unread,
May 17, 2010, 11:08:10 AM5/17/10
to
On May 17, 9:51 am, David Mark <dmark.cins...@gmail.com> wrote:
> [snip a heap of blithering]
> I suppose you still use jQuery as well.  :)
> http://www.urbandictionary.com/define.php?term=pseudo-intellectual

It's good to see that you are still here trolling with ad-hominem
attacks and spewing your same old tired mantra, David. But seriously,
isn't it time to grow up, move on, and discuss ideas instead of
attacking people?

Matt Kruse

Scott Sauyet

unread,
May 17, 2010, 11:28:06 AM5/17/10
to

Scott Sauyet

unread,
May 17, 2010, 11:48:28 AM5/17/10
to
Matt Kruse wrote:
> Thomas 'PointedEars' Lahn wrote:

>> No, I am saying that such a property-accessing function should allow access
>> to all properties.
>
> Your quest for completeness is cute, but ultimately futile.

Nice to hear you back in this conversation! :-)


> A string delimited with '.' works in probably at least 99% of the
> cases in which I wish to use it, and probably the same for most
> people. Solving for the remaining <1% of cases requires a syntax that
> is less concise and convenient, and more prone to error (matching up
> quotes, etc).
>
> There is simply no compelling need to solve for the general case. I
> realize this probably bugs you to the core, but that is your personal
> problem.

I suggested a generalization in a different direction, and wonder if
you find that one any more interesting:

fetch("obj1.prop1.prop2[objA.propA.propB].prop3");

where both "obj1" and "objA" are assumed to be defined in the current
context, although the code should handle the case where they're not,
and objA.propA.propB contains the name of some property of
obj1.prop1.prop2, although again the code should handle things
appropriately when that's not true.

Because of this generalization, I find it easier to move the initial
object into the String and supply just a single string parameter.
Obviously I could add an optional delimiter parameter too if needed.

Would you find this useful?


> Pros:
>  - Simple, concise syntax
>  - Works for the vast majority of common cases
>  - Handles arrays[0], methods(), nested arrays[0][0], and even
> property names with empty brackets[]

And I think you could extend it relatively easily to handle property
names with content in the brackets as long as you were willing to risk
a possible ambiguity in

var objA = {
"propA": {
"propB": "myVal"
//, ...
} //, ...
};
var obj1 = {
"prop1": {
"prop2" : {
"myVal": {
"prop3": "final result"
//, ...
}
"objA.propA.propB": {
"prop3": "incorrect result"
//, ...
} //, ...
} // , ...
} //, ...
};

var result = fetch("obj1.prop1.prop2[objA.propA.propB].prop3");

> Cons:
>  - Fails for property names containing the delimiter
>  - String splitting is slightly less efficient than passing multiple
> args
>
> I'm perfectly happy with that balance, while still being interested in
> and seeing the benefits of solving the more general case.

I'm curious too, but would probably still use a simpler solution
unless my requirements started getting more complex.

--
Scott

Stefan Weiss

unread,
May 17, 2010, 2:53:27 PM5/17/10
to
On 17/05/10 15:12, Scott Sauyet wrote:
> $prop(obj, "foo.bar.baz")
>
> vs.
>
> $prop(obj, ["foo", "bar", "baz"]);
>
> Even in those rare cases where a delimiter is needed, I would argue
> that the first is simpler to read and understand that the latter. And
> mine went one step further, eliminating the first parameter, so it
> looked just like
>
> fetch("obj.foo.bar.baz");

How can that work unless obj is global?

[and unless $prop() is defined inside the scope where you call it, but
that would be silly]


--
stefan

Scott Sauyet

unread,
May 17, 2010, 3:21:13 PM5/17/10
to
Stefan Weiss wrote:
> On 17/05/10 15:12, Scott Sauyet wrote:
>>     fetch("obj.foo.bar.baz");
>
> How can that work unless obj is global?

Hmmm, I'm wondering if I'm simply misremembering code from 2003-04 or
if we had a way to deal with that. In those days we used the global
scope a lot, but I can't believe we didn't run into such an issue.
Now I *really* wish I had access to that code!

-- Scott

Matt Kruse

unread,
May 17, 2010, 4:07:25 PM5/17/10
to

Oh yeah, that's what I meant to ask you and forgot. That's why I pass
in the root object, because otherwise you would need to resolve the
first identifier globally, and that never happens in my code ;)

In my syntax, if there is no root object passed in, then the first
identifier is assumed to be an id, and getElementById() is called
first to get the root object. Since this is the most common scenario
for me, it's another layer of convenience.

Matt Kruse

Scott Sauyet

unread,
May 17, 2010, 4:15:36 PM5/17/10
to

I wasn't using it for DOM nodes usually, so I know I wasn't doing
that. I'm wondering if it was just that we were running so much in
those days in the global context. That might be the main reason that
we eventually abandoned it, having to hoist locals to a global context
to use it. But that doesn't really sound familiar. I can't think of
any tricks now to deal with that problem.

I have this problem with my memory, I forget exactly what it is! :-(

--
Scott

nick

unread,
May 17, 2010, 11:29:12 PM5/17/10
to
David Mark wrote:
> nick wrote:
>> Garrett Smith wrote:
>>> Stefan Weiss wrote:

>>>>   try { var color = body.firstChild.style.backgroundColor; } catch(e) {}

>> This seems like the most obvious way to do it.

> The trouble is that it is ham-fisted.  You will have no idea why the
> exception is thrown, so the pattern has very limited potential in
> anything but the simplest of contexts.

Not any more so that a function that parses a string and returns
either 'true' or 'false.' This should solve the problem the OP
presented just about as effectively, minus the built-in dom stuff from
Matt's "stab at it" post (I'd rather have separate dom selector and
'can access' functions, personally).

It could be easily modified to return the property value if it is
found as in Matt's example, but I'm not sure I like this either...
what if the value is 0, false, null, or undefined? If you forget to
use ===, the behavior could invite mistakes. Maybe returning something
like this would be safer?

{ "value" : /* return value goes here */ }

David Mark

unread,
May 18, 2010, 5:42:53 AM5/18/10
to

Some spin that. Who is responsible for moving projects like jQuery,
Dojo, etc. forward (whether they like it or not?) Who comes up with and
publishes the best ideas (not to mention library) for cross-browser
scripting?

http://www.cinsoft.net/host.html
http://www.cinsoft.net/mylib.html

Then who periodically pops in here to whine and insult me because much
of what I do invalidates years of futility on their part? And other
than periodically pointing out that you are a time-wasting twit, I
rarely insult anyone in here. Out of nearly 5,000 posts, virtually all
of them are about ideas. Look at how many times I have gone out of my
way to solve problems for people here, despite the fact that often they
are ungrateful (and even hostile). Go back and read them from the start
if your amnesia is flaring up again.

Nobody's buying your revisionism (except perhaps you).

It is loading more messages.
0 new messages