Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.javascript > #17925 > unrolled thread
| Started by | Cezary Tomczyk <cezary.tomczyk@gmail.com> |
|---|---|
| First post | 2013-01-03 22:58 +0100 |
| Last post | 2013-01-06 21:38 +0100 |
| Articles | 20 on this page of 32 — 6 participants |
Back to article view | Back to comp.lang.javascript
Two versions of code - advantages and differences Cezary Tomczyk <cezary.tomczyk@gmail.com> - 2013-01-03 22:58 +0100
Re: Two versions of code - advantages and differences Stefan Weiss <krewecherl@gmail.com> - 2013-01-04 00:41 +0100
Re: Two versions of code - advantages and differences Cezary Tomczyk <cezary.tomczyk@gmail.com> - 2013-01-04 09:15 +0100
Re: Two versions of code - advantages and differences Gregor Kofler <usenet@gregorkofler.com> - 2013-01-04 11:26 +0100
Re: Two versions of code - advantages and differences Cezary Tomczyk <cezary.tomczyk@gmail.com> - 2013-01-04 14:29 +0100
Re: Two versions of code - advantages and differences Gregor Kofler <usenet@gregorkofler.com> - 2013-01-04 14:56 +0100
Re: Two versions of code - advantages and differences Cezary Tomczyk <cezary.tomczyk@gmail.com> - 2013-01-04 16:52 +0100
Re: Two versions of code - advantages and differences Cezary Tomczyk <cezary.tomczyk@gmail.com> - 2013-01-04 09:19 +0100
Re: Two versions of code - advantages and differences Gregor Kofler <usenet@gregorkofler.com> - 2013-01-04 11:25 +0100
Re: Two versions of code - advantages and differences Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2013-01-04 15:31 +0100
Re: Two versions of code - advantages and differences David Mark <dmark.cinsoft@gmail.com> - 2013-01-05 08:37 -0800
Re: Two versions of code - advantages and differences Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2013-01-05 18:14 +0100
Re: Two versions of code - advantages and differences David Mark <dmark.cinsoft@gmail.com> - 2013-01-05 10:51 -0800
Re: Two versions of code - advantages and differences Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2013-01-05 20:46 +0100
Re: Two versions of code - advantages and differences David Mark <dmark.cinsoft@gmail.com> - 2013-01-05 17:12 -0800
Re: Two versions of code - advantages and differences David Mark <dmark.cinsoft@gmail.com> - 2013-01-06 17:43 -0800
Re: Two versions of code - advantages and differences Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2013-01-07 03:58 +0100
Re: Two versions of code - advantages and differences David Mark <dmark.cinsoft@gmail.com> - 2013-01-06 19:23 -0800
Re: Two versions of code - advantages and differences Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2013-01-07 05:19 +0100
Re: Two versions of code - advantages and differences Cezary Tomczyk <cezary.tomczyk@gmail.com> - 2013-01-06 22:30 +0100
Re: Two versions of code - advantages and differences Stefan Weiss <krewecherl@gmail.com> - 2013-01-07 02:35 +0100
Re: Two versions of code - advantages and differences Cezary Tomczyk <cezary.tomczyk@gmail.com> - 2013-01-07 22:45 +0100
Re: Two versions of code - advantages and differences Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2013-01-07 04:36 +0100
Re: Two versions of code - advantages and differences Cezary Tomczyk <cezary.tomczyk@gmail.com> - 2013-01-07 23:06 +0100
Re: Two versions of code - advantages and differences Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2013-01-08 12:35 +0100
Re: Two versions of code - advantages and differences Cezary Tomczyk <cezary.tomczyk@gmail.com> - 2013-01-09 08:34 +0100
Re: Two versions of code - advantages and differences David Mark <dmark.cinsoft@gmail.com> - 2013-01-05 09:13 -0800
Re: Two versions of code - advantages and differences Cezary Tomczyk <cezary.tomczyk@gmail.com> - 2013-01-06 11:09 +0100
Re: Two versions of code - advantages and differences David Mark <dmark.cinsoft@gmail.com> - 2013-01-06 12:56 -0800
Re: Two versions of code - advantages and differences Cezary Tomczyk <cezary.tomczyk@gmail.com> - 2013-01-07 22:53 +0100
Re: Two versions of code - advantages and differences Luc Yen <luc@goal.tw> - 2013-01-05 12:54 -0800
Re: Two versions of code - advantages and differences Cezary Tomczyk <cezary.tomczyk@gmail.com> - 2013-01-06 21:38 +0100
Page 1 of 2 [1] 2 Next page →
| From | Cezary Tomczyk <cezary.tomczyk@gmail.com> |
|---|---|
| Date | 2013-01-03 22:58 +0100 |
| Subject | Two versions of code - advantages and differences |
| Message-ID | <kc4uud$fam$1@speranza.aioe.org> |
I have a two versions of code. They are just only examples and contains
simple operations, but I want to understand more deeply some general things.
Version 1
var el = document.getElementById('test');
var fn = function(){
if( !el ){
// fallback if el is not available and then return
}
return el;
};
Version 2
var fn = (function(){
var el = document.getElementById('test');
if(el){
return function(){
return el;
}
} else {
// fallback if el is not available and then return
}
}());
Correct me, if I am wrong.
a) Version 1 has an advantage over Version 2, because Version 2 is
slower (?) and consumes more memory (?).
b) Version 2 has a closure and inside fn everything is not available
outside (except what return "return").
Anything else what can be said about advantages or differences between them?
--
Cezary Tomczyk
http://www.ctomczyk.pl/
[toc] | [next] | [standalone]
| From | Stefan Weiss <krewecherl@gmail.com> |
|---|---|
| Date | 2013-01-04 00:41 +0100 |
| Message-ID | <kc54ui$hvr$1@news.albasani.net> |
| In reply to | #17925 |
On 2013-01-03 22:58, Cezary Tomczyk wrote:
> Version 1
>
> var el = document.getElementById('test');
> var fn = function(){
> if( !el ){
> // fallback if el is not available and then return
> }
> return el;
> };
>
> Version 2
>
> var fn = (function(){
> var el = document.getElementById('test');
>
> if(el){
> return function(){
> return el;
> }
> } else {
> // fallback if el is not available and then return
> }
> }());
>
> Correct me, if I am wrong.
>
> a) Version 1 has an advantage over Version 2, because Version 2 is
> slower (?) and consumes more memory (?).
> b) Version 2 has a closure and inside fn everything is not available
> outside (except what return "return").
Your interpretation is broadly correct, but the example is too trivial
to make a good distinction (especially concerning performance or
memory). If that's all there is to it, version 1 would usually be
preferred for its simplicity.
There are several situations where a closure like version 2 would be
better suited. For example:
- When the function performs something computationally expensive (or
taking a long time), the result will be "remembered" and available for
subsequent calls to 'fn'.
- When, depending on the availability of 'el', two different functions
will be returned.
- When it uses an internal state (for example, a counter).
- When it uses private helper functions that are useless in the
surrounding scope.
In general, if the same goal can be achieved in a simple and a
complicated way, choose simple :)
By the way, one way of keeping it simple would be to use
function fn () {}
instead of
var fn = function () {};
for version 1.
Some people recommend to always use function expressions, but IMO, if
you know how variable and function declarations are handled when an
execution context is entered, this is unnecessary in most cases.
- stefan
[toc] | [prev] | [next] | [standalone]
| From | Cezary Tomczyk <cezary.tomczyk@gmail.com> |
|---|---|
| Date | 2013-01-04 09:15 +0100 |
| Message-ID | <kc6320$ngm$1@speranza.aioe.org> |
| In reply to | #17927 |
W dniu 2013-01-04 00:41, Stefan Weiss pisze:
> On 2013-01-03 22:58, Cezary Tomczyk wrote:
>> Version 1
>>
>> var el = document.getElementById('test');
>> var fn = function(){
>> if( !el ){
>> // fallback if el is not available and then return
>> }
>> return el;
>> };
>>
>> Version 2
>>
>> var fn = (function(){
>> var el = document.getElementById('test');
>>
>> if(el){
>> return function(){
>> return el;
>> }
>> } else {
>> // fallback if el is not available and then return
>> }
>> }());
>>
>> Correct me, if I am wrong.
>>
>> a) Version 1 has an advantage over Version 2, because Version 2 is
>> slower (?) and consumes more memory (?).
>> b) Version 2 has a closure and inside fn everything is not available
>> outside (except what return "return").
>
> Your interpretation is broadly correct, but the example is too trivial
> to make a good distinction (especially concerning performance or
> memory). If that's all there is to it, version 1 would usually be
> preferred for its simplicity.
As I mentioned the examples is just a simple examples. Yes, they are
trivial, but just wanted to show general idea. They can contains more
complicated code.
> There are several situations where a closure like version 2 would be
> better suited. For example:
>
> - When the function performs something computationally expensive (or
> taking a long time), the result will be "remembered" and available for
> subsequent calls to 'fn'.
But same can be done in Version 1.
> - When, depending on the availability of 'el', two different functions
> will be returned.
That's true, but this can be done also in Version 1. Functions can be
defined and returned.
> - When it uses an internal state (for example, a counter).
This also can be done in Version 1 and I do not see advantage here over
Version 2.
> - When it uses private helper functions that are useless in the
> surrounding scope.
Yes. This is the advantage Version 2 over Version 1. Of course, in some
cases and it depend on what is required.
> In general, if the same goal can be achieved in a simple and a
> complicated way, choose simple :)
I agree :-) Just wanted to get some confirmations if I am thinking in
the right way ;-)
> By the way, one way of keeping it simple would be to use
> function fn () {}
> instead of
> var fn = function () {};
> for version 1.
>
> Some people recommend to always use function expressions, but IMO, if
> you know how variable and function declarations are handled when an
> execution context is entered, this is unnecessary in most cases.
You mean this?
http://stackoverflow.com/a/3344397
--
Cezary Tomczyk
http://www.ctomczyk.pl/
[toc] | [prev] | [next] | [standalone]
| From | Gregor Kofler <usenet@gregorkofler.com> |
|---|---|
| Date | 2013-01-04 11:26 +0100 |
| Message-ID | <kc6ans$b32$2@dont-email.me> |
| In reply to | #17935 |
Am 2013-01-04 09:15, Cezary Tomczyk meinte:
> W dniu 2013-01-04 00:41, Stefan Weiss pisze:
>> On 2013-01-03 22:58, Cezary Tomczyk wrote:
>>> Version 1
>>>
>>> var el = document.getElementById('test');
>>> var fn = function(){
>>> if( !el ){
>>> // fallback if el is not available and then return
>>> }
>>> return el;
>>> };
>>>
>>> Version 2
>>>
>>> var fn = (function(){
>>> var el = document.getElementById('test');
>>>
>>> if(el){
>>> return function(){
>>> return el;
>>> }
>>> } else {
>>> // fallback if el is not available and then return
>>> }
>>> }());
>>>
>>> Correct me, if I am wrong.
>>>
>>> a) Version 1 has an advantage over Version 2, because Version 2 is
>>> slower (?) and consumes more memory (?).
>>> b) Version 2 has a closure and inside fn everything is not available
>>> outside (except what return "return").
>>
>> Your interpretation is broadly correct, but the example is too trivial
>> to make a good distinction (especially concerning performance or
>> memory). If that's all there is to it, version 1 would usually be
>> preferred for its simplicity.
>
> As I mentioned the examples is just a simple examples. Yes, they are
> trivial, but just wanted to show general idea. They can contains more
> complicated code.
>
>> There are several situations where a closure like version 2 would be
>> better suited. For example:
>>
>> - When the function performs something computationally expensive (or
>> taking a long time), the result will be "remembered" and available for
>> subsequent calls to 'fn'.
>
> But same can be done in Version 1.
At the cost of requiring more non-private variables.
>> - When, depending on the availability of 'el', two different functions
>> will be returned.
>
> That's true, but this can be done also in Version 1. Functions can be
> defined and returned.
When you start returning functions, then you end up with version 2.
>> - When it uses an internal state (for example, a counter).
>
> This also can be done in Version 1 and I do not see advantage here over
> Version 2.
See above.
>> - When it uses private helper functions that are useless in the
>> surrounding scope.
>
> Yes. This is the advantage Version 2 over Version 1. Of course, in some
> cases and it depend on what is required.
>
>> In general, if the same goal can be achieved in a simple and a
>> complicated way, choose simple
>
> I agree Just wanted to get some confirmations if I am thinking in
> the right way
>
>> By the way, one way of keeping it simple would be to use
>> function fn () {}
>> instead of
>> var fn = function () {};
>> for version 1.
>>
>> Some people recommend to always use function expressions, but IMO, if
>> you know how variable and function declarations are handled when an
>> execution context is entered, this is unnecessary in most cases.
>
> You mean this?
> http://stackoverflow.com/a/3344397
As long as you understand the differences between the two you can use
both (or prefer whatever meets your personal preference).
Gregor
[toc] | [prev] | [next] | [standalone]
| From | Cezary Tomczyk <cezary.tomczyk@gmail.com> |
|---|---|
| Date | 2013-01-04 14:29 +0100 |
| Message-ID | <kc6lff$4oh$1@speranza.aioe.org> |
| In reply to | #17939 |
W dniu 2013-01-04 11:26, Gregor Kofler pisze: > > Am 2013-01-04 09:15, Cezary Tomczyk meinte: > > W dniu 2013-01-04 00:41, Stefan Weiss pisze: [...] > >> - When the function performs something computationally expensive (or > >> taking a long time), the result will be "remembered" and available for > >> subsequent calls to 'fn'. > > > > But same can be done in Version 1. > > At the cost of requiring more non-private variables. Well, they can be private if higher there is also closure. > >> - When, depending on the availability of 'el', two different functions > >> will be returned. > > > > That's true, but this can be done also in Version 1. Functions can be > > defined and returned. > > When you start returning functions, then you end up with version 2. But the Version 2 can be used when I want to use some variables inside and I am not sure if in the higher scope there is no same variable name. With all others I agree with you. [...] > >> Some people recommend to always use function expressions, but IMO, if > >> you know how variable and function declarations are handled when an > >> execution context is entered, this is unnecessary in most cases. > > > > You mean this? > > http://stackoverflow.com/a/3344397 > > As long as you understand the differences between the two you can use > both (or prefer whatever meets your personal preference). I agree. -- Cezary Tomczyk http://www.ctomczyk.pl/
[toc] | [prev] | [next] | [standalone]
| From | Gregor Kofler <usenet@gregorkofler.com> |
|---|---|
| Date | 2013-01-04 14:56 +0100 |
| Message-ID | <kc6n1l$j0p$1@dont-email.me> |
| In reply to | #17943 |
Am 2013-01-04 14:29, Cezary Tomczyk meinte: > W dniu 2013-01-04 11:26, Gregor Kofler pisze: >> >> Am 2013-01-04 09:15, Cezary Tomczyk meinte: >> > W dniu 2013-01-04 00:41, Stefan Weiss pisze: > [...] >> >> - When the function performs something computationally expensive (or >> >> taking a long time), the result will be "remembered" and available >> for >> >> subsequent calls to 'fn'. >> > >> > But same can be done in Version 1. >> >> At the cost of requiring more non-private variables. > > Well, they can be private if higher there is also closure. Of course. However, they are no longer private variables of this function. If you need this variables only within this function scope, I prefer to restrict their visibility. > >> >> - When, depending on the availability of 'el', two different >> functions >> >> will be returned. >> > >> > That's true, but this can be done also in Version 1. Functions can be >> > defined and returned. >> >> When you start returning functions, then you end up with version 2. > > But the Version 2 can be used when I want to use some variables inside > and I am not sure if in the higher scope there is no same variable name. Er...? Yes? Gregor
[toc] | [prev] | [next] | [standalone]
| From | Cezary Tomczyk <cezary.tomczyk@gmail.com> |
|---|---|
| Date | 2013-01-04 16:52 +0100 |
| Message-ID | <kc6tr4$s79$1@speranza.aioe.org> |
| In reply to | #17944 |
W dniu 2013-01-04 14:56, Gregor Kofler pisze: > Am 2013-01-04 14:29, Cezary Tomczyk meinte: >> W dniu 2013-01-04 11:26, Gregor Kofler pisze: >>> >>> Am 2013-01-04 09:15, Cezary Tomczyk meinte: >>> > W dniu 2013-01-04 00:41, Stefan Weiss pisze: >> [...] >>> >> - When the function performs something computationally expensive (or >>> >> taking a long time), the result will be "remembered" and available >>> for >>> >> subsequent calls to 'fn'. >>> > >>> > But same can be done in Version 1. >>> >>> At the cost of requiring more non-private variables. >> >> Well, they can be private if higher there is also closure. > > Of course. However, they are no longer private variables of this > function. If you need this variables only within this function scope, I > prefer to restrict their visibility. That's true. >>> >> - When, depending on the availability of 'el', two different >>> functions >>> >> will be returned. >>> > >>> > That's true, but this can be done also in Version 1. Functions can be >>> > defined and returned. >>> >>> When you start returning functions, then you end up with version 2. >> >> But the Version 2 can be used when I want to use some variables inside >> and I am not sure if in the higher scope there is no same variable name. > > Er...? Yes? Yes :-) -- Cezary Tomczyk http://www.ctomczyk.pl/
[toc] | [prev] | [next] | [standalone]
| From | Cezary Tomczyk <cezary.tomczyk@gmail.com> |
|---|---|
| Date | 2013-01-04 09:19 +0100 |
| Message-ID | <kc63ah$o19$1@speranza.aioe.org> |
| In reply to | #17927 |
W dniu 2013-01-04 00:41, Stefan Weiss pisze: [...] > Your interpretation is broadly correct[...] I know that closures consumes more memory, but I want to know more about that. Is there a description in details how it works? -- Cezary Tomczyk http://www.ctomczyk.pl/
[toc] | [prev] | [next] | [standalone]
| From | Gregor Kofler <usenet@gregorkofler.com> |
|---|---|
| Date | 2013-01-04 11:25 +0100 |
| Message-ID | <kc6am2$b32$1@dont-email.me> |
| In reply to | #17925 |
Am 2013-01-04 09:15, Cezary Tomczyk meinte:
> W dniu 2013-01-04 00:41, Stefan Weiss pisze:
>> On 2013-01-03 22:58, Cezary Tomczyk wrote:
>>> Version 1
>>>
>>> var el = document.getElementById('test');
>>> var fn = function(){
>>> if( !el ){
>>> // fallback if el is not available and then return
>>> }
>>> return el;
>>> };
>>>
>>> Version 2
>>>
>>> var fn = (function(){
>>> var el = document.getElementById('test');
>>>
>>> if(el){
>>> return function(){
>>> return el;
>>> }
>>> } else {
>>> // fallback if el is not available and then return
>>> }
>>> }());
>>>
>>> Correct me, if I am wrong.
>>>
>>> a) Version 1 has an advantage over Version 2, because Version 2 is
>>> slower (?) and consumes more memory (?).
>>> b) Version 2 has a closure and inside fn everything is not available
>>> outside (except what return "return").
>>
>> Your interpretation is broadly correct, but the example is too trivial
>> to make a good distinction (especially concerning performance or
>> memory). If that's all there is to it, version 1 would usually be
>> preferred for its simplicity.
>
> As I mentioned the examples is just a simple examples. Yes, they are
> trivial, but just wanted to show general idea. They can contains more
> complicated code.
>
>> There are several situations where a closure like version 2 would be
>> better suited. For example:
>>
>> - When the function performs something computationally expensive (or
>> taking a long time), the result will be "remembered" and available for
>> subsequent calls to 'fn'.
>
> But same can be done in Version 1.
At the cost of requiring more non-private variables.
>> - When, depending on the availability of 'el', two different functions
>> will be returned.
>
> That's true, but this can be done also in Version 1. Functions can be
> defined and returned.
When you start returning functions, then you end up with version 2.
>> - When it uses an internal state (for example, a counter).
>
> This also can be done in Version 1 and I do not see advantage here over
> Version 2.
See above.
>> - When it uses private helper functions that are useless in the
>> surrounding scope.
>
> Yes. This is the advantage Version 2 over Version 1. Of course, in some
> cases and it depend on what is required.
>
>> In general, if the same goal can be achieved in a simple and a
>> complicated way, choose simple :)
>
> I agree :-) Just wanted to get some confirmations if I am thinking in
> the right way ;-)
>
>> By the way, one way of keeping it simple would be to use
>> function fn () {}
>> instead of
>> var fn = function () {};
>> for version 1.
>>
>> Some people recommend to always use function expressions, but IMO, if
>> you know how variable and function declarations are handled when an
>> execution context is entered, this is unnecessary in most cases.
>
> You mean this?
> http://stackoverflow.com/a/3344397
As long as you understand the differences between the two you can use
both (or prefer whatever meets your personal preference).
Gregor
[toc] | [prev] | [next] | [standalone]
| From | Thomas 'PointedEars' Lahn <PointedEars@web.de> |
|---|---|
| Date | 2013-01-04 15:31 +0100 |
| Message-ID | <1512443.gQHv90F1im@PointedEars.de> |
| In reply to | #17925 |
Cezary Tomczyk wrote:
> I have a two versions of code. They are just only examples and contains
> simple operations, but I want to understand more deeply some general
> things.
>
> Version 1
>
> var el = document.getElementById('test');
> var fn = function(){
> if( !el ){
> // fallback if el is not available and then return
> }
> return el;
> };
>
> Version 2
>
> var fn = (function(){
> var el = document.getElementById('test');
>
> if(el){
> return function(){
> return el;
> }
> } else {
> // fallback if el is not available and then return
> }
> }());
Your indentation looks partially bad here. Use spaces, not tabs.
> […]
> Anything else what can be said about advantages or differences between
> them?
Static code analysis has a hard(er) time recognizing that “fn” actually
refers to a function in Version 2. AFAIK, the JSDoc Toolkit cannot deal
with it at all (but my JSdoc is going to).
Another advantage of Version 1 over Version 2 is that it does not matter if
“el” is initialized, or its initialization value is available, before or
after the definition. For example, you would not want to use Version 2 in a
library that is loaded before the document has been loaded, because ”el”
will be a false-value then. The document need not have been parsed to after
the element in question, and the document tree not been populated as much,
before the document has been loaded. If you skip the initialization of “el”
in Version 1, you can load the code and still initialize “el” later, when
appropriate.
Your should not simply return in the second branch in Version 2, because
calls will fail then; you should return a reference to a Function instance
with an empty function body. Incidentally, this code can then be simplified
to
var fn = (function () {
var el = document.getElementById('test');
return function () {
return el;
};
}());
where it becomes obvious that the additional closure is not really needed
here, and the function itself is unnecessary. Perhaps you should present
better examples.
PointedEars
--
When all you know is jQuery, every problem looks $(olvable).
[toc] | [prev] | [next] | [standalone]
| From | David Mark <dmark.cinsoft@gmail.com> |
|---|---|
| Date | 2013-01-05 08:37 -0800 |
| Message-ID | <cff125fd-2f6a-4432-aace-ab265b857a3a@4g2000yqv.googlegroups.com> |
| In reply to | #17946 |
On Jan 4, 9:31 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
> Cezary Tomczyk wrote:
> > I have a two versions of code. They are just only examples and contains
> > simple operations, but I want to understand more deeply some general
> > things.
>
> > Version 1
>
> > var el = document.getElementById('test');
> > var fn = function(){
> > if( !el ){
> > // fallback if el is not available and then return
> > }
> > return el;
> > };
>
> > Version 2
>
> > var fn = (function(){
> > var el = document.getElementById('test');
>
> > if(el){
> > return function(){
> > return el;
> > }
> > } else {
> > // fallback if el is not available and then return
> > }
> > }());
>
> Your indentation looks partially bad here. Use spaces, not tabs.
>
> > […]
> > Anything else what can be said about advantages or differences between
> > them?
>
> Static code analysis has a hard(er) time recognizing that “fn” actually
> refers to a function in Version 2. AFAIK, the JSDoc Toolkit cannot deal
> with it at all (but my JSdoc is going to).
>
> Another advantage of Version 1 over Version 2 is that it does not matter if
> “el” is initialized, or its initialization value is available, before or
> after the definition. For example, you would not want to use Version 2 in a
> library that is loaded before the document has been loaded, because ”el”
> will be a false-value then. The document need not have been parsed to after
> the element in question, and the document tree not been populated as much,
> before the document has been loaded. If you skip the initialization of “el”
> in Version 1, you can load the code and still initialize “el” later, when
> appropriate.
>
> Your should not simply return in the second branch in Version 2, because
> calls will fail then; you should return a reference to a Function instance
> with an empty function body.
Disagree with that. Then the calling code would have no way of knowing
whether the function does anything useful. It's a variation of the
"unbreakable chain" pattern seen in jQuery:
A().B().C().D()...
If A, B and/or C fail, D blunders right ahead and tries to do
something with the failed result. Most software needs to be a bit
smarter than that. :)
[toc] | [prev] | [next] | [standalone]
| From | Thomas 'PointedEars' Lahn <PointedEars@web.de> |
|---|---|
| Date | 2013-01-05 18:14 +0100 |
| Message-ID | <2329900.uRMUlLskrn@PointedEars.de> |
| In reply to | #17956 |
David Mark wrote: > Thomas 'PointedEars' Lahn wrote: >> [You] should not simply return in the second branch in Version 2, because >> calls will fail then; you should return a reference to a Function >> instance with an empty function body. > > Disagree with that. Then the calling code would have no way of knowing > whether the function does anything useful. (For brevity, I am using “function” instead of “referred Function instance” from here.) That is not so. With an empty function body the returned function can be called *and* a called function returns “undefined” if it cannot do anything useful. That would be different from it returning “null”, *and* an advantage over returning a non-callable value from the function-constructor. My point is that the latter should return a function here as the rest of the code hinges on the callability of the returned value. And if I am not very much mistaken, this is the pattern that you are employing in My Library, too. > It's a variation of the "unbreakable chain" pattern seen in jQuery: > > A().B().C().D()... Which is why *chaining* *can be* error-prone. Non sequitur. PointedEars -- > If you get a bunch of authors […] that state the same "best practices" > in any programming language, then you can bet who is wrong or right... Not with javascript. Nonsense propagates like wildfire in this field. -- Richard Cornford, comp.lang.javascript, 2011-11-14
[toc] | [prev] | [next] | [standalone]
| From | David Mark <dmark.cinsoft@gmail.com> |
|---|---|
| Date | 2013-01-05 10:51 -0800 |
| Message-ID | <d7ce83ca-b35f-4db5-a17d-43b91a36cd08@j4g2000yqh.googlegroups.com> |
| In reply to | #17960 |
On Jan 5, 12:14 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de> wrote: > David Mark wrote: > > Thomas 'PointedEars' Lahn wrote: > >> [You] should not simply return in the second branch in Version 2, because > >> calls will fail then; you should return a reference to a Function > >> instance with an empty function body. > > > Disagree with that. Then the calling code would have no way of knowing > > whether the function does anything useful. > > (For brevity, I am using “function” instead of “referred Function instance” > from here.) > > That is not so. With an empty function body the returned function can be > called *and* a called function returns “undefined” if it cannot do anything > useful. Lots of functions return undefined, even after they have done something useful. > That would be different from it returning “null”, *and* an > advantage over returning a non-callable value from the function-constructor. What function constructor? The OP is conditionally defining a function based on whether a needed element exists. See my follow up. > > My point is that the latter should return a function here as the rest of the > code hinges on the callability of the returned value. And if I am not very > much mistaken, this is the pattern that you are employing in My Library, > too. I think you have that backwards. My Library does leave API properties undefined to indicate that there is no method available. The dynamic nature of the API allows the calling code to make intelligent decisions *before* calling API functions. Sometimes the decision is to leave the document alone. If, at the outset, when you are initializing your document enhancements, you have to call every needed API function to determine whether it is going to work (by virtue of it "returning" undefined I suppose), you are going to have a hard day of it. Some functions may "return" undefined simply by virtue of having no explicit return value (as in the case of an empty function), others may have the undefined value as part of their defined range and then there are those that won't be ready to go until after the parse (can detect if the required features are present, but can't test reliably until the document is ready). See also: https://github.com/rassie/jessie > > > It's a variation of the "unbreakable chain" pattern seen in jQuery: > > > A().B().C().D()... > > Which is why *chaining* *can be* error-prone. Non sequitur. > Yes, it *can* if D relies on C, C relies on B, etc. That's why we have conditionals in programming, which is not to be confused with rearranging patterns of CSS selectors and dollar signs until they seem to do something right. :) And no, it's not strictly the same problem as I have with your suggestion about the empty function.
[toc] | [prev] | [next] | [standalone]
| From | Thomas 'PointedEars' Lahn <PointedEars@web.de> |
|---|---|
| Date | 2013-01-05 20:46 +0100 |
| Message-ID | <1810646.Zi7hGo9um1@PointedEars.de> |
| In reply to | #17961 |
David Mark wrote:
> Thomas 'PointedEars' Lahn wrote:
>> David Mark wrote:
>> > Thomas 'PointedEars' Lahn wrote:
>> >> [You] should not simply return in the second branch in Version 2,
>> >> [because
>> >> calls will fail then; you should return a reference to a Function
>> >> instance with an empty function body.
>>
>> > Disagree with that. Then the calling code would have no way of knowing
>> > whether the function does anything useful.
>>
>> (For brevity, I am using “function” instead of “referred Function
>> instance” from here.)
>>
>> That is not so. With an empty function body the returned function can be
>> called *and* a called function returns “undefined” if it cannot do
>> anything useful.
>
> Lots of functions return undefined, even after they have done
> something useful.
Non sequitur. I was referring to *this* *example*.
>> That would be different from it returning “null”, *and* an
>> advantage over returning a non-callable value from the
>> function-constructor.
>
> What function constructor? The OP is conditionally defining a function
> based on whether a needed element exists. See my follow up.
I have taken the liberty of calling that a “function-constructor” (sic!).
>> My point is that the latter should return a function here as the rest of
>> the code hinges on the callability of the returned value. And if I am
>> not very much mistaken, this is the pattern that you are employing in My
>> Library, too.
>
> I think you have that backwards. My Library does leave API properties
> undefined to indicate that there is no method available.
In that case I must say that I do not think it is wise to leave it to the
caller to check for the existence of an API feature, and you will observe
that in JSX I am returning “undefined” or “null”, e. g., my getElementById()
emulation returns “null” if none of the available approaches are supported.
That way you can write, for example
… = (function () {
var _getElementById = jsx.dom.getElementById;
return function () {
var foo = _getElementById("foo");
if (foo)
{
/* do something with #foo */
}
};
}())
and if none of the gEBI() approaches is going to work simply nothing will be
done, the same as if there is no element with that ID. Why bother about the
difference? You cannot get to an element object, so leave a possible
related element as it is, and refrain from doing what depends on the
existence of the element.
> The dynamic nature of the API allows the calling code to make intelligent
> decisions *before* calling API functions. Sometimes the decision is to
> leave the document alone.
A function that does virtually nothing leaves the document alone. With your
approach you are not allowing, you are *forcing* the caller to make the
decision, by *forcing* them to check whether what is supposed to be a method
is not a method at all before they call it, in order to avoid a TypeError
exception to be thrown.
I do not think that is a terribly good idea. The users of such code are
paying for a slightly smaller memory footprint with greater runtime for
checks that have already been done by the library, *each* time they use the
library feature. Or they would have to cache the test result. Why would
they want to use a library then? Is not a main goal of a library to make
programs that use it *easier* and *shorter* to write, and *less* complex to
the developer; to provide *transparent* access to native features?
>> > It's a variation of the "unbreakable chain" pattern seen in jQuery:
>> >
>> > A().B().C().D()...
>>
>> Which is why *chaining* *can be* error-prone. Non sequitur.
>
> Yes, it *can* if D relies on C, C relies on B, etc. That's why we have
> conditionals in programming, which is not to be confused with
> rearranging patterns of CSS selectors and dollar signs until they seem
> to do something right. :)
There have been abuses of chaining, but you should not discount it so
quickly because of a few bad examples. Especially when it is guaranteed
that a method will return a reference to a certain type of object, chaining
can be most useful and time-saving. Given sufficiently advanced method
code, debuggers are sophisticated enough to tell you what exactly went wrong
in a chain, so that is hardly a good argument for not using it.
> And no, it's not strictly the same problem as I have with your
> suggestion about the empty function.
Good.
PointedEars
--
Prototype.js was written by people who don't know javascript for people
who don't know javascript. People who don't know javascript are not
the best source of advice on designing systems that use javascript.
-- Richard Cornford, cljs, <f806at$ail$1$8300dec7@news.demon.co.uk>
[toc] | [prev] | [next] | [standalone]
| From | David Mark <dmark.cinsoft@gmail.com> |
|---|---|
| Date | 2013-01-05 17:12 -0800 |
| Message-ID | <a17534f7-0641-48e2-bcb2-c1e196479e2e@b8g2000yqh.googlegroups.com> |
| In reply to | #17962 |
On Jan 5, 2:46 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
> David Mark wrote:
> > Thomas 'PointedEars' Lahn wrote:
> >> David Mark wrote:
> >> > Thomas 'PointedEars' Lahn wrote:
> >> >> [You] should not simply return in the second branch in Version 2,
> >> >> [because
> >> >> calls will fail then; you should return a reference to a Function
> >> >> instance with an empty function body.
>
> >> > Disagree with that. Then the calling code would have no way of knowing
> >> > whether the function does anything useful.
>
> >> (For brevity, I am using “function” instead of “referred Function
> >> instance” from here.)
>
> >> That is not so. With an empty function body the returned function can be
> >> called *and* a called function returns “undefined” if it cannot do
> >> anything useful.
>
> > Lots of functions return undefined, even after they have done
> > something useful.
>
> Non sequitur. I was referring to *this* *example*.
Okay.
>
> >> That would be different from it returning “null”, *and* an
> >> advantage over returning a non-callable value from the
> >> function-constructor.
>
> > What function constructor? The OP is conditionally defining a function
> > based on whether a needed element exists. See my follow up.
>
> I have taken the liberty of calling that a “function-constructor” (sic!).
Okay.
>
> >> My point is that the latter should return a function here as the rest of
> >> the code hinges on the callability of the returned value. And if I am
> >> not very much mistaken, this is the pattern that you are employing in My
> >> Library, too.
>
> > I think you have that backwards. My Library does leave API properties
> > undefined to indicate that there is no method available.
>
> In that case I must say that I do not think it is wise to leave it to the
> caller to check for the existence of an API feature, and you will observe
> that in JSX I am returning “undefined” or “null”, e. g., my getElementById()
> emulation returns “null” if none of the available approaches are supported.
And if it can't find the element? It also returns null, right? That's
a trivial example that demonstrates the problem of trying to slap a
static API on environments that are unknown until run time.
> That way you can write, for example
>
> … = (function () {
> var _getElementById = jsx.dom.getElementById;
>
> return function () {
> var foo = _getElementById("foo");
> if (foo)
> {
> /* do something with #foo */
> }
> };
> }())
>
> and if none of the gEBI() approaches is going to work simply nothing will be
> done, the same as if there is no element with that ID. Why bother about the
> difference?
In this trivial example, you could certainly get away with that.
> You cannot get to an element object, so leave a possible
> related element as it is, and refrain from doing what depends on the
> existence of the element.
Yes.
>
> > The dynamic nature of the API allows the calling code to make intelligent
> > decisions *before* calling API functions. Sometimes the decision is to
> > leave the document alone.
>
> A function that does virtually nothing leaves the document alone.
Then why are you calling it (or creating it in the first place)? ;)
> With your
> approach you are not allowing, you are *forcing* the caller to make the
> decision, by *forcing* them to check whether what is supposed to be a method
> is not a method at all before they call it, in order to avoid a TypeError
> exception to be thrown.
That TypeError is your friend. If you forget to do the appropriate
detection *once* at the top of your application:
if (API.areFeatures('getEBI', 'getEBCN', 'playAudio', 'whatever')) {
// Put application that requires those features here
}
Then the helpful TypeError will tell you exactly what feature is
missing (assuming you happen to test in at least one lacking
environment). Of course, there's no substitute for doing it right the
first time.
>
> I do not think that is a terribly good idea. The users of such code are
> paying for a slightly smaller memory footprint with greater runtime for
> checks that have already been done by the library, *each* time they use the
> library feature.
Not at all. The whole idea is based on one-off detection, just as the
host objects are detected behind the scenes. I suggest you see some of
my examples (or the related Jessie project).
> Or they would have to cache the test result.
Absolutely not.
> Why would
> they want to use a library then? Is not a main goal of a library to make
> programs that use it *easier* and *shorter* to write, and *less* complex to
> the developer; to provide *transparent* access to native features?
You bet. See my examples. ;)
[toc] | [prev] | [next] | [standalone]
| From | David Mark <dmark.cinsoft@gmail.com> |
|---|---|
| Date | 2013-01-06 17:43 -0800 |
| Message-ID | <f9f5f515-aa41-4892-b44b-d7542ae684da@h2g2000yqa.googlegroups.com> |
| In reply to | #17975 |
On Jan 5, 8:12 pm, David Mark <dmark.cins...@gmail.com> wrote:
> On Jan 5, 2:46 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
> wrote:
>
>
>
>
>
>
>
>
>
> > David Mark wrote:
> > > Thomas 'PointedEars' Lahn wrote:
> > >> David Mark wrote:
> > >> > Thomas 'PointedEars' Lahn wrote:
> > >> >> [You] should not simply return in the second branch in Version 2,
> > >> >> [because
> > >> >> calls will fail then; you should return a reference to a Function
> > >> >> instance with an empty function body.
>
> > >> > Disagree with that. Then the calling code would have no way of knowing
> > >> > whether the function does anything useful.
>
> > >> (For brevity, I am using “function” instead of “referred Function
> > >> instance” from here.)
>
> > >> That is not so. With an empty function body the returned function can be
> > >> called *and* a called function returns “undefined” if it cannot do
> > >> anything useful.
>
> > > Lots of functions return undefined, even after they have done
> > > something useful.
>
> > Non sequitur. I was referring to *this* *example*.
>
> Okay.
>
>
>
> > >> That would be different from it returning “null”, *and* an
> > >> advantage over returning a non-callable value from the
> > >> function-constructor.
>
> > > What function constructor? The OP is conditionally defining a function
> > > based on whether a needed element exists. See my follow up.
>
> > I have taken the liberty of calling that a “function-constructor” (sic!).
>
> Okay.
>
>
>
> > >> My point is that the latter should return a function here as the rest of
> > >> the code hinges on the callability of the returned value. And if I am
> > >> not very much mistaken, this is the pattern that you are employing in My
> > >> Library, too.
>
> > > I think you have that backwards. My Library does leave API properties
> > > undefined to indicate that there is no method available.
>
> > In that case I must say that I do not think it is wise to leave it to the
> > caller to check for the existence of an API feature, and you will observe
> > that in JSX I am returning “undefined” or “null”, e. g., my getElementById()
> > emulation returns “null” if none of the available approaches are supported.
>
> And if it can't find the element? It also returns null, right? That's
> a trivial example that demonstrates the problem of trying to slap a
> static API on environments that are unknown until run time.
>
>
>
>
>
>
>
>
>
> > That way you can write, for example
>
> > … = (function () {
> > var _getElementById = jsx.dom.getElementById;
>
> > return function () {
> > var foo = _getElementById("foo");
> > if (foo)
> > {
> > /* do something with #foo */
> > }
> > };
> > }())
>
> > and if none of the gEBI() approaches is going to work simply nothing will be
> > done, the same as if there is no element with that ID. Why bother about the
> > difference?
>
> In this trivial example, you could certainly get away with that.
>
> > You cannot get to an element object, so leave a possible
> > related element as it is, and refrain from doing what depends on the
> > existence of the element.
>
> Yes.
>
>
>
> > > The dynamic nature of the API allows the calling code to make intelligent
> > > decisions *before* calling API functions. Sometimes the decision is to
> > > leave the document alone.
>
> > A function that does virtually nothing leaves the document alone.
>
> Then why are you calling it (or creating it in the first place)? ;)
>
> > With your
> > approach you are not allowing, you are *forcing* the caller to make the
> > decision, by *forcing* them to check whether what is supposed to be a method
> > is not a method at all before they call it, in order to avoid a TypeError
> > exception to be thrown.
>
> That TypeError is your friend. If you forget to do the appropriate
> detection *once* at the top of your application:
>
> if (API.areFeatures('getEBI', 'getEBCN', 'playAudio', 'whatever')) {
> // Put application that requires those features here
>
> }
Here's another example. Say you have a client that wants an app that
delegates based on CSS selectors. This is a terrible (yet very
popular) strategy that gives future pattern re-arrangers comfort, but
demonstrates how the higher level API functions work in Jessie.
if (API.delegateQueryListener) {
// Put app here
}
First thing that should stick out about this pattern is that it is
self-documenting. The "boiler plate" explicitly states the highest
level API functions that are required by the application. Though the
delegateQueryListener function is built atop several other API
functions, those are implied to exist by the existence of the higher
level function. How do you know what the hierarchy of dependencies
looks like? It's documented. It was for My Library as well if one
cared to look closely.
Secondly, there is no arcane host object detection or testing in the
application code. This makes for simple and concise application code.
Finally, the application code will always look exactly the same,
regardless of the context. If the client wants IE 8- to get static
content, it is as simple as re-building the library to suit. There are
multiple renditions of each API function, each with clearly defined
contexts. This allows you to include just the code you need to satisfy
your primary audience without breaking documents for everybody else.
That's how cross-browser scripting is supposed to work.
http://en.wikipedia.org/wiki/Cross-browser
Example that bails out in IE 8-:
if (API.delegateQueryListener) {
// Put app here
}
Example that works for virtually every browser in use today:
if (API.delegateQueryListener) {
// Put app here
}
Same goes for plug-ins, add-ons or whatever you want to call them.
Those obviously shouldn't contain redundant host detection. An example
of an add-on that requires the "delegateQueryListener" function (and
all of its dependencies):
if (API.delegateQueryListener) {
// Put add-on here
}
No maintenance related to browser issues ever. :)
None of this is theoretical. This is how I do it and I can't remember
the last time I had a script go awry due to an unanticipated
environment. It doesn't happen because the possibility is designed out
of the system. The time it takes to type (or paste) the "boiler plate"
is negligible and has zero impact on performance or resources.
The trick is to realize that what sounds at first like a lot of
trouble is in fact the easiest way to write cross-browser
applications. Logically speaking (and what other language do
programmers speak?), it's the *only* way for all but the most trivial
applications.
Of course, the majority of those "writing" JS on the Web will never
buy into such a "complex" scheme. For the most part, they aren't
programmers. All they want is something they can copy and paste that
seems to work in whatever browsers they are using in today's
presentation. Don't pay any attention to what they are doing (or
blogging about). After all, their idea of self-documenting, fast,
concise and cross-browser is jQuery. ;)
[toc] | [prev] | [next] | [standalone]
| From | Thomas 'PointedEars' Lahn <PointedEars@web.de> |
|---|---|
| Date | 2013-01-07 03:58 +0100 |
| Message-ID | <8935431.65aROmshh0@PointedEars.de> |
| In reply to | #17975 |
David Mark wrote:
> Thomas 'PointedEars' Lahn wrote:
>> David Mark wrote:
>> > Thomas 'PointedEars' Lahn wrote:
>> >> David Mark wrote:
>> >> > Thomas 'PointedEars' Lahn wrote:
>> >> >> [You] should not simply return in the second branch in Version 2,
>> >> >> [because calls will fail then; you should return a reference to a
>> >> >> Function instance with an empty function body.
>> >>
>> >> My point is that the latter should return a function here as the rest
>> >> of the code hinges on the callability of the returned value. And if I
>> >> am not very much mistaken, this is the pattern that you are employing
>> >> in My Library, too.
>> >
>> > I think you have that backwards. My Library does leave API properties
>> > undefined to indicate that there is no method available.
>>
>> In that case I must say that I do not think it is wise to leave it to the
>> caller to check for the existence of an API feature, and you will observe
>> that in JSX I am returning “undefined” or “null”, e. g., my
>> getElementById() emulation returns “null” if none of the available
>> approaches are supported.
>
> And if it can't find the element? It also returns null, right?
Yes, AISB.
> That's a trivial example that demonstrates the problem of trying to slap a
> static API on environments that are unknown until run time.
I fail to see a problem with that approach. In fact, ISTM the very problem
that you perceive in my approach (without it actually being there) occurs
with your approach. Apparently you are testing *everything* *too early*.
>> That way you can write, for example
>>
>> … = (function () {
>> var _getElementById = jsx.dom.getElementById;
>>
>> return function () {
>> var foo = _getElementById("foo");
>> if (foo)
>> {
>> /* do something with #foo */
>> }
>> };
>> }())
>>
>> and if none of the gEBI() approaches is going to work simply nothing will
>> be done, the same as if there is no element with that ID. Why bother
>> about the difference?
>
> In this trivial example, you could certainly get away with that.
I have yet to see an example where this method does not work. This approach
is possible because we can presuppose an initialized “document” property
even before the document has been loaded. By contrast, several other JSX
methods perform feature tests not before they are called, because doing it
differently would mean object inference, which is a bad idea.
>> You cannot get to an element object, so leave a possible
>> related element as it is, and refrain from doing what depends on the
>> existence of the element.
>
> Yes.
>
>> > The dynamic nature of the API allows the calling code to make
>> > intelligent decisions *before* calling API functions. Sometimes the
>> > decision is to leave the document alone.
>> A function that does virtually nothing leaves the document alone.
>
> Then why are you calling it (or creating it in the first place)? ;)
If the purpose of the function is to find out whether an element object is
accessible in the used runtime environment, then it has to be called, of
course. But that does not need to be its only purpose. If the function can
be called to find out whether an element object is accessible, it can return
a reference to the corresponding element object at the same time. It should
not be necessary to test if this wrapper function exists.
>> With your approach you are not allowing, you are *forcing* the caller to
>> make the decision, by *forcing* them to check whether what is supposed to
>> be a method is not a method at all before they call it, in order to avoid
>> a TypeError exception to be thrown.
>
> That TypeError is your friend.
Actually, no. There are too many cases in which a TypeError exception may
be thrown.
> If you forget to do the appropriate
> detection *once* at the top of your application:
>
> if (API.areFeatures('getEBI', 'getEBCN', 'playAudio', 'whatever')) {
> // Put application that requires those features here
> }
ISTM you are confusing two concepts here.
One is performing availability tests (here: feature tests). Those are the
domain of the service provider (here: the library developer). They belong
*in the service* (here: in the library code), and should be hidden from the
user (here: the developer using the library).
The other is using the service. The purpose of a service should be to make
tasks less complicated for the user; in this case, for them to skip the
intricacies of feature tests in their code, so that they can concentrate on
the business logic. That means that the features that the service provides
should *always* be available, and therefore need _not_ be tested for by the
user. What requires tests on part of the user then is only that the service
(here: the library method) returns a value that is useful for them in their
use-case.
Somehow I find it hard to believe that someone using a (DOM) library wants
to replace (I am oversimplifying the code here for brevity, bear with me)
var foo;
if (document.getElementById)
{
foo = document.getElementById("foo");
}
else if (document.all)
{
foo = document.all["foo"];
}
else if (document.layers)
{
foo = document.layers["foo"];
}
else
{
foo = null;
}
if (foo)
{
foo.bar = baz;
}
with
var foo;
if (D.gEBI)
{
foo = D.gEBI("foo");
if (foo)
{
foo.bar = baz;
}
}
Instead, they would probably just want to write
var foo = D.gEBI("foo");
if (foo)
{
foo.bar = baz;
}
instead.
> Then the helpful TypeError will tell you exactly what feature is
> missing (assuming you happen to test in at least one lacking
> environment). Of course, there's no substitute for doing it right the
> first time.
Your approach would have virtue if it was generally possible that calling a
property that was not callable threw a *specific* user-defined exception.
Then you could catch that exception (and no other).
>> I do not think that is a terribly good idea. The users of such code are
>> paying for a slightly smaller memory footprint with greater runtime for
>> checks that have already been done by the library, *each* time they use
>> the library feature.
>
> Not at all. The whole idea is based on one-off detection, just as the
> host objects are detected behind the scenes. I suggest you see some of
> my examples (or the related Jessie project).
It does not make sense to me to test on the top in advance all features that
could possibly be used at the bottom, regardless if any or all of them will
ever be needed in the actual program flow. This effectively leads to double
maintenance. Duplicates are bad[tm]. DRY.
One should only test what one is using right before one actually uses it.
Not only because an all-in-one test is much more expensive, but also because
circumstances can change considerably between the point in time when the
feature test occurs and when the feature is used. So the interval between
those two points in time should be short.
>> Or they would have to cache the test result.
>
> Absolutely not.
Yes, they would if they were to optimize this approach.
>> Why would they want to use a library then? Is not a main goal of a
>> library to make programs that use it *easier* and *shorter* to write, and
>> *less* complex to the developer; to provide *transparent* access to
>> native features?
>
> You bet. See my examples. ;)
That is *not* transparent access. Transparent access presupposes
availability of the provider, with *all* the services they provide.
--
PointedEars
[toc] | [prev] | [next] | [standalone]
| From | David Mark <dmark.cinsoft@gmail.com> |
|---|---|
| Date | 2013-01-06 19:23 -0800 |
| Message-ID | <f02639d0-d79c-482e-926d-88cc86207a80@4g2000yqv.googlegroups.com> |
| In reply to | #17994 |
On Jan 6, 9:58 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
> David Mark wrote:
> > Thomas 'PointedEars' Lahn wrote:
> >> David Mark wrote:
> >> > Thomas 'PointedEars' Lahn wrote:
> >> >> David Mark wrote:
> >> >> > Thomas 'PointedEars' Lahn wrote:
> >> >> >> [You] should not simply return in the second branch in Version 2,
> >> >> >> [because calls will fail then; you should return a reference to a
> >> >> >> Function instance with an empty function body.
>
> >> >> My point is that the latter should return a function here as the rest
> >> >> of the code hinges on the callability of the returned value. And if I
> >> >> am not very much mistaken, this is the pattern that you are employing
> >> >> in My Library, too.
>
> >> > I think you have that backwards. My Library does leave API properties
> >> > undefined to indicate that there is no method available.
>
> >> In that case I must say that I do not think it is wise to leave it to the
> >> caller to check for the existence of an API feature, and you will observe
> >> that in JSX I am returning “undefined” or “null”, e. g., my
> >> getElementById() emulation returns “null” if none of the available
> >> approaches are supported.
>
> > And if it can't find the element? It also returns null, right?
>
> Yes, AISB.
And that illustrates the problem; despite it being trivial in this
case, it's still a problem.
>
> > That's a trivial example that demonstrates the problem of trying to slap a
> > static API on environments that are unknown until run time.
>
> I fail to see a problem with that approach. In fact, ISTM the very problem
> that you perceive in my approach (without it actually being there) occurs
> with your approach. Apparently you are testing *everything* *too early*.
No, I don't think you understand. See my follow up.
>
>
>
>
>
>
>
>
>
> >> That way you can write, for example
>
> >> … = (function () {
> >> var _getElementById = jsx.dom.getElementById;
>
> >> return function () {
> >> var foo = _getElementById("foo");
> >> if (foo)
> >> {
> >> /* do something with #foo */
> >> }
> >> };
> >> }())
>
> >> and if none of the gEBI() approaches is going to work simply nothing will
> >> be done, the same as if there is no element with that ID. Why bother
> >> about the difference?
>
> > In this trivial example, you could certainly get away with that.
>
> I have yet to see an example where this method does not work. This approach
> is possible because we can presuppose an initialized “document” property
> even before the document has been loaded. By contrast, several other JSX
> methods perform feature tests not before they are called, because doing it
> differently would mean object inference, which is a bad idea.
See my follow up.
>
> >> You cannot get to an element object, so leave a possible
> >> related element as it is, and refrain from doing what depends on the
> >> existence of the element.
>
> > Yes.
>
> >> > The dynamic nature of the API allows the calling code to make
> >> > intelligent decisions *before* calling API functions. Sometimes the
> >> > decision is to leave the document alone.
> >> A function that does virtually nothing leaves the document alone.
>
> > Then why are you calling it (or creating it in the first place)? ;)
>
> If the purpose of the function is to find out whether an element object is
> accessible in the used runtime environment, then it has to be called, of
> course.
But calling an empty function shell instead is just a waste.
> But that does not need to be its only purpose. If the function can
> be called to find out whether an element object is accessible, it can return
> a reference to the corresponding element object at the same time. It should
> not be necessary to test if this wrapper function exists.
Yes, because you may need to know if the gEBI (or whatever) wrapper
will be expected to work before you can reliably test it.
>
> >> With your approach you are not allowing, you are *forcing* the caller to
> >> make the decision, by *forcing* them to check whether what is supposed to
> >> be a method is not a method at all before they call it, in order to avoid
> >> a TypeError exception to be thrown.
>
> > That TypeError is your friend.
>
> Actually, no. There are too many cases in which a TypeError exception may
> be thrown.
No idea what you are talking about. You will get a very predictable
"Cannot call undefined value" (or something like that) at the exact
spot that you attempted to call the unavailable method. What could be
easier? On the contrary, if the code is calling empty functions
instead... Yeah, good luck debugging in unexpected environments. Won't
have any idea what is going on at a glance.
>
> > If you forget to do the appropriate
> > detection *once* at the top of your application:
>
> > if (API.areFeatures('getEBI', 'getEBCN', 'playAudio', 'whatever')) {
> > // Put application that requires those features here
> > }
>
> ISTM you are confusing two concepts here.
Doubtful. :)
>
> One is performing availability tests (here: feature tests). Those are the
> domain of the service provider (here: the library developer).
Host object feature detection is certainly the domain of the service
provider.
> They belong
> *in the service* (here: in the library code), and should be hidden from the
> user (here: the developer using the library).
Exactly. That's what all of my projects do.
>
> The other is using the service.
Well, I didn't have any confusion about that. :)
> The purpose of a service should be to make
> tasks less complicated for the user;
Yes, like host object feature detection and testing. ;)
> in this case, for them to skip the
> intricacies of feature tests in their code, so that they can concentrate on
> the business logic.
But, but, but... :)
> That means that the features that the service provides
> should *always* be available, and therefore need _not_ be tested for by the
> user.
There's where you go off the road. Some features cannot *always* be
available, nor should you have to try to force them to be available in
some legacy browser (e.g. QSA in IE 7) that could just as well do
without the enhancement that requires those features.
> What requires tests on part of the user then is only that the service
> (here: the library method) returns a value that is useful for them in their
> use-case.
Returns a value that is useful to them? That doesn't make any sense.
You can't expect to call every function at the outset. You don't want
to tangle up your application code with checks for returned undefined
values. What exactly would you do at the point where the user clicked
a command button (the most basic UI) and your API function crapped
out. Throw up an alert (requiring more code of course) telling them
not to push that button? :)
Cross-browser scripting presents unique challenges. You cannot treat
it like other programming disciplines.
>
> Somehow I find it hard to believe that someone using a (DOM) library wants
> to replace (I am oversimplifying the code here for brevity, bear with me)
>
> var foo;
> if (document.getElementById)
> {
> foo = document.getElementById("foo");
> }
> else if (document.all)
> {
> foo = document.all["foo"];
> }
> else if (document.layers)
> {
> foo = document.layers["foo"];
> }
> else
> {
> foo = null;
> }
>
> if (foo)
> {
> foo.bar = baz;
> }
>
> with
>
> var foo;
> if (D.gEBI)
> {
> foo = D.gEBI("foo");
>
> if (foo)
> {
> foo.bar = baz;
> }
> }
>
> Instead, they would probably just want to write
>
> var foo = D.gEBI("foo");
>
> if (foo)
> {
> foo.bar = baz;
> }
>
> instead.
You are too preoccupied with the most basic API function. See my
follow up. Also, there are times when you need to know if gEBI (or
related wrapper) is available before the document is ready.
>
> > Then the helpful TypeError will tell you exactly what feature is
> > missing (assuming you happen to test in at least one lacking
> > environment). Of course, there's no substitute for doing it right the
> > first time.
>
> Your approach would have virtue if it was generally possible that calling a
> property that was not callable threw a *specific* user-defined exception.
> Then you could catch that exception (and no other).
No. You *never* catch the exception. I can't make that point strongly
enough. It's there in the console to help you figure out which feature
you forgot to detect.
>
> >> I do not think that is a terribly good idea. The users of such code are
> >> paying for a slightly smaller memory footprint with greater runtime for
> >> checks that have already been done by the library, *each* time they use
> >> the library feature.
>
> > Not at all. The whole idea is based on one-off detection, just as the
> > host objects are detected behind the scenes. I suggest you see some of
> > my examples (or the related Jessie project).
>
> It does not make sense to me to test on the top in advance all features that
> could possibly be used at the bottom, regardless if any or all of them will
> ever be needed in the actual program flow.
Really? Your app doesn't have to be a single block of code. See add-
ons for My Library (e.g. Transform). That's part of the example
application, but is segregated so that the primary code needs only to
detect the presence of setElementTransform. Any other way and you'd be
trying to detect the same host features in every application.
> This effectively leads to double
> maintenance. Duplicates are bad[tm]. DRY.
You've got that backwards. See my follow up (please). :)
>
> One should only test what one is using right before one actually uses it.
That's nonsense as a general rule.
> Not only because an all-in-one test is much more expensive, but also because
> circumstances can change considerably between the point in time when the
> feature test occurs and when the feature is used. So the interval between
> those two points in time should be short.
Nothing expensive about an "areFeatures" call (or equivalent boolean
type conversion tests). As far as things changing between the time the
features are detected/tested, that's for the API function author to
consider (and it's not a common case). The application developer just
calls "areFeatures" (typically on load or "ready") and proceeds or
not. For the majority of applications, this is a very simple process
(even behind the scenes). Time intervals just don't enter into it.
>
> >> Or they would have to cache the test result.
>
> > Absolutely not.
>
> Yes, they would if they were to optimize this approach.
Nonsense. One-offs are (by definition) called once. It's over at that
point; nothing to optimize.
>
> >> Why would they want to use a library then? Is not a main goal of a
> >> library to make programs that use it *easier* and *shorter* to write, and
> >> *less* complex to the developer; to provide *transparent* access to
> >> native features?
>
> > You bet. See my examples. ;)
>
> That is *not* transparent access. Transparent access presupposes
> availability of the provider, with *all* the services they provide.
Doesn't matter what you call it. This so-called "transparency" is
generally impractical for cross-browser scripting. At a glance, it may
seem like nirvana (and the opposite some sort of hell), but that's the
wrong reaction. See the follow up post.
[toc] | [prev] | [next] | [standalone]
| From | Thomas 'PointedEars' Lahn <PointedEars@web.de> |
|---|---|
| Date | 2013-01-07 05:19 +0100 |
| Message-ID | <2365275.2IGAmF23P8@PointedEars.de> |
| In reply to | #17995 |
David Mark wrote: > Thomas 'PointedEars' Lahn wrote: >> David Mark wrote: >> > Thomas 'PointedEars' Lahn wrote: >> >> David Mark wrote: >> >> > Thomas 'PointedEars' Lahn wrote: >> >> >> David Mark wrote: >> >> >> > Thomas 'PointedEars' Lahn wrote: >> >> >> >> [You] should not simply return in the second branch in Version >> >> >> >> [2, because calls will fail then; you should return a reference >> >> >> >> [to a >> >> >> >> Function instance with an empty function body. >> >> >> >> >> >> My point is that the latter should return a function here as the >> >> >> rest of the code hinges on the callability of the returned value. >> >> >> And if I am not very much mistaken, this is the pattern that you >> >> >> are employing in My Library, too. >> >> > >> >> > I think you have that backwards. My Library does leave API >> >> > properties undefined to indicate that there is no method available. >> >> >> >> In that case I must say that I do not think it is wise to leave it to >> >> the caller to check for the existence of an API feature, and you will >> >> observe that in JSX I am returning “undefined” or “null”, e. g., my >> >> getElementById() emulation returns “null” if none of the available >> >> approaches are supported. >> > And if it can't find the element? It also returns null, right? >> Yes, AISB. > > And that illustrates the problem; despite it being trivial in this > case, it's still a problem. I do not think so. There has not been any problem both in trivial and non- trivial cases, whereever you want to draw the line. Perhaps you are just misunderstanding my approach. >> > That's a trivial example that demonstrates the problem of trying to >> > slap a static API on environments that are unknown until run time. >> >> I fail to see a problem with that approach. In fact, ISTM the very >> problem that you perceive in my approach (without it actually being >> there) occurs with your approach. Apparently you are testing >> *everything* *too early*. > > No, I don't think you understand. See my follow up. If you mean the follow-up with “−1” lines that begins with about 50 lines of quote, I'll have to pass. Get a newsreader, and learn to post. >> If the purpose of the function is to find out whether an element object >> is accessible in the used runtime environment, then it has to be called, >> of course. > > But calling an empty function shell instead is just a waste. Not if it allows the calling code to be less complicated, and the call only to be wasteful in border cases. Whereas the latter was one goal of a library. Remember? >> But that does not need to be its only purpose. If the function can >> be called to find out whether an element object is accessible, it can >> return a reference to the corresponding element object at the same time. >> It should not be necessary to test if this wrapper function exists. > > Yes, because you may need to know if the gEBI (or whatever) wrapper > will be expected to work before you can reliably test it. Then there can be another feature that tells you about it *if* you want to know. >> >> With your approach you are not allowing, you are *forcing* the caller >> >> to make the decision, by *forcing* them to check whether what is >> >> supposed to be a method is not a method at all before they call it, in >> >> order to avoid a TypeError exception to be thrown. >> > >> > That TypeError is your friend. >> >> Actually, no. There are too many cases in which a TypeError exception >> may be thrown. > > No idea what you are talking about. RTFSpec. > You will get a very predictable "Cannot call undefined value" (or > something like that) at the exact spot that you attempted to call the > unavailable method. What could be easier? On the contrary, if the code is > calling empty functions instead... Yeah, good luck debugging in unexpected > environments. FUD. Nothing bad happens with an empty function. If something should have happened and it did not, then one knows where to look. But, I repeat, that should be the domain of author of the wrapper, when testing it, not the user (unless both of them happen to be the same person). > Won't have any idea what is going on at a glance. With a TypeError you will not know at a glance where it comes from. >> One is performing availability tests (here: feature tests). Those are >> the domain of the service provider (here: the library developer). > > Host object feature detection is certainly the domain of the service > provider. And I maintain that all feature detection should be. >> They belong *in the service* (here: in the library code), and should be >> hidden from the user (here: the developer using the library). > > Exactly. That's what all of my projects do. No, you have your users test what My Library is capable of providing. >> The other is using the service. > > Well, I didn't have any confusion about that. :) I think you do. Using should not imply testing of *service* features in the user code. That would not be abstraction, it would be shifting responsibilities. >> The purpose of a service should be to make >> tasks less complicated for the user; > > Yes, like host object feature detection and testing. ;) Why stop there? >> in this case, for them to skip the intricacies of feature tests in their >> code, so that they can concentrate on the business logic. > > But, but, but... :) > >> That means that the features that the service provides >> should *always* be available, and therefore need _not_ be tested for by >> the user. > > There's where you go off the road. Some features cannot *always* be > available, Try to put yourself into the position of a (not so dumb) library user for a minute: *Your* features *can* always be available. I have just loaded them. Why are they not there? > nor should you have to try to force them to be available in > some legacy browser (e.g. QSA in IE 7) that could just as well do > without the enhancement that requires those features. Why should I use your library which forces me to test *its* features instead of the native ones, when all I wanted is to *avoid* testing *features* by myself? I simply want to get an object that I can manipulate, to implement my business logic. Why are you not only not providing it, but actively *preventing* me from *trying* to get at it? >> What requires tests on part of the user then is only that the service >> (here: the library method) returns a value that is useful for them in >> their use-case. > > Returns a value that is useful to them? That doesn't make any sense. It makes a lot of sense. > You can't expect to call every function at the outset. Nobody does. But one can expect that if the library says it provides a feature that feature is always available. Whether it does something useful in a certain environment is another matter altogether. > You don't want to tangle up your application code with checks for returned > undefined values. Instead you tangle it up with a growing list of tests for features that may never be used. Great. > What exactly would you do at the point where the user clicked > a command button (the most basic UI) and your API function crapped > out. Throw up an alert (requiring more code of course) telling them > not to push that button? :) Nonsense. It is the job of the user of the library to make sure that this case is handled, and the job of the library to make sure that it can be recognized. But it is not the job of the user to make sure that the case can be handled using the library. Because that is what the library already promised to provide, and that is why the user is using it instead of hand- crafted tests. > Cross-browser scripting presents unique challenges. You cannot treat > it like other programming disciplines. Yet you do. For example, you are assuming – and misleading the users of your code into believing – that because something is available on the top it must be available at the bottom. > You are too preoccupied with the most basic API function. See my > follow up. Also, there are times when you need to know if gEBI (or > related wrapper) is available before the document is ready. You are too preoccupied with trying to be right, not seeing the obvious disadvantages of your design when it comes to be people who want to use it. >> Not only because an all-in-one test is much more expensive, but also >> because circumstances can change considerably between the point in time >> when the feature test occurs and when the feature is used. So the >> interval between those two points in time should be short. > > Nothing expensive about an "areFeatures" call (or equivalent boolean > type conversion tests). It is, in essence, a function call to make sure that you can make a function call, when you could have just made the second call. Yes, the former *is* more expensive than the latter. And as the first call invokes tests for features that may never be used in the program flow, it is considerably more wasteful. >> >> Or they would have to cache the test result. >> > Absolutely not. >> Yes, they would if they were to optimize this approach. > > Nonsense. One-offs are (by definition) called once. It's over at that > point; nothing to optimize. The optimization would be to test only certain features at certain times, on an as-needed basis. What you call “one-off” I call a waste of resources, and a hindrance to software maintenance. >> >> Why would they want to use a library then? Is not a main goal of a >> >> library to make programs that use it *easier* and *shorter* to write, >> >> and *less* complex to the developer; to provide *transparent* access >> >> to native features? >> >> > You bet. See my examples. ;) >> >> That is *not* transparent access. Transparent access presupposes >> availability of the provider, with *all* the services they provide. > > Doesn't matter what you call it. This so-called "transparency" is > generally impractical for cross-browser scripting. At a glance, it may > seem like nirvana (and the opposite some sort of hell), but that's the > wrong reaction. See the follow up post. It would appear that you have deluded yourself into believing that you know everything. That way lies madness. -- PointedEars
[toc] | [prev] | [next] | [standalone]
| From | Cezary Tomczyk <cezary.tomczyk@gmail.com> |
|---|---|
| Date | 2013-01-06 22:30 +0100 |
| Message-ID | <kccqct$ksk$1@speranza.aioe.org> |
| In reply to | #17946 |
W dniu 2013-01-04 15:31, Thomas 'PointedEars' Lahn pisze:
> Cezary Tomczyk wrote:
>
>> I have a two versions of code. They are just only examples and contains
>> simple operations, but I want to understand more deeply some general
>> things.
>>
>> Version 1
>>
>> var el = document.getElementById('test');
>> var fn = function(){
>> if( !el ){
>> // fallback if el is not available and then return
>> }
>> return el;
>> };
>>
>> Version 2
>>
>> var fn = (function(){
>> var el = document.getElementById('test');
>>
>> if(el){
>> return function(){
>> return el;
>> }
>> } else {
>> // fallback if el is not available and then return
>> }
>> }());
>
> Your indentation looks partially bad here. Use spaces, not tabs.
Sorry, copied and pasted from Aptana maybe was wrong.
>> […]
>> Anything else what can be said about advantages or differences between
>> them?
>
> Static code analysis has a hard(er) time recognizing that “fn” actually
> refers to a function in Version 2. AFAIK, the JSDoc Toolkit cannot deal
> with it at all (but my JSdoc is going to).
True, but they are two different examples.
> Another advantage of Version 1 over Version 2 is that it does not matter if
> “el” is initialized, or its initialization value is available, before or
> after the definition. For example, you would not want to use Version 2 in a
> library that is loaded before the document has been loaded, because ”el”
> will be a false-value then. The document need not have been parsed to after
> the element in question, and the document tree not been populated as much,
> before the document has been loaded. If you skip the initialization of “el”
> in Version 1, you can load the code and still initialize “el” later, when
> appropriate.
Yes, but the examples are really simple and I wanted to demonstrate some
general idea. The "el" doesn't have to be always an reference to object.
This could be anything and could be more complex.
> Your should not simply return in the second branch in Version 2, because
> calls will fail then; you should return a reference to a Function instance
> with an empty function body. Incidentally, this code can then be simplified
> to
>
> var fn = (function () {
> var el = document.getElementById('test');
>
> return function () {
> return el;
> };
> }());
>
> where it becomes obvious that the additional closure is not really needed
> here, and the function itself is unnecessary. Perhaps you should present
> better examples.
I've just wrote something like this:
var main = {
[...]
apply : (function(){
var tempImg = document.createElement('img'),
t, img;
tempImg.width = '10';
tempImg.height = '10';
return function(o){
img = tempImg.cloneNode(false);
img.alt = o.alt;
img.src = o.src;
t = document.createElement('span');
t.appendChild(document.createTextNode('\u00a0'));
t.appendChild(img);
t.appendChild(document.createTextNode('\u00a0'));
window.setTimeout(function(){ examplefn(t); }, 100);
};
}
[...]
};
As I understand (correct me if I am wrong) this is inefficient because:
* closure need extra memory and will be always in memory because
returned function refers to variables that are outside of returned function.
* "apply" is parsed immediately which is not needed always
Anything else inefficient or wrong?
--
Cezary Tomczyk
http://www.ctomczyk.pl/
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | comp.lang.javascript
csiph-web