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


Groups > comp.lang.javascript > #32140

Re: Empty function

From Thomas 'PointedEars' Lahn <PointedEars@web.de>
Newsgroups comp.lang.javascript
Subject Re: Empty function
Date 2017-01-08 23:21 +0100
Organization PointedEars Software (PES)
Message-ID <8026292.CDJkKcVGEf@PointedEars.de> (permalink)
References <UPqdnRaDtOBAT-zFnZ2dnUU7-RHNnZ2d@westnet.com.au>

Show all headers | View raw


Andrew Poulos wrote:

> I'm needing to edit some code that's been given to me. Apparently its
> been written a decade or so ago. Paraphrased, the code follows:
> 
> var Drag = {
>    obj : null,
>    init: function(o) {
>      o.onmousedown = Drag.start;
>      o.root.onDrag = function() {}; //--> what does this line do?
>    },
>    start: function(e) {
>      document.onmousemove = Drag.drag;
>      document.onmouseup = Drag.end;
>      return false;
>    },
>    drag: function(e) {
>      Drag.obj.root.onDrag(nx, ny);
>      return false;
>    },
>    end: function() {
>      document.onmousemove = null;
>      document.onmouseup   = null;
>    }
> };
> 
> What I don't follow is what the line
>      o.root.onDrag = function() {};
> is doing. If I comment the line out the code "doesn't work". What's the
> purpose of setting an event to an empty function?

That “onDrag” is an "event" is your jump to conclusions, and a wrong one at 
that (read up on events).  It could merely be an event-_handler property_, 
and then it would be a user-defined or proprietary one (AFAIK, all standard 
event-handler properties have all-lowercase names).  For now, however, it is 
just the name of an ordinary property.  In the drag() method of the object 
referred to by “Drag”, that property needs to be callable.  That is why the 
code “doesn’t work” if you comment out the initialization (as you could have 
seen in the error console; see the FAQ).

This appears to be a lazy person’s approach to avoid feature tests in the 
drag() method.  It is error-prone as long as the property that is supposed 
to be callable there is (publicly) writable (and it appears to be so here), 
because then when the “drag” method is called, the “onDrag” property value 
can be any (even a non-callable) value even if the init() method had been 
called before.  It is also memory-inefficient because even if an onDrag() 
method is never required to be called, heap memory is being reserved for 
storing the Function instance referred to by onDrag().

The code also appears to violate the Law of Demeter because it performs a 
write access to a property of an object referred to by one of the properties 
of an object whose reference was passed to the init() method.  The init() 
method should delegate that action by calling a method of the referred 
object instead.


Contrary to common misconception, it is also insufficient and potentially  
error-prone (not all host object’s methods take kindly to that test) to test 
a property for being a true-value in order to ascertain that it is callable:

  foo.bar = 42;

  /* Do not do this */
  if (foo.bar)
  {
    foo.bar();
  }

The safest way is to subject it(s value) to a “typeof” test; should that 
operation yield "function", then it is very likely that the property value 
is callable (since ECMAScript Ed. 5 it is a requirement even for host 
object’s methods to behave this way):

  /*
   * You can also use “===”, but it is not strictly necessary
   * (no pun intended) due to the result of the “typeof” operation
   */
  if (typeof foo.bar == "function")
  {
    foo.bar();
  }

[Although it is tempting to wrap that test in a method because it can become 
tedious to write and it takes more space, it turned out that doing so 
actually reduces the runtime efficiency of the code because of the overhead 
of the method’s identifier resolution, property lookup, and method call when 
compared to the simple operation.  Therefore, a wrapping method should only 
be used if it accomplishes more than this simple test.  For example, 
jsx.object.isNativeMethod()/.areNativeMethods() prevails in JSX:object.js 
because it can test along a “property path” and multiple “leaf” properties 
in one call.  Work is in progress to remove all unnecessary calls to this 
method from JSX.]

The only completely safe solution regarding a call, however less backwards-
compatible and error-prone because it can result in false negatives, is to 
use a try…catch statement in which to attempt the call:

  try
  {
    foo.bar();
  }
  catch (e)
  {
    if (e instanceof TypeError)
    {
      /* handle problem */
    }
  }

It is error-prone because, in theory, the called method and any method that 
is called by it could throw a TypeError exception.  Also, one must be 
careful not to catch too many exceptions with one try…catch statement, 
making the source code harder to debug.

-- 
PointedEars
FAQ: <http://PointedEars.de/faq> | <http://PointedEars.de/es-matrix>
<https://github.com/PointedEars> | <http://PointedEars.de/wsvn/>
Twitter: @PointedEars2 | Please do not cc me./Bitte keine Kopien per E-Mail.

Back to comp.lang.javascript | Previous | Next — Previous in thread | Find similar | Unroll thread


Thread

Empty function Andrew Poulos <ap_prog@hotmail.com> - 2017-01-08 16:49 +1100
  Re: Empty function Martin Honnen <martin.honnen@gmx.de> - 2017-01-08 08:29 +0100
    Re: Empty function Andrew Poulos <ap_prog@hotmail.com> - 2017-01-08 20:05 +1100
      Re: Empty function Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2017-01-08 23:40 +0100
        Re: Empty function Andrew Poulos <ap_prog@hotmail.com> - 2017-01-09 10:47 +1100
          Re: Empty function Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2017-01-09 01:10 +0100
  Re: Empty function JJ <jj4public@vfemail.net> - 2017-01-08 20:53 +0700
  Re: Empty function "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2017-01-08 10:02 -0800
  Re: Empty function Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2017-01-08 23:21 +0100

csiph-web