Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.javascript > #17925 > unrolled thread

Two versions of code - advantages and differences

Started byCezary Tomczyk <cezary.tomczyk@gmail.com>
First post2013-01-03 22:58 +0100
Last post2013-01-06 21:38 +0100
Articles 20 on this page of 32 — 6 participants

Back to article view | Back to comp.lang.javascript


Contents

  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 →


#17925 — Two versions of code - advantages and differences

FromCezary Tomczyk <cezary.tomczyk@gmail.com>
Date2013-01-03 22:58 +0100
SubjectTwo 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]


#17927

FromStefan Weiss <krewecherl@gmail.com>
Date2013-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]


#17935

FromCezary Tomczyk <cezary.tomczyk@gmail.com>
Date2013-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]


#17939

FromGregor Kofler <usenet@gregorkofler.com>
Date2013-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]


#17943

FromCezary Tomczyk <cezary.tomczyk@gmail.com>
Date2013-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]


#17944

FromGregor Kofler <usenet@gregorkofler.com>
Date2013-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]


#17947

FromCezary Tomczyk <cezary.tomczyk@gmail.com>
Date2013-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]


#17936

FromCezary Tomczyk <cezary.tomczyk@gmail.com>
Date2013-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]


#17937

FromGregor Kofler <usenet@gregorkofler.com>
Date2013-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]


#17946

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2013-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]


#17956

FromDavid Mark <dmark.cinsoft@gmail.com>
Date2013-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]


#17960

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2013-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]


#17961

FromDavid Mark <dmark.cinsoft@gmail.com>
Date2013-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]


#17962

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2013-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]


#17975

FromDavid Mark <dmark.cinsoft@gmail.com>
Date2013-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]


#17993

FromDavid Mark <dmark.cinsoft@gmail.com>
Date2013-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]


#17994

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2013-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]


#17995

FromDavid Mark <dmark.cinsoft@gmail.com>
Date2013-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]


#17997

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2013-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]


#17989

FromCezary Tomczyk <cezary.tomczyk@gmail.com>
Date2013-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