addEvent - The late entry :)

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Richard Cornford

    #31
    Re: addEvent - The late entry :)

    kangax wrote:
    On Jul 21, 5:37 pm, Richard Cornford wrote:
    >
    >[snip]
    >
    >And finally, using the - concat - method to append an array created
    >from
    >the arguments object is very convoluted and relatively inefficient
    >when
    >the arguments object can be used as the second argument to the -
    >apply -
    >method and the - apply - method could be called on - push -, which
    >will
    >take any number of arguments and append them to an array. That is:-
    >__method.apply (object, args.concat($A( arguments))); - can be replaced
    >with - __method.apply( obj, args.push.apply (args, arguments)); - and
    >should result in superior performance.
    >
    I didn't know about Array.prototype .push being faster than
    Array.prototype .concat in this case. Thanks for the tip.
    Faster, but not usefully so.

    However, it seems that the fastest method of turning an arguments object
    into an array is:-

    ((arguments.len gth == 1)?[arguments[0]]:Array.apply(th is, arguments))

    - where - this - is the global object in my tests, but should not be
    altered by the process so could be any object. I did try null as first
    argument, which is fine on everything but Firefox, where it makes the
    process considerably slower than using an object reference.

    Unfortunately when the Array constructor, called as a function (so not
    with the - new - keyword), is only given one argument and that argument
    turns out to be a numeric value that is a positive integer smaller than
    2 to the power of 32 then you get different behaviour. So the expression
    has to include that special handling for (arguments.leng th == 1). My
    test still show that whole expression outperforming all of the
    alternatives that I could think of.

    The precise benefit depends on the number of arguments. With zero
    arguments the different can be very small on some browsers (especially
    firefox and IE). I did my comparisons against Prototype.js's - $A -
    function , which is considered to be 100% in the following numbers. At
    20 arguments Windows Safari 3 executes that expression in 48% of the
    time, and at zero arguments 47%. Mac Safari 2 was better, ranging from
    16% with 20 arguments down to 34% with zero.

    Opera 9.2 showed the next greatest performance change. 23% at 20
    arguments and 57% at zero.
    IE 7 came next with 62% at 20 arguments and 81% at zero.
    IE 6: 65% to 89%.

    Firefox 2.0.4 was the worst I have tried to date. At 20 arguments it
    only manages 79% and was down to 85% by zero arguments, but the actual
    execution time for the expression (and all of the alternatives) was the
    longest of the group tested on the same hardware (by at least a factor
    of 2) so the actual gain in time saved was still greater than for some
    of the better performing JS engines.

    Array.prototype .slice.call(arg uments, X); - has still got to be the
    fastest method if not all of the arguments are wanted, and (strangely) -
    Array.prototype .splice.call(ar guments, 0, arguments.lengt h); - is
    another alternative, but there, with Windows Safari 3, the benefit
    dropped off with more arguments and at 8 arguments it was worse than -
    $A -.

    These were tests on a mixture of Pentium 4, Core 2 Duo and Core 2 Quad
    processors and Windows and Mac OSs so the results may not yet be
    sufficiently reprehensive for the comparisons to hold in general. I will
    probably post the test code for these tomorrow (or soonish) in case
    anyone wants to see if other hardware permutations contradict those
    results (or try it with other browsers/OSs).

    Richard.

    Comment

    • kangax

      #32
      Re: addEvent - The late entry :)

      On Jul 23, 8:44 pm, "Richard Cornford" <Rich...@litote s.demon.co.uk>
      wrote:
      kangax wrote:
      On Jul 21, 5:37 pm, Richard Cornford wrote:
      >
      [snip]
      >
      And finally, using the - concat - method to append an array created
      from
      the arguments object is very convoluted and relatively inefficient
      when
      the arguments object can be used as the second argument to the -
      apply -
      method and the - apply - method could be called on - push -, which
      will
      take any number of arguments and append them to an array. That is:-
      __method.apply( object, args.concat($A( arguments))); - can be replaced
      with - __method.apply( obj, args.push.apply (args, arguments)); - and
      should result in superior performance.
      >
      I didn't know about Array.prototype .push being faster than
      Array.prototype .concat in this case. Thanks for the tip.
      >
      Faster, but not usefully so.
      >
      However, it seems that the fastest method of turning an arguments object
      into an array is:-
      >
      ((arguments.len gth == 1)?[arguments[0]]:Array.apply(th is, arguments))
      >
      - where - this - is the global object in my tests, but should not be
      altered by the process so could be any object. I did try null as first
      argument, which is fine on everything but Firefox, where it makes the
      process considerably slower than using an object reference.
      >
      Unfortunately when the Array constructor, called as a function (so not
      with the - new - keyword), is only given one argument and that argument
      turns out to be a numeric value that is a positive integer smaller than
      2 to the power of 32 then you get different behaviour. So the expression
      has to include that special handling for (arguments.leng th == 1). My
      test still show that whole expression outperforming all of the
      alternatives that I could think of.
      >
      The precise benefit depends on the number of arguments. With zero
      arguments the different can be very small on some browsers (especially
      firefox and IE). I did my comparisons against Prototype.js's - $A -
      function , which is considered to be 100% in the following numbers. At
      20 arguments Windows Safari 3 executes that expression in 48% of the
      time, and at zero arguments 47%. Mac Safari 2 was better, ranging from
      16% with 20 arguments down to 34% with zero.
      >
      Opera 9.2 showed the next greatest performance change. 23% at 20
      arguments and 57% at zero.
      IE 7 came next with 62% at 20 arguments and 81% at zero.
      IE 6: 65% to 89%.
      >
      Firefox 2.0.4 was the worst I have tried to date. At 20 arguments it
      only manages 79% and was down to 85% by zero arguments, but the actual
      execution time for the expression (and all of the alternatives) was the
      longest of the group tested on the same hardware (by at least a factor
      of 2) so the actual gain in time saved was still greater than for some
      of the better performing JS engines.
      >
      Array.prototype .slice.call(arg uments, X); - has still got to be the
      fastest method if not all of the arguments are wanted, and (strangely) -
      Array.prototype .splice.call(ar guments, 0, arguments.lengt h); - is
      another alternative, but there, with Windows Safari 3, the benefit
      dropped off with more arguments and at 8 arguments it was worse than -
      $A -.
      >
      These were tests on a mixture of Pentium 4, Core 2 Duo and Core 2 Quad
      processors and Windows and Mac OSs so the results may not yet be
      sufficiently reprehensive for the comparisons to hold in general. I will
      probably post the test code for these tomorrow (or soonish) in case
      anyone wants to see if other hardware permutations contradict those
      results (or try it with other browsers/OSs).
      >
      Richard.
      Thanks for an exhaustive comparison.

      Unfortunately, prototype.js's $A is a general-purpose function. That's
      one of the reasons why it's slower than other alternatives. Besides
      converting arguments object into an array, it's often used to convert
      array-like objects (namely NodeList's) into actual arrays (by
      exploiting length property that NodeList's expose).

      $A is also used for delegating behavior to a passed object's toArray
      method if an object has one. Delegating allows to decouple concerns,
      as we know, so this pattern allows other data structures to define
      "toArray" containing its own logic.

      As an example, String.prototyp e.toArray is defined as:

      ....
      function() {
      return this.split('');
      }
      ....

      It would probably be wiser to use a separate function when converting
      arguments to an array, rather than relying on a "heavier" $A. We might
      consider this in later revisions.


      Best,

      --
      kangax

      Comment

      • dhtml

        #33
        Re: addEvent - The late entry :)

        On Jul 21, 6:33 pm, Lasse Reichstein Nielsen <l...@hotpop.co mwrote:
        "Richard Cornford" <Rich...@litote s.demon.co.ukwr ites:
        Function.protot ype.bind = function(obj){
          var args, fnc;
          if(arguments.le ngth 1){
            fnc = this;
            args = Array.prototype .slice.call(arg uments, 1);
        >
        This copies the arguments ...
        >
            return (function(){
              return fnc.apply(obj, args.push.apply (args, arguments));
        >
        ... and this push call changes the copy. I.e., every time
        the function is called, the args array is made larger.
        Also, the push function doesn't return the updated array.
        >

        Good point. push() will return a number. Passing a number as the
        second argument to Function.protot ype.apply would result in a
        TypeError -- Definitely not good for performance.

        concat returns a new Array. So do slice and splice.

        In this case, the concat function would probably be better, i.e.:
        >
        The change could be rolled back, e.g.:
              return function() {
                return fnc.apply(obj, args.concat(arg uments));
              }
        >
        But that would not work in the way that you want it o with an
        arguments object because arguments is not an array, so it would be
        added next in the list. Now if arguments were an array, it would work
        as desired, adding up all the items to the array. So it would be
        necessary to slice() it.

        Garrett
        /L

        Comment

        • dhtml

          #34
          Re: addEvent - The late entry :)

          On Jul 25, 12:46 am, dhtml <dhtmlkitc...@g mail.comwrote:
          On Jul 20, 1:37 am, Thomas 'PointedEars' Lahn <PointedE...@we b.de>
          wrote:
          >
          dhtml wrote:
          On Jul 19, 6:49 pm, "Aaron Gray" <ang.use...@gma il.comwrote:
          Could you provide a test case that demonstrates the issue, please?
          >
          I've added a test case below that adds callbacks for change, submit,
          and select events. The callbacks are added to an ancestor node. The
          example shows that the events DO NOT bubble in IE, just as the MSDN
          spec states.
          We can see that the events don't bubble in IE.
          I was wrong about the legacy events bubbling differently, but not
          about IE DOM Events. They don't bubble the same.
          >
          http://www.w3.org/TR/DOM-Level-2-Eve...nts-eventgroup...
          >
          | change
          | The change event occurs when a control loses the input focus and its
          | value has been modified since gaining focus. This event is valid for
          | INPUT, SELECT, and TEXTAREA. element.
          | Bubbles: Yes
          | Cancelable: No
          | Context Info: None
          |
          | submit
          | The submit event occurs when a form is submitted. This event only
          | applies to the FORM element.
          | Bubbles: Yes
          | Cancelable: Yes
          | Context Info: None
          >
          Both of these events should bubble.
          Moz and Safari: these events bubble when registered with
          addEventListene r.
          >
          IE: these events don't bubble
          >
          MSDN docs
           onchange:http://msdn.microsoft.com/en-us/libr...12(VS.85).aspx
           onsubmit:http://msdn.microsoft.com/en-us/library/ms536972.aspx
          >
          I'll post up an example tomorrow.
          Example:
          =============== =============== =============== =============== ======

          <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
          <html>
          <head>
          <titleChange </title>
          <style type="text/css">
          label { cursor: default; }
          </style>
          </head>

          <body>

          <h1>Form Dirty?</h1>

          <form action="">

          <fieldset id="ff"><legend >legend</legend>
          <select name='big'>
          <option disabled="disab led">disabled option</option>
          <option>one</option>
          <option>two</option>
          </select>

          <textarea name="a" cols="12" rows="1">foo</textarea>
          <label>
          <input type="radio" name="df" value="R1"/>radio
          </label>
          <label>
          <input type="radio" name="df" value="R2"/>radio
          </label>
          <input type="checkbox"/>
          <input type='text'/>
          <input type="password"/>
          <input type="submit" value="go"/>
          </fieldset>

          </form>

          <strong>attachE vent/addEventListene r</strong>
          <pre id='monitor'>



          </pre>
          <strong>legac y event</strong>
          <pre id='monitor2'>



          </pre>
          <script type="text/javascript">(fu nction(){
          var ff = document.getEle mentById('ff'),
          monitor = document.getEle mentById('monit or'),
          monitor2 = document.getEle mentById('monit or2');

          if(ff.addEventL istener) {
          ff.addEventList ener("change", getTimeStamp, false);
          document.addEve ntListener("sub mit", getTimeStamp, false);
          document.addEve ntListener("sel ect", getTimeStamp, false);
          } else if(ff.attachEve nt) {
          ff.attachEvent( "onchange", getTimeStamp);
          document.attach Event("onsubmit ", getTimeStamp);
          document.attach Event("onselect ", getTimeStamp);
          }

          ff.onchange = document.onsubm it = document.onsele ct = legacy;

          function getTimeStamp(e) {
          e = e || event;
          var tag = (e.target || e.srcElement);
          monitor.innerHT ML = "this = " + this.nodeName
          + "\ntarget: " + (tag.type || tag.nodeName)
          + "\ntype: " +(e.type + "\ntimestam p: " + e.timeStamp);
          }
          function legacy(e) {
          e = e || event;
          var tag = (e.target || e.srcElement);
          monitor2.innerH TML = "this = " + this.nodeName + "\n"
          + "target: " + (tag.type || tag.nodeName)
          + "\ntype: legacy on" + (e.type + "\ntimestam p: " + e.timeStamp);
          return false;
          }
          })();</script>
          </body>
          </html>

          =============== =============== =============== =============== ======

          By interacting with the example, it can be seen that the registered
          events do fire callbacks in MSIE. This is because these events don't
          bubble, and this is clearly stated on MSDN documentation links
          (provided).

          It can also be observed that the events will fire callbacks
          registered
          with useCapture=true , by changing the code to:

          ff.addEventList ener("change", getTimeStamp, true);
          document.addEve ntListener("sub mit", getTimeStamp, true);
          document.addEve ntListener("sel ect", getTimeStamp, true);

          Callbacks fire on bubbled event in: Opera9, Safari3, Firefox3, a bug
          in all 3 browsers.

          Garrett
          >
          PointedEars

          Comment

          • dhtml

            #35
            Re: addEvent - The late entry :)

            On Jul 25, 6:28 pm, dhtml <dhtmlkitc...@g mail.comwrote:
            On Jul 25, 12:46 am, dhtml <dhtmlkitc...@g mail.comwrote:
            On Jul 20, 1:37 am, Thomas 'PointedEars' Lahn <PointedE...@we b.de>
            wrote:
            dhtml wrote:
            By interacting with the example, it can be seen that the registered
            events do fire callbacks in MSIE.
            ^
            correction: do NOT fire callbacks in MSIE.

            Garrett
            >
            Garrett
            >
            >
            >
            PointedEars
            >
            >

            Comment

            • Richard Cornford

              #36
              Re: addEvent - The late entry :)

              Jorge wrote:
              On 24 jul, 02:44, Richard Cornford wrote:
              >At 20 arguments Windows Safari 3 executes that expression
              >in 48% of the time, and at zero arguments 47%. Mac Safari
              >2 was better, ranging from 16% with 20 arguments down to
              >34% with zero.
              >>
              >Opera 9.2 showed the next greatest performance change. 23%
              >at 20 arguments and 57% at zero.
              >IE 7 came next with 62% at 20 arguments and 81% at zero.
              >IE 6: 65% to 89%.
              >>
              >Firefox 2.0.4 was the worst I have tried to date. At 20
              >arguments it only manages 79% and was down to 85% by zero
              >arguments, but the actual execution time for the expression
              >(and all of the alternatives) was the longest of the group
              >tested on the same hardware (by at least a factor of 2) so
              >the actual gain in time saved was still greater than for some
              >of the better performing JS engines.
              >>
              >
              Now let's see who's got the balls to argue with Richard for
              having posted a benchmark... a *benchmark* !
              Your point being?
              Duh. And Safari wins one more time, again, as ever. LOL.
              <snip>

              That is not implied by anything that I posted. Even if one process runs
              in 16% of the time taken by another on some Safari browsers that does
              not mean that the time taken by either process was shorter then those
              exhibited by all other browsers.

              And where Mac Safari is concerned direct comparisons become extremely
              difficult due to the impossibility of running tests against IE on
              equivalent hardware. We can expect Mac Safari to be in a position to
              take advantage of low-level OS details unavailable to other browser
              manufacturers, in the same way as we can expect Windows IE to be in a
              position to take advantage of a similar understanding of Window OS
              details.

              Richard.

              Comment

              • Richard Cornford

                #37
                Re: addEvent - The late entry :)

                On Jul 24, 2:46 am, kangax wrote:
                On Jul 23, 8:44 pm, "Richard Cornford wrote:
                <snip>
                >... . I did my comparisons against Prototype.js's - $A -
                >function , ...
                <snip>
                >These were tests on a mixture of Pentium 4, Core 2 Duo and
                >Core 2 Quad processors and Windows and Mac OSs so the results
                >may not yet be sufficiently reprehensive for the comparisons
                >to hold in general. ...
                <snip>
                Thanks for an exhaustive comparison.
                Didn't I make the point that they were not exhaustive clearly enough?
                Unfortunately, prototype.js's $A is a general-purpose function.
                That's one of the reasons why it's slower than other alternatives.
                Besides converting arguments object into an array, it's often
                used to convert array-like objects (namely NodeList's) into
                actual arrays (by exploiting length property that NodeList's
                expose).
                What - $A - may or may not be is irrelevant to the question. The
                approach used in converting an - arguments - object into an array can be
                chosen at the point of needing to do it. There is no necessity to choose
                to use a general function to do it, and no reason for the changing of
                the approach used for converting - arguments - objects to arrays to
                impact on the - $A - function at all.
                $A is also used for delegating behavior to a passed object's
                toArray method if an object has one. Delegating allows to
                decouple concerns, as we know, so this pattern allows other
                data structures to define "toArray" containing its own logic.
                >
                As an example, String.prototyp e.toArray is defined as:
                >
                ...
                function() {
                return this.split(''); }
                >
                ...
                But we can be certain that - arguments - objects will not have -
                toArray - methods (unless they are explicitly assigned them).
                It would probably be wiser to use a separate function when
                converting arguments to an array, rather than relying on a
                "heavier" $A. We might consider this in later revisions.
                I did include a dedicated function in my tests (one that did little more
                than create a new array and loop over the 'array index' properties of
                its argument object copying values to corresponding properties of the
                new array). Inevitably it was a little faster than - $A - by virtue of
                doing less, but it was such a minimal difference that I would not regard
                it as worth consideration in comparison to the differences that some of
                the alternatives offer.

                At this point it is probably worth posting my test code. The following
                is a simple scripted HTML page. At the top there is a filed for entering
                the number of iterations to perform (which may need adjusting for
                particular browser/OS/hardware combinations). Generally, the number of
                iterations should be the most that any particular system will allow
                without putting up the 'A script on this page ... " dialog, and
                certainly large enough to make the total duration of _all_ the results
                greater than 300 milliseconds at (absolute) minimum (as the 10
                millisecond resolution of most browser timers would make shorter
                durations close to meaningless).

                There is a table at the bottom of the page into which the results are
                written, and a number of buttons ladled 'Test' to start to test process
                (which are disabled while the test runs). On of these buttons is under
                the output table at the bottom of the page. Individual loop runs are
                separated with - setTimeout - calls with long-ish intervals (to
                guarantee that the browser has time to catch up with any work it needs
                to do (including re-laying out the results table) and reduce the
                likelihood of seeing the "A Script on this page ..." dialog.

                The individual test functions are stored in an array of objects with the
                global identifier - fncts -. These object have - description - and -
                testFnc - properties, where - testFnc - is the function that executes
                the expression being tested. With the exception of the first item in
                this array (which is used to gauge the overheads involved in the test
                loop) items in this array may be removed, or alternatives added. Layout
                and overall test looping is driven from the length of this array. The
                last item in the array is the one against which comparisons are made and
                should be the one expected to be slowest.

                And array of argument sets with the global identifier - args - is used
                to demonstrate the impact of changing numbers of arguments on the
                process. The number of entries in this array can also be changed as the
                array length is used to drive that aspect of the test process. Also,
                currently all of the arguments are numeric literals. Other types of
                arguments may be tried to see whether that has an impact on performance
                (unlikely but not impossible).

                <html>
                <head>
                <title>arguemnt s to Array tests</title>
                <style type="text/css">
                TD.alRight {
                text-align:right;
                }
                </style>
                <script type="text/javascript">


                function $A(iterable) {
                if (!iterable) return [];
                if (iterable.toArr ay) return iterable.toArra y();
                var length = iterable.length || 0, results = new Array(length);
                while (length--) results[length] = iterable[length];
                return results;
                }
                function makeArray(itera ble) {
                var c, ar = [];
                if((c = iterable.length )){
                do{
                ar[--c] = iterable[c];
                }while(c)
                }
                return ar;
                }

                var args = [
                [1,2,3,4,5,6,7,8 ,9,10,11,12,13, 14,15,16,17,18, 19,20],
                [1,2,3,4,5,6,7,8 ,9,10,11,12,13, 14,15],
                [1,2,3,4,5,6,7,8 ,9,10],
                [1,2,3,4,5,6,7,8 ,9],
                [1,2,3,4,5,6,7,8],
                [1,2,3,4,5,6,7],
                [1,2,3,4,5,6],
                [1,2,3,4,5],
                [1,2,3,4],
                [1,2,3],
                [1,2],
                [1],
                []
                ];

                var argsIndex = 0;

                var frm = null;
                var fncts = [
                /* Timing of an "empty" loop to estimate the overheads of the
                test itself. */
                {
                testFnc:functio n(){
                return arguments;
                },
                description:'On ly overheads.'
                },
                {
                testFnc:functio n(){
                var ar = [];
                ar.push.apply(a r, arguments);
                return ar;
                },
                description:'pu sh.apply'
                },
                {
                testFnc:functio n(){
                var ar = [];
                ar.unshift.appl y(ar, arguments);
                return ar;
                },
                description:'un shift.apply'
                },
                {
                testFnc:functio n(){
                return (
                arguments.lengt h == 1)?
                [arguments[0]]:
                Array.apply(nul l, arguments
                );
                },
                description:'Ar ray.apply(null'
                },
                {
                testFnc:functio n(){
                return (
                arguments.lengt h == 1)?
                [arguments[0]]:
                Array.apply(thi s, arguments
                );
                },
                description:'Ar ray.apply(this'
                },
                {
                testFnc:functio n(){
                return Array.prototype .slice.call(arg uments, 0);
                },
                description:'sl ice.call'
                },
                {
                testFnc:functio n(){
                return Array.prototype .splice.call(
                arguments, 0, arguments.lengt h
                );
                },
                description:'sp lice.call'
                },
                {
                testFnc:functio n(){
                switch(argument s.length){
                case 0:
                return [];
                case 1:
                return [arguments[0]];
                default:
                return Array.apply(thi s, arguments);
                }
                },
                description:'sw itch'
                },
                {
                testFnc:functio n(){
                return makeArray(argum ents);
                },
                description:'ma keArray'
                },
                {
                testFnc:functio n(){
                return $A(arguments);
                },
                description:'$A '
                }
                ];

                function runTest(p){
                var lim = +frm['loopLimit'].value;
                var N, totTime, stTime;
                var obj = {};
                stTime = new Date().getTime( );
                for(var c = 0;c < lim;c++){
                N = fncts[p].testFnc.apply( this, args[argsIndex]);
                }
                totTime = (new Date().getTime( ) - stTime);
                frm["Dur"+p].value = totTime;
                frm["Avr"+p].value = (totTime/lim);
                frm["Res"+p].value = N;
                act(p+1);
                }

                var f;
                var running = false;
                function setButtons(bl){
                frm['loopLimit'].disabled = bl;
                var sw = frm['bt'];
                if(typeof sw.length == 'undefined'){
                sw = [sw];
                }
                for(var c = 0;c < sw.length;c++){
                sw[c].disabled = bl;
                }
                }
                function startTests(){
                if(!running){
                frm = document.forms['f'].elements;
                setButtons(true );
                frm["Dur0"].value = '';frm["Avr0"].value = '';
                for(var c = 1;c < fncts.length;c+ +){
                frm["Dur"+c].value = '';
                frm["Avr"+c].value = '';
                frm["Res"+c].value = '';
                }
                running = true;
                act(0);
                }
                }
                function act(p){
                /* setTimeout is used to minimise the occurrences
                of 'a script on this page is running slow' dialogs. */
                if(p >= fncts.length){
                ++argsIndex;
                if(argsIndex < args.length){
                setTimeout('rep ort();startTest s()',1000);
                }else{
                setTimeout('rep ort();argsIndex = 0;',1000);
                }
                }else{
                setTimeout(('(f = runTest('+p+')) ;'),2000);
                }
                }
                function report(){
                var co = ((argsIndex - 1)<<1)+1
                var emDur, unaC, diff1, diff2, c, evaC;
                var lim = +frm['loopLimit'].value;
                var row, tBody = document.getEle mentById('outBo dy');
                emDur = +frm["Dur0"].value;
                c = (fncts.length-1);
                row = tBody.rows[1+c];
                diff1 = (frm["Dur"+c].value - emDur); //if this is negative then
                //the whole test is invalid.
                if(diff1 < 0){
                // "Empty" loop longer than base test loop
                row.cells[co].innerHTML = '+++++++'
                return;
                }
                unaC = diff1 / lim;
                if(!unaC){
                row.cells[co].innerHTML = 'Loop too short';
                return;
                }
                row.cells[co].innerHTML = formatVal(100);
                row.cells[co+1].innerHTML = formatVal(unaC) ;
                for(c = 1;c < (fncts.length-1);c++){
                row = tBody.rows[1+c];
                diff2 = (frm["Dur"+c].value - emDur);
                if(diff2 < 0){
                //"Empty" loop longer than this test';
                row.cells[co].innerHTML = '*******'
                }else{
                evaC = diff2 / lim;
                row.cells[co].innerHTML = formatVal(((eva C/unaC)*100));
                row.cells[co+1].innerHTML = formatVal(evaC) ;
                }
                }
                tBody.rows[0].cells[0].innerHTML = (navigator.user Agent);
                tBody.rows[1].cells[0].innerHTML = ('Iterations = '+lim);
                setButtons(fals e);
                running = false;
                }
                function roundToR(X, R) { return Math.round(X*R)/R }
                function formatVal(n){
                if(isNaN(n)){
                return '------'
                }
                var s = String(roundToR (n, 10000));
                var ind;
                if((ind = s.indexOf('.')) < 0){
                s += '.';
                ind = s.length - 1;
                }
                s += '000'
                return s.substring(0, (ind+4));
                }
                </script>
                </head>
                <body>
                <div>
                <form name="f" action="#">
                Loop Length = <input type="text" value="80000"
                name="loopLimit "><br><br>


                <input type="button" value="Test" name="bt" onclick="startT ests();">
                Repeat tests to reduce/expose the influence of background tasks.
                <br><br>
                Empty Loop Duration (milliseconds) = <input type="text" value="X"
                name="Dur0"><br >
                Empty Loop Average (milliseconds) = <input type="text" value="X"
                name="Avr0" size="22"><br>
                (result = <input type="text" value="X" name="Res0" size="42">)<br>
                <br>

                <script type="text/javascript">
                var c, len = fncts.length;
                var st = ''
                for(c = 1;c < len;++c){
                st += '<br><code>'+fn cts[c].description;
                st += '</codeDuration (milliseconds) = ';
                st += '<input type="text" value="X" name="Dur'+c+'" ><br>';
                st += '<code>'+fncts[c].description;
                st += '</codeAverage (milliseconds) = ';
                st += '<input type="text" value="X" name="Avr'+c;
                st += '" size="22"><br>' ;
                st += '(result = <input type="text" value="X" name="Res'+c;
                st += '" size="42">)<br> ';
                }
                document.write( st);
                </script>

                <input type="button" value="Test" name="bt" onclick="startT ests();">
                Repeat tests to reduce/expose the influence of background tasks.
                <br><br>

                Average: (duration of test - duration of &quot;empty&quo t; loop)
                / loop length (Milliseconds)< br>

                <script type="text/javascript">
                var tdsOut = [''];
                tdsOut.toString = function(){
                return ('<td>'+this.jo in('<\/td><td class="alRight" >')+'<\/td>');
                }
                var rowsOut = [];
                rowsOut.toStrin g = function(){
                return ('<tr>'+this.jo in('<\/tr><tr>')+'<\/tr>');
                }
                var tableOut = [
                '<table border="2"><tbo dy id="outBody">' ,
                rowsOut,
                '<\/tbody><\/table>'
                ]

                //fncts.length // vertical
                //args.length){ //horezontal
                var c, d, len = fncts.length, dLen = args.length;
                var st = '<th><\/th>'
                for(d = 0;d < dLen;++d){
                st += '<th colspan="2">N<s up>o</supargs = ';
                st += args[d].length+'<\/th>'
                }
                rowsOut.push(st );
                for(d = 0;d < dLen;++d){
                tdsOut.push('%' );
                tdsOut.push('Av erage');
                }
                rowsOut.push(St ring(tdsOut));
                for(c = 1;c < len;++c){
                tdsOut.length = 0;
                tdsOut.push(c+' :'+fncts[c].description);
                for(d = 0;d < dLen;++d){
                tdsOut.push('') ;
                tdsOut.push('') ;
                }
                rowsOut.push(St ring(tdsOut));
                }
                document.write( tableOut.join(' '));
                </script>
                <br><br>
                <input type="button" value="Test" name="bt" onclick="startT ests();">
                Repeat tests to reduce/expose the influence of background tasks.
                <br><br>
                </form>
                </div>
                </body>
                </html>

                It may be observed that the process with the description - switch - is
                actually the fasted across the board. Suggesting that short-circuiting
                the process in the (probably common) case of having zero arguments is
                beneficial . However, I have not proposed this as the fasted approach
                because I was interested in a single expression that could replace the -
                $A(arguments) - expression, and - switch - is a statement not an
                expression. Moving the switch statement into a function and calling that
                in place of - $A - would add the function call overheads and so may
                negate its advantages (indeed a quick test of that in IE6 shows the
                function call overheads have that approach drop to 120% of - $A -
                performance at two arguments and it does not overtake - $A - again until
                the number of arguments gets up to 5).

                If the zero arguments case really is expected to be common then the
                expression:-

                (
                (!arguments.len gth)?
                []:
                (
                (arguments.leng th == 1)?
                [arguments[0]]:
                Array.apply(thi s, arguments)
                )
                )

                - might prove advantageous (performance-wise, otherwise it is getting
                too big/complex). Though it would still be possible to recognise the
                common case at the point of calling and so call a faster alternative
                instead and so avoid any need to be processing arguments object for that
                case.

                Richard.

                Comment

                • Jorge

                  #38
                  Re: addEvent - The late entry :)

                  On Jul 26, 5:18 pm, "Richard Cornford" <Rich...@litote s.demon.co.uk>
                  wrote:
                  Jorge wrote:
                  On 24 jul, 02:44, Richard Cornford wrote:
                  At 20 arguments Windows Safari 3 executes that expression
                  in 48% of the time, and at zero arguments 47%. Mac Safari
                  2 was better, ranging from 16% with 20 arguments down to
                  34% with zero.
                  >
                  Opera 9.2 showed the next greatest performance change. 23%
                  at 20 arguments and 57% at zero.
                  IE 7 came next with 62% at 20 arguments and 81% at zero.
                  IE 6: 65% to 89%.
                  >
                  Firefox 2.0.4 was the worst I have tried to date. At 20
                  arguments it only manages 79% and was down to 85% by zero
                  arguments, but the actual execution time for the expression
                  (and all of the alternatives) was the longest of the group
                  tested on the same hardware (by at least a factor of 2) so
                  the actual gain in time saved was still greater than for some
                  of the better performing JS engines.
                  >
                  Now let's see who's got the balls to argue with Richard for
                  having posted a benchmark... a *benchmark* !
                  >
                  Your point being?
                  That whenever I've posted here a benchmark showing that a certain code
                  runs x times faster in browser a than in browser b (in my machine)
                  they all jump on me saying that JS benchmarks are meaningless.
                  Duh. And Safari wins one more time, again, as ever. LOL.
                  >
                  <snip>
                  >
                  That is not implied by anything that I posted. Even if one process runs
                  in 16% of the time taken by another on some Safari browsers that does
                  not mean that the time taken by either process was shorter then those
                  exhibited by all other browsers.
                  >
                  Now I'm lost. Unless the trick here is in the word *all* other
                  browsers.
                  Certainly it was faster than *all* other browsers in which you've run
                  the test. Or not (?), and that info is useful.
                  And where Mac Safari is concerned direct comparisons become extremely
                  difficult due to the impossibility of running tests against IE on
                  equivalent hardware.
                  Boot the Mac (intel) in Windows.
                  We can expect Mac Safari to be in a position to
                  take advantage of low-level OS details unavailable to other browser
                  manufacturers,
                  Safari´s source code unlike IE's is open sourced. Darwin unlike
                  Windows is open sourced. So unless the code we're talking about was a
                  call to a Cocoa framework, that's impossible as there aren't any
                  "unavailabl e details".

                  And "expecting" that is being quite paranoic unless you discover
                  (studying the source code) the (highly unlikely) event that whenever
                  something runs faster in Safari it happens to be a call to propietary
                  code, as a Cocoa framework for example.
                  in the same way as we can expect Windows IE to be in a
                  position to take advantage of a similar understanding of Window OS
                  details.
                  That's not only possible, but very likely, as history has shown us
                  already.

                  --Jorge.

                  Comment

                  • Peter Michaux

                    #39
                    Re: addEvent - The late entry :)

                    On Jul 21, 9:47 pm, Peter Michaux <petermich...@g mail.comwrote:
                    On Jul 21, 2:37 pm, "Richard Cornford" <Rich...@litote s.demon.co.uk>
                    wrote:
                    >
                    [snip]
                    >
                    Function.protot ype.bind = function(obj){
                    var args, fnc;
                    if(arguments.le ngth 1){
                    fnc = this;
                    args = Array.prototype .slice.call(arg uments, 1);
                    >
                    [snip]
                    If I remember correctly, David Mark suggested he new of
                    an implementation where the above code would error. I use a loop to
                    accomplish the goal in the above line.
                    I'm cc'ing David about this.

                    David, am I remembering incorrectly?

                    Thanks,
                    Peter

                    Comment

                    • dhtml

                      #40
                      Re: addEvent - The late entry :)

                      On Jul 26, 8:18 am, "Richard Cornford" <Rich...@litote s.demon.co.uk>
                      wrote:
                      On Jul 24, 2:46 am, kangax wrote:
                      >
                      On Jul 23, 8:44 pm, "Richard Cornford wrote:
                      <snip>
                      ... . I did my comparisons against Prototype.js's - $A -
                      function , ...
                      <snip>
                      These were tests on a mixture of Pentium 4, Core 2 Duo and
                      Core 2 Quad processors and Windows and Mac OSs so the results
                      may not yet be sufficiently reprehensive for the comparisons
                      to hold in general. ...
                      <snip>
                      Thanks for an exhaustive comparison.
                      >
                      Didn't I make the point that they were not exhaustive clearly enough?
                      >
                      Unfortunately, prototype.js's $A is a general-purpose function.
                      That's one of the reasons why it's slower than other alternatives.
                      Besides converting arguments object into an array, it's often
                      used to convert array-like objects (namely NodeList's) into
                      actual arrays (by exploiting length property that NodeList's
                      expose).
                      >
                      And the fact that NodeList has been given numeric-named properties,
                      e.g
                      document.childN odes["0"]
                      What - $A - may or may not be is irrelevant to the question. The
                      approach used in converting an - arguments - object into an array can be
                      chosen at the point of needing to do it.
                      By choosing this approach, the overhead of an extra function call can
                      be avoided.

                      function getReversedChil dNodes(el) {
                      var kids = Array.prototype .slice.call(el. childNodes);
                      return kids.reverse();
                      }

                      >
                      But we can be certain that - arguments - objects will not have -
                      toArray - methods (unless they are explicitly assigned them).
                      >
                      For an arguments object, Array.prototype .slice.call(arg uments) inline
                      would be faster.
                      It would probably be wiser to use a separate function when
                      converting arguments to an array, rather than relying on a
                      "heavier" $A. We might consider this in later revisions.
                      >
                      I think it would be faster and clearer as to what the code is doing by
                      using an inline call.

                      Inline code would be fastest:

                      // Get the arguments as a real Array.
                      [].slice.call(arg uments).

                      It would be concise, simple, and easy to understand.

                      If the Array were needed from:

                      A string:
                      s.split('');

                      An arguments object:
                      Array.prototype .push.apply(arg uments);

                      An Array-like object:
                      Array.prototype .slice.call(nod eList);

                      A native ecmascript object:
                      var r = [];
                      for(var p in o) r.push(o[p]);

                      The requirements of Prototype.js is that the $A function convert an
                      array-like object into an Array. (array-like - has sequential numeric
                      properties and a length property).

                      Function.protot ype.apply requires the second argument to be an Array
                      or arguments object. Using push.apply() or unshift.apply as a
                      replacement in $A would impose a new restriction that will probably
                      break existing code in or using Prototype.js.

                      A generalized approach would not be able to differentiate an arguments
                      object from a NodeList, so that would reduce the switch to: A string,
                      an Array-like object.

                      The potential value of creating an abstraction for an object that has
                      a specific toArray seems to be only that there are different types of
                      objects that can be converted to an array in different ways.

                      Enumerable has a toArray:-

                      toArray -map -each, with n calls to iterator/Prototype.K, which
                      returns the item. It is a long string of function calls. The "Write a
                      Loop Once" Pattern is powerful, when needed. It can also be used in a
                      template pattern, and a Template pattern can also use other types of
                      iteration, such as setInterval.

                      map is just an alias to collect:

                      collect: function(iterat or, context) {
                      iterator = iterator ? iterator.bind(c ontext) : Prototype.K;
                      var results = [];
                      this.each(funct ion(value, index) {
                      results.push(it erator(value, index));
                      });
                      return results;
                      }

                      If there is no iterator function, and if the each function is simply a
                      Mapper that calls the iterator function, then it would be much more
                      efficient to simply return the object as an array.

                      However, for other needs, if a unique mapper function is desired, then
                      the Array extras can be used on the object after converting it to an
                      Array (which can also be sorted, et c). This has the benefit of using
                      the standard built-in Array.

                      Why is toArray called in $A? The only benefit would seem to be with:

                      A native ecmascript object:
                      var r = [];
                      for(var p in o) r.push(o[p]);

                      Which is something that is seen in Hash._each:-

                      _each: function(iterat or) {
                      for (var key in this._object) {
                      var value = this._object[key], pair = [key, value];
                      pair.key = key;
                      pair.value = value;
                      iterator(pair);
                      }
                      },

                      Where the iterator takes a "pair" type object that is an array with
                      key and value properties. The Hash object's prototype chain is also
                      enumerated over, which seems undesirable and unexpected, as far as a
                      HashMap type of functionality goes.

                      Iteration abstractions are powerful but not always needed. The costs
                      are complexity (especially in PrototypeJS) and performance.

                      I would not mind a native Array.fromArray Like(obj) in a newer version
                      of ES, but it doesn't seem necessary to me. Mountains out of
                      molehills.

                      It's nice out. That will be all for today!


                      Garrett


                      Comment

                      • Peter Michaux

                        #41
                        Re: addEvent - The late entry :)

                        On Jul 26, 5:07 pm, Peter Michaux <petermich...@g mail.comwrote:
                        On Jul 21, 9:47 pm, Peter Michaux <petermich...@g mail.comwrote:
                        >
                        On Jul 21, 2:37 pm, "Richard Cornford" <Rich...@litote s.demon.co.uk>
                        wrote:
                        >
                        [snip]
                        >
                        Function.protot ype.bind = function(obj){
                        var args, fnc;
                        if(arguments.le ngth 1){
                        fnc = this;
                        args = Array.prototype .slice.call(arg uments, 1);
                        >
                        [snip]
                        >
                        If I remember correctly, David Mark suggested he new of
                        an implementation where the above code would error. I use a loop to
                        accomplish the goal in the above line.
                        >
                        I'm cc'ing David about this.
                        >
                        David, am I remembering incorrectly?
                        David replied to me

                        "Yes. DOM node collections throw exceptions on slice, not arguments."

                        ECMA-262 3rd 15.4.4.10

                        "The slice function is intentionally generic; it does not require that
                        its this value be an Array object. Therefore it can be transferred to
                        other kinds of objects for use as a method. Whether the slice function
                        can be applied successfully to a host object is implementation-
                        dependent."

                        Peter

                        Comment

                        • dhtml

                          #42
                          Re: addEvent - The late entry :)

                          On Jul 26, 5:11 pm, dhtml <dhtmlkitc...@g mail.comwrote:
                          On Jul 26, 8:18 am, "Richard Cornford" <Rich...@litote s.demon.co.uk>
                          wrote:
                          >
                          >
                          >
                          On Jul 24, 2:46 am, kangax wrote:
                          >
                          On Jul 23, 8:44 pm, "Richard Cornford wrote:
                          <snip>
                          >... . I did my comparisons against Prototype.js's - $A -
                          >function , ...
                          <snip>
                          >These were tests on a mixture of Pentium 4, Core 2 Duo and
                          >Core 2 Quad processors and Windows and Mac OSs so the results
                          >may not yet be sufficiently reprehensive for the comparisons
                          >to hold in general. ...
                          <snip>
                          Thanks for an exhaustive comparison.
                          >
                          Didn't I make the point that they were not exhaustive clearly enough?
                          >
                          Unfortunately, prototype.js's $A is a general-purpose function.
                          That's one of the reasons why it's slower than other alternatives.
                          Besides converting arguments object into an array, it's often
                          used to convert array-like objects (namely NodeList's) into
                          actual arrays (by exploiting length property that NodeList's
                          expose).
                          >
                          And the fact that NodeList has been given numeric-named properties,
                          e.g
                          document.childN odes["0"]
                          >
                          What - $A - may or may not be is irrelevant to the question. The
                          approach used in converting an - arguments - object into an array can be
                          chosen at the point of needing to do it.
                          >
                          By choosing this approach, the overhead of an extra function call can
                          be avoided.
                          >
                          function getReversedChil dNodes(el) {
                            var kids = Array.prototype .slice.call(el. childNodes);
                            return kids.reverse();
                          >
                          }
                          >
                          But we can be certain that - arguments - objects will not have -
                          toArray - methods (unless they are explicitly assigned them).
                          >
                          For an arguments object, Array.prototype .slice.call(arg uments) inline
                          would be faster.
                          >
                          It would probably be wiser to use a separate function when
                          converting arguments to an array, rather than relying on a
                          "heavier" $A. We might consider this in later revisions.
                          >
                          I think it would be faster and clearer as to what the code is doing by
                          using an inline call.
                          >
                          Inline code would be fastest:
                          >
                          // Get the arguments as a real Array.
                          [].slice.call(arg uments).
                          >
                          It would be concise, simple, and easy to understand.
                          >
                          If the Array were needed from:
                          >
                          A string:
                            s.split('');
                          >
                          An arguments object:
                            Array.prototype .push.apply(arg uments);
                          >
                          Would have to be:-
                          var a = [];
                          a.push.apply(a, arguments);


                          Example:-
                          var argsIsArray = (function(){

                          var a = [];
                          a.push.apply(a, arguments);
                          return a;

                          })(1,2,3).const ructor === Array;

                          alert(argsIsArr ay);

                          "true"
                          Garrett

                          Comment

                          • Richard Cornford

                            #43
                            Re: addEvent - The late entry :)

                            Peter Michaux wrote:
                            On Jul 26, 5:07 pm, Peter Michaux wrote:
                            >On Jul 21, 9:47 pm, Peter Michaux wrote:
                            >>On Jul 21, 2:37 pm, Richard Cornford wrote:
                            <snip>
                            >>>Function.pro totype.bind = function(obj){
                            >>> var args, fnc;
                            >>> if(arguments.le ngth 1){
                            >>> fnc = this;
                            >>> args = Array.prototype .slice.call(arg uments, 1);
                            >>
                            >[snip]
                            >>
                            >>If I remember correctly, David Mark suggested he new of
                            >>an implementation where the above code would error.
                            >>I use a loop to accomplish the goal in the above line.
                            >>
                            >I'm cc'ing David about this.
                            >>
                            >David, am I remembering incorrectly?
                            >
                            David replied to me
                            >
                            "Yes. DOM node collections throw exceptions on slice,
                            not arguments."
                            >
                            ECMA-262 3rd 15.4.4.10
                            <snip>
                            ... . Whether the slice function can be applied successfully
                            to a host object is implementation-dependent."
                            I suspected that if there had been an example of an implementation with
                            an issue handling arguments object then that would have come to my
                            attention by now.

                            (Incidentally, I do intend responding to your last substantial response
                            to me in this thread. I have started writing that response but I don't
                            think I will have time to finish it tonight.)

                            Richard.

                            Comment

                            • Richard Cornford

                              #44
                              Re: addEvent - The late entry :)

                              dhtml wrote:
                              >On Jul 26, 8:18 am, Richard Cornford wrote:
                              <snip>
                              >What - $A - may or may not be is irrelevant to the question.
                              >The approach used in converting an - arguments - object into
                              >an array can be chosen at the point of needing to do it.
                              >
                              By choosing this approach, the overhead of an extra function
                              call can be avoided.
                              >
                              function getReversedChil dNodes(el) {
                              var kids = Array.prototype .slice.call(el. childNodes);
                              return kids.reverse();
                              }
                              Why don't you see that it is superfluous to respond to me asserting the
                              very thing that I not only have already suggested but gong to some
                              effort to ascertain the truth of?

                              <snip - more pointless noise>

                              It's nice out. That will be all for today!

                              Ah, doing something smart for a change.

                              Richard.

                              Comment

                              • Richard Cornford

                                #45
                                Re: addEvent - The late entry :)

                                Jorge wrote:
                                On Jul 26, 5:18 pm, Richard Cornford wrote:
                                >Jorge wrote:
                                >>On 24 jul, 02:44, Richard Cornford wrote:
                                >>>At 20 arguments Windows Safari 3 executes that
                                >>>expression in 48% of the time, and at zero arguments
                                >>>47%. Mac Safari 2 was better, ranging from 16% with
                                >>>20 arguments down to 34% with zero.
                                >>
                                >>>Opera 9.2 showed the next greatest performance change.
                                >>>23% at 20 arguments and 57% at zero. IE 7 came next
                                >>>with 62% at 20 arguments and 81% at zero. IE 6: 65%
                                >>>to 89%.
                                >>
                                >>>Firefox 2.0.4 was the worst I have tried to date. At
                                >>>20 arguments it only manages 79% and was down to 85%
                                >>>by zero arguments, but the actual execution time for
                                >>>the expression (and all of the alternatives) was the
                                >>>longest of the group tested on the same hardware (by
                                >>>at least a factor of 2) so the actual gain in time
                                >>>saved was still greater than for some of the better
                                >>>performing JS engines.
                                >>
                                >>Now let's see who's got the balls to argue with Richard
                                >>for having posted a benchmark... a *benchmark* !
                                >>
                                >Your point being?
                                >
                                That whenever I've posted here a benchmark showing that a
                                certain code runs x times faster in browser a than in
                                browser b (in my machine) they all jump on me saying that
                                JS benchmarks are meaningless.
                                On the 3GHz 4 core CPU I used for some of the tests differences in the
                                durations of single operations was tenths of a nanosecond, and on an OS
                                that does not necessarily report the time with a precision of better
                                than +/- 10 milliseconds. It is trivially easy to undertake such a test
                                and come up with results that are meaningless (and/or misleading).

                                It is meaningless to post numbers in isolation. It is important to say
                                how those numbers were obtained, what they are supposed to mean, how
                                they show that meaning and that the numbers are reported in reality. To
                                which end it is a very good idea to post a demonstration page that will
                                demonstrate the method and facilitate third party verification of the
                                results.
                                >>Duh. And Safari wins one more time, again, as ever. LOL.
                                >>
                                ><snip>
                                >>
                                >That is not implied by anything that I posted. Even if
                                >one process runs in 16% of the time taken by another on
                                >some Safari browsers that does not mean that the time
                                >taken by either process was shorter then those exhibited
                                >by all other browsers.
                                >>
                                >
                                Now I'm lost. Unless the trick here is in the word *all*
                                other browsers.
                                The word 'all' is their following consideration. I did state that
                                Firefox was slower in these tests than any other browser tested on the
                                same hardware/OS combination, and so implied it was slower than Safari
                                (which it was). But being faster than Firefox is not the same as being
                                fastest.
                                Certainly it was faster than *all* other browsers in which
                                you've run the test. Or not (?), and that info is useful.
                                No. In reality Opera 9.20 and Windows Safari 3 tested on the same box
                                running the same OS reported vary similar durations for the various
                                expressions tested. For some Safari was fractionally ahead and for
                                others Opera was ahead. Safari, for some reason, singled out -
                                Array.prototype .splice.call(ar guments, 0, arguments.lengt h) - for
                                particularly bad performance (worse than - $A(arguments) - with more
                                than about 6 arguments and getting worse as the number of arguments
                                increased, while Opera showed that expression to be between ~50% and
                                ~35% better than - $A(arguments) - at zero and 20 arguments
                                respectively.
                                >And where Mac Safari is concerned direct comparisons become
                                >extremely difficult due to the impossibility of running tests
                                >against IE on equivalent hardware.
                                >
                                Boot the Mac (intel) in Windows.
                                And would that be the same hardware? The box may contain the same
                                hardware but what was being used in what way by each operating system
                                would be difficult to know. Imagine, for example, on OS using a generic
                                hardware drives while the other fully exploited the capabilities of a
                                dedicated driver.
                                >We can expect Mac Safari to be in a position to take
                                >advantage of low-level OS details unavailable to other browser
                                >manufacturer s,
                                >
                                Safari´s source code unlike IE's is open sourced. Darwin
                                unlike Windows is open sourced. So unless the code we're
                                talking about was a call to a Cocoa framework, that's
                                impossible as there aren't any "unavailabl e details".
                                OK, not unavailable, but unlikely to as obvious to the readers of open
                                source code than they are to its authors. Details hide well among very
                                large collections of similar details.
                                And "expecting" that is being quite paranoic
                                The word is 'cynical', and I am.
                                unless you discover (studying the source code) the (highly
                                unlikely) event that whenever something runs faster in Safari
                                it happens to be a call to propietary code, as a Cocoa
                                framework for example.
                                Ah, so heaven forbid a corporation might ever use inside information to
                                help negotiate itself into a monopoly position.
                                >in the same way as we can expect Windows IE to be in a
                                >position to take advantage of a similar understanding of
                                >Window OS details.
                                >
                                That's not only possible, but very likely, as history has
                                shown us already.
                                So you are saying that Microsoft have already done this thing but Apple
                                never would even if they could? You have not understood capitalism.

                                Richard.

                                Comment

                                Working...