From: Antony Scriven on
On Apr 2, 7:02 pm, Thomas 'PointedEars' Lahn wrote:

> Lasse Reichstein Nielsen wrote:
> > Thomas 'PointedEars' Lahn <PointedE...(a)web.de> writes:
> > > 2. Several function calls will be always more
> > > expensive than just one and the creation of an
> > > Array instance.
> >
> > That's not a given.
> >
> > It's possible that four function calls take longer than
> > creating an Array and calling one function that loops
> > over the array and extracts the elements again
> > (possible, but not given), but the latter also
> > allocates space for the array. If this happens often
> > enough, the memory overhead will also cause earlier
> > garbage collection.
>
> That argument is dubious and the tests have no meaning
> because the function argument in chaining may be an Array
> or Object reference anyway. Incidentally, that is what
> can be observed in current general-purpose libraries that
> use chaining.
>
> You are correct that cost is not merely measured in
> runtime spent. However, you are ignoring here that for,
> say, ten registrations I would need ten chained function
> calls, or only one function call with an Array instance
> of length 10. There can be no doubt that the chaining
> grows more inefficient than the alternatives with each
> registration. With 1000 registrations I would still need
> only one Array instance or 1000 items to iterate over,
> instead of 1000 calls to be made.

And if, on average, the OP has only four registrations, what
then? For the OP's specific case, theorising is pointless.
I'm not saying you should entirely ignore performance
considerations, and I do find Lasse's tests interesting, but
optimisation should always be based on hard evidence,
specific to the application. And remember The First Rule of
Performance Optimisation: don't. --Antony
From: Lasse Reichstein Nielsen on
Thomas 'PointedEars' Lahn <PointedEars(a)web.de> writes:

> Lasse Reichstein Nielsen wrote:
>
>> Thomas 'PointedEars' Lahn <PointedEars(a)web.de> writes:
>>> 2. Several function calls will be always more expensive than just one
>>> and the creation of an Array instance.
>>
>> That's not a given.
>>
>> It's possible that four function calls take longer than creating an Array
>> and calling one function that loops over the array and extracts the
>> elements again (possible, but not given), but the latter also allocates
>> space for the array. If this happens often enough, the memory overhead
>> will also cause earlier garbage collection.
>
> That argument is dubious and the tests have no meaning because the function
> argument in chaining may be an Array or Object reference anyway.

That is irrelevant. If you create more objects, but do so in both
cases, then it will just reduce the impact of the difference, but not
eliminate it.

> Incidentally, that is what can be observed in current general-purpose
> libraries that use chaining.

I won't argue against that without knowing the quality of code of
those projects (but I'll wager a guess and assume that bad code
could be blamed for most of their performance characteristics).

> You are correct that cost is not merely measured in runtime spent.

Any other cost, e.g., memory allocation, generally shows up in runtime
as well.

> However, you are ignoring here that for, say, ten registrations I would
> need ten chained function calls, or only one function call with an Array
> instance of length 10.

This is not about chaining. Chaining may or may not cause an overhead
compared to directly calling, but chaining wasn't mentioned in the
point I'm arguing against.

And as to the number of calls/length of the array, I'm not ignoring
it. I show that for the case where the number is four, the point
("... will always be more expensive than ...") doesn't hold.
I believe it will hold for larger numbers too, and I'm willing to test
it.

> There can be no doubt that the chaining grows more
> inefficient than the alternatives with each registration. With 1000
> registrations I would still need only one Array instance or 1000 items to
> iterate over, instead of 1000 calls to be made.

The overhead of creating the array will be reduced compared to the case
with fewer calls, but the cost of populating the array won't, nor will
the cost of iterating over it and extracting the values again. Those
are expensive memory accesses, compared to stack allocated function
arguments.

But again, I'm willing to test it: Is there number of calls where
creating the array is faster. It's not obvious that there is, nor is
it obvious that there isn't.

> I find it particularly dubious that you have not noticed that the length of
> the effective prototype chain can be an important factor regarding
> efficiency. setChained() is an instance method with a short effective
> prototype chain, setProp() and setProps() are prototype methods with longer
> ones.

That is a good point. While it's the natural implementation of each of
these strategies, it does give a natural difference in the time of a single
method call (a quick test shows the difference to be marginal in Opera
and Chrome, and quite significant in Firefox).

> I also don't see you considering that the chaining approach needs at
> least one Function object more than the non-chaining one in your example.

It needs one function per instance, which is significant.
However, my main point was not about chaining (which I'm not convinced
is a win compared to diret calls), but purely against the notion that
passing an array of arguments in one call is always faster than doing
multiple calls.

> All in all, I don't think your argument or test holds water.

Which test would?

I tried making another one, ignoring chaining for now, since it's not
part of the point I'm trying to make:
http://www.infimum.dk/privat/testcallvsarray.html

There does seem to be a point where using a single call with an array
is faster than doing separate calls. For Opera it is around *2000*
calls[1]. I'm wagering that counts as a very rare use case.

So, the point is that:
"Several function calls will be always more expensive than just one
and the creation of an Array instance."
is wrong. For such an absolute statement, it might not be surprising that
there is a counter example. However, it seems that for *any* reasonable
number of calls, calling is faster than building an array of arguments
and passing them in one go - in most browsers [2].
After testing, it seems that it's only the case in very
very rare cases.

/L "Function calls aren't slow. 'nuff said"

[1] Firefox is weird: An Array of length 2000 is *slower* than one
of length 3000!
[2] Just checked Safari. It's actually slightly faster with the array.
--
Lasse Reichstein Holst Nielsen
'Javascript frameworks is a disruptive technology'

From: Richard Cornford on
On Apr 1, 4:38 pm, Thomas Allen wrote:
> On Apr 1, 6:56 am, Richard Cornford wrote:
>> On Apr 1, 12:10 am, nick wrote:
>>> To me something like
>>> this is easily understandable, if a bit esoteric:
>
>>> Cufon('h1')('h2')('h3');
>
>> Looking at this code itself we see a call to (what is assumed
>> to be) a function, and then a call to whatever is returned
>> from that first call, and then a call to whatever is returned
>> from that. We might also observe a similarity in the arguments.
>
>> That is all the information available in the code. In order to
>> determine that this actually represents three calls to the same
>> function it will be necessary to find the code for a - Cufon -
>> definition, or the code for whatever function is assigned to
>> - Cufon - at any given time. Otherwise (even if 'Cfon' were
>> instead an Identifier that described what the function did)
>> the nature/process of the second and third function calls
>> remains unknown. It is not even hinted at by the code above,
>> and that is an objective fact.
>
> To be fair, I think that code intended for other developers' use
> should be well-documented.

Fair enough, you might not have to go to the code for - Cufon -,
instead you could go to the documentation (assuming it actually was
good enough).

> So, in my opinion, your concern about the "nature/process of
> the second and third function calls" is unwarranted, provided
> that the function's return value (and usage too, given the
> bizarre operation nick wants) is explained adequately.

My concern here is only with how much understanding can be derived
from the source code itself. For that it makes no real difference if
understanding is only available through reference to documentation or
only through reference to other source code, what is significant is
that the code above is not saying what it is doing when it could be.

If maintenance is where most software development resources are spent
(as is frequently attested) strategies that ease maintenance can be
disproportionately advantageous (over, say, strategies that easy
initial code entry/typing). Writing directly understandable (even self-
documenting) source code is one such strategy, particularly for the
top level code that employs pre-built APIs (and the like).

Richard.