Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Splicing exercise

10 views
Skip to first unread message

Csaba Gabor

unread,
Oct 19, 2009, 3:44:43 PM10/19/09
to
I'd like to write a
function insertArray(a1, a2, pos) { ... }
which will splice the a2.length elements of array a2 into array a1
starting at index position pos, and return the resultant array.

What is a "shortest" javascript function to do this?
Assume that you don't have to worry about error checking,
and that pos is an integer such that 0 <= pos <= a1.length
Can it be (semi reasonably) done as a single return statement?

Csaba Gabor from Vienna

Thomas 'PointedEars' Lahn

unread,
Oct 19, 2009, 4:12:23 PM10/19/09
to
Csaba Gabor wrote:

> I'd like to write a
> function insertArray(a1, a2, pos) { ... }
> which will splice the a2.length elements of array a2 into array a1
> starting at index position pos, and return the resultant array.
>
> What is a "shortest" javascript function to do this?

Is this a trick question?

PointedEars
--
Anyone who slaps a 'this page is best viewed with Browser X' label on
a Web page appears to be yearning for the bad old days, before the Web,
when you had very little chance of reading a document written on another
computer, another word processor, or another network. -- Tim Berners-Lee

VK

unread,
Oct 19, 2009, 4:33:48 PM10/19/09
to

I would rather to propose to your students to write a List data type
emulator. It could be a very good exercise on slice and splice methods
- this is what you are giving them right now, right? The final code
with errors correction can be found at my "List data type"
http://groups.google.com/group/comp.lang.javascript/msg/19ac11e0164d8ab4

Your question is a minor case of that and the solution is:

a1 = [1,2,3];
a2 = [10,20,30];

insertArray(a1,a2,1);

window.alert(a1);

function insertArray(a1, a2, pos) {
a1.splice(pos, 0, a2);
}

there is no need to return anything as it needlessly complicates the
code. If one still needs to create a new array then
a1.splice(pos, 0, a2);
return a1.slice(0);


Thomas 'PointedEars' Lahn

unread,
Oct 19, 2009, 4:41:10 PM10/19/09
to
VK wrote:

> function insertArray(a1, a2, pos) {
> a1.splice(pos, 0, a2);
> }
>
> there is no need to return anything as it needlessly complicates the
> code.

Nonsense. Returning the return value of a1.splice(...), which would only
"complicate the code" by 7 characters, would make the function insertArray()
more flexible in use.


PointedEars
--
Danny Goodman's books are out of date and teach practices that are
positively harmful for cross-browser scripting.
-- Richard Cornford, cljs, <cife6q$253$1$8300...@news.demon.co.uk> (2004)

VK

unread,
Oct 19, 2009, 4:51:16 PM10/19/09
to
On Oct 20, 12:41 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> Nonsense.  Returning the return value of a1.splice(...), which would only
> "complicate the code" by 7 characters, would make the function insertArray()
> more flexible in use.

Tommy, I feel like it's really time to you to go to bed and start
tomorrow with a fresh head.
For sweeter dreams please check the return value of array's splice
method.

Thomas 'PointedEars' Lahn

unread,
Oct 19, 2009, 5:08:40 PM10/19/09
to
VK wrote:

> Thomas 'PointedEars' Lahn wrote:
>> Nonsense. Returning the return value of a1.splice(...), which would only
>> "complicate the code" by 7 characters, would make the function
>> insertArray() more flexible in use.
>
> Tommy,

Oh shut up!

> I feel like it's really time to you to go to bed and start
> tomorrow with a fresh head.

Mirror, mirror ...

> For sweeter dreams please

I said shut up.

> check the return value of array's splice method.

I know what it returns (since JavaScript 1.2), thank you very much.
Apparently you don't.


PointedEars
--
realism: HTML 4.01 Strict
evangelism: XHTML 1.0 Strict
madness: XHTML 1.1 as application/xhtml+xml
-- Bjoern Hoehrmann

Csaba Gabor

unread,
Oct 19, 2009, 5:49:55 PM10/19/09
to
On Oct 19, 10:12 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> Csaba Gabor wrote:
> > I'd like to write a
> > function insertArray(a1, a2, pos) { ... }
> > which will splice the a2.length elements of array a2 into array a1
> > starting at index position pos, and return the resultant array.
>
> > What is a "shortest" javascript function to do this?
>
> Is this a trick question?

It wasn't meant to be. However, insertArray should
produce an array of length a1.length + a2.length,
which does not happen with VK's example.

Csaba Gabor

unread,
Oct 19, 2009, 6:08:56 PM10/19/09
to
On Oct 19, 10:33 pm, VK <schools_r...@yahoo.com> wrote:
> On Oct 19, 11:44 pm, Csaba  Gabor <dans...@gmail.com> wrote:
>
> > I'd like to write a
> > function insertArray(a1, a2, pos) { ... }
> > which will splice the a2.length elements of array a2 into array a1
> > starting at index position pos, and return the resultant array.
>
> > What is a "shortest" javascript function to do this?
> > Assume that you don't have to worry about error checking,
> > and that pos is an integer such that 0 <= pos <= a1.length
> > Can it be (semi reasonably) done as a single return statement?
>
> I would rather to propose to your students to write a List data type
> emulator. It could be a very good exercise on slice and splice methods
> - this is what you are giving them right now, right? The final code

No, I am not teaching. I encountered this issue today on
a project I'm working on, and thought I'd share.

> with errors correction can be found at my "List data type"
>  http://groups.google.com/group/comp.lang.javascript/msg/19ac11e0164d8ab4
>
> Your question is a minor case of that and the solution is:
>
> a1 = [1,2,3];
> a2 = [10,20,30];
>
> insertArray(a1,a2,1);
> window.alert(a1);
>
> function insertArray(a1, a2, pos) {
>  a1.splice(pos, 0, a2);
> }
>
> there is no need to return anything as it needlessly complicates the
> code. If one still needs to create a new array then
>  a1.splice(pos, 0, a2);
>  return a1.slice(0);

VK, my requested insertArray is meant to "imitate" PHP's
http://php.net/array_splice in that the second array's
*elements* are to be spliced in, rather than the array
itself. Specifically, the array that insertArray returns
should have a1.length + a2.length elements, and not
1 + a1.length as with your example. If this is confusing,
replace your window.alert with window.alert(a1.join(" ** "))
and you'll see what I mean.

Thomas 'PointedEars' Lahn

unread,
Oct 19, 2009, 6:02:53 PM10/19/09
to
Csaba Gabor wrote:

> Thomas 'PointedEars' Lahn wrote:
>> Csaba Gabor wrote:
>> > I'd like to write a
>> > function insertArray(a1, a2, pos) { ... }
>> > which will splice the a2.length elements of array a2 into array a1
>> > starting at index position pos, and return the resultant array.
>>
>> > What is a "shortest" javascript function to do this?
>>
>> Is this a trick question?
>
> It wasn't meant to be. However, insertArray should
> produce an array of length a1.length + a2.length,
> which does not happen with VK's example.

True. So, what have *you* tried?


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$8300...@news.demon.co.uk>

VK

unread,
Oct 19, 2009, 6:29:07 PM10/19/09
to
On Oct 20, 1:49 am, Csaba Gabor <dans...@gmail.com> wrote:
> It wasn't meant to be.  However, insertArray should
> produce an array of length a1.length + a2.length,
> which does not happen with VK's example.

Of course, because it adds a2 array object as one member, not all a2
elements separately. The rest of coding, especially to have it as a
single return statement, would require the "SqueeseCrypt" coding style
which I hate a lot. In my strong opinion 2,3,4... separate statements
are better than a single statement cryptic mess: even if it's "cool"
looking. It is especially bad on the initial learning stage because
besides other things it plants the false idea into students' heads
that "lesser lines == better program". All this IMHO and nevertheless:

function insertArray(a1, a2, pos) {
return (new Array(a1.splice(pos, 0, a2), a1)).slice(1);
}


Message has been deleted

Thomas 'PointedEars' Lahn

unread,
Oct 19, 2009, 7:03:30 PM10/19/09
to
VK wrote:

> Csaba Gabor wrote:
>> It wasn't meant to be. However, insertArray should
>> produce an array of length a1.length + a2.length,
>> which does not happen with VK's example.
>
> Of course, because it adds a2 array object as one member, not all a2
> elements separately.

Which is not even remotely what the OP asked for. You get an "F".

> The rest of coding, especially to have it as a
> single return statement, would require the "SqueeseCrypt" coding style
> which I hate a lot. In my strong opinion

... which is worthless as usual as it is evidently not based on logical
thinking but on made-up bedtime stories ...

> 2,3,4... separate statements
> are better than a single statement cryptic mess: even if it's "cool"
> looking.

Or more efficient to no foreseeable disadvantage?

> It is especially bad on the initial learning stage because
> besides other things it plants the false idea into students' heads
> that "lesser lines == better program".

Nobody who has posted in this thread is teaching students. Got it?

> All this IMHO and nevertheless:
>
> function insertArray(a1, a2, pos) {
> return (new Array(a1.splice(pos, 0, a2), a1)).slice(1);
> }

That still creates an array consisting of four elements (instead of the
specified six) -- [1, [10, 20, 30], 2, 3] -- for the posted test case.

So much for testing before posting, and labelling untested code, Often
Wrong.

VK

unread,
Oct 19, 2009, 7:30:44 PM10/19/09
to
On Oct 20, 3:03 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> So much for testing before posting, and labelling untested code, Often
> Wrong.

Yes, yes, our Always Right one :) If you really got an insomnia (I am
fine with my rather early evening) you might try the previous task
with \00100-\uFFFD case insensitive pattern.

To OP:
As I said earlier I hate SqueeseCrypt'ing and respectively hate the
very look of it below instead of nicely followed separate
statements :), but if it would be a do-or-die task to have a single
return statement then:

a1 = [0,1,2];
a2 = ['a','b','c'];
a3 = insertArray(a1,a2,1);
window.alert(a3.length);
window.alert(a3);

function insertArray(a1, a2, pos) {
return [a1.splice(pos,0,a2),a1].pop().toString().split(',');
}

Johannes Baagoe

unread,
Oct 19, 2009, 7:35:06 PM10/19/09
to
Csaba Gabor :

Perhaps this ?

function insertArray(a1, a2, pos) {
return a1.slice(0, pos).concat(a2, a1.slice(pos, a1.length));
}

--
Johannes

Thomas 'PointedEars' Lahn

unread,
Oct 19, 2009, 7:54:52 PM10/19/09
to
VK wrote:

> Thomas 'PointedEars' Lahn wrote:
>> So much for testing before posting, and labelling untested code, Often
>> Wrong.
>
> Yes, yes, our Always Right one :) If you really got an insomnia (I am
> fine with my rather early evening)

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
As your replying at 03:30 (your local time, 01:30 my local time) clearly
indicates ...

(You're such a *lousy* liar.)

> you might try the previous task
> with \00100-\uFFFD case insensitive pattern.

Whatever that is supposed to mean.



> To OP:
> As I said earlier I hate SqueeseCrypt'ing and respectively hate the
> very look of it below instead of nicely followed separate
> statements :), but if it would be a do-or-die task to have a single
> return statement then:
>
> a1 = [0,1,2];
> a2 = ['a','b','c'];
> a3 = insertArray(a1,a2,1);
> window.alert(a3.length);
> window.alert(a3);
>
> function insertArray(a1, a2, pos) {
> return [a1.splice(pos,0,a2),a1].pop().toString().split(',');
> }

This works only for primitive values, if that. When will you ever learn?

A reasonable person would have checked *all* the methods of
`Array.prototype' before resorting to nonsense as above:

<https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Array/prototype>

Thomas 'PointedEars' Lahn

unread,
Oct 19, 2009, 8:37:45 PM10/19/09
to
Johannes Baagoe wrote:

Exactly. You can omit the `a1.length' argument, though.

Now that the proverbial cat is out of the bag: there is an example very
similar to the test case posted by VK at
<https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Array/concat>

Had the OP read the Reference (included in "RTFM") as (I) recommended, and
referred to by the FAQ, instead of waiting for someone to post the spoon-fed
answer, they would have had the answer several hours earlier.

<http://jibbering.com/faq/#posting>

Johannes Baagoe

unread,
Oct 20, 2009, 4:34:01 AM10/20/09
to
Johannes Baagoe :

>> function insertArray(a1, a2, pos) {
>> return a1.slice(0, pos).concat(a2, a1.slice(pos, a1.length));
>> }

Thomas 'PointedEars' Lahn :

> Exactly. You can omit the `a1.length' argument, though.

Ah, yes. Thanks.

There is a problem, though : the OP asks for a function "which
will splice the a2.length elements of array a2 INTO array a1", my
capitals. The proposed solution does not : a1 is left unchanged.

The shortest (except for whitespace) exact solution I have found is

function insertArray(a1, a2, pos) {
return a1.splice(0, a1.length,
a1.slice(0, pos).concat(a2, a1.slice(pos))), a1;
}

but I rather hope it can be improved.

> Had the OP read the Reference (included in "RTFM") as (I) recommended,
> and referred to by the FAQ, instead of waiting for someone to post
> the spoon-fed answer, they would have had the answer several hours
> earlier.

Well, *you* could have posted an answer if you knew one, you were
obviously on-line and reading the thread.

--
Johannes

Csaba Gabor

unread,
Oct 20, 2009, 4:55:03 AM10/20/09
to
On Oct 20, 2:37 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> Johannes Baagoe wrote:
> > Csaba  Gabor :
> >> I'd like to write a
> >> function insertArray(a1, a2, pos) { ... } which will splice the
> >> a2.length elements of array a2 into array a1 starting at index position
> >> pos, and return the resultant array.
>
> >> What is a "shortest" javascript function to do this? Assume that you
> >> don't have to worry about error checking, and that pos is an integer
> >> such that 0 <= pos <= a1.length Can it be (semi reasonably) done as a
> >> single return statement?
>
> > Perhaps this ?
>
> >   function insertArray(a1, a2, pos) {
> >     return a1.slice(0, pos).concat(a2, a1.slice(pos, a1.length));
> >   }
>
> Exactly.  You can omit the `a1.length' argument, though.

Looks good Johannes. Thanks for directly addressing the question.

> Now that the proverbial cat is out of the bag: there is an
> example very > similar to the test case posted by VK at

> <https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global...>


>
> Had the OP read the Reference (included in "RTFM") as (I) recommended,
> and referred to by the FAQ, instead of waiting for someone to post the
> spoon-fed answer, they would have had the answer several hours earlier.

Another botched presumption about me. It would be so refreshing
to see posts from you that are insult free, address issues head on,
and
are free of presumption about me. I was pleased to read your answer
and
had thought you'd turned over a new leaf at:
http://groups.google.com/group/comp.lang.javascript/browse_frm/thread/5cfe80871d53b921/
since you had a specific solution to an asked question. I rather hope
it will become less of an anomaly.

But excuse me - Recommended? In your first 6(!) posts to this topic,
not one of which indicated that you had a competitive answer, the
only time I see a mention of reading a reference is in the 6th one.

But even had you referenced a manual in a halfway timely fashion,
without detracting from your message by encasing it in insult, it
would
not have been effective, because this phrase has in general become
almost a
joke as far as being helpful. In some cases, it's more of an
indication
that the person doesn't know the answer. It's about as useful as
saying,
"Read the relevant material, and you'll find an answer", or "Search on
google, someone's sure to have covered this in the past". Possibly
true, just not usually particularly helpful.

If a person wants to be helpful along these lines, then I
would suggest that it's far more effective to say, use these
search terms on Google: xxx yyy or If you look at the
following site it should address your question.

In any case, the OP (that would be me), already had an answer several
hours before posting. I did not post the question for my benefit; it
was rather meant as an excercise with an interesting point.

Johannes gave a nice answer. In my routine, where I do not need
to have a return value (yes, I realize it alters the problem)
since I can reuse the input array, I used:

function insertArray(a1, a2, pos) {
a1.splice.apply(aImg, [pos, 0].concat(a2)); }

which approach, by the way, I don't see directly mentioned
in the manual page you referenced.

Thomas 'PointedEars' Lahn

unread,
Oct 20, 2009, 4:55:52 AM10/20/09
to
Johannes Baagoe wrote:

> Thomas 'PointedEars' Lahn wrote:
>
> There is a problem, though : the OP asks for a function "which
> will splice the a2.length elements of array a2 INTO array a1", my
> capitals. The proposed solution does not : a1 is left unchanged.
>
> The shortest (except for whitespace) exact solution I have found is
>
> function insertArray(a1, a2, pos) {
> return a1.splice(0, a1.length,
> a1.slice(0, pos).concat(a2, a1.slice(pos))), a1;
> }
>
> but I rather hope it can be improved.

I surely hope so, because it returns the value of `a1' unchanged :)

The supposed nesting error aside, the obvious solution is to keep it as it
is and update the documentation. Another one is to work with another object
reference:

function insertArray(o, a2, pos)
{
var a1 = o.a;
return o.a.splice(0, a1.length, ...);
}

insertArray({a: [...]}, [...], 42);



>> Had the OP read the Reference (included in "RTFM") as (I) recommended,
>> and referred to by the FAQ, instead of waiting for someone to post
>> the spoon-fed answer, they would have had the answer several hours
>> earlier.
>
> Well, *you* could have posted an answer if you knew one,

True, but see below.

> you were obviously on-line

How can you possibly tell?

> and reading the thread.

But I wouldn't be a good teacher (and we're all teachers here, right? ;-))
if I gave the student the spoon-fed answer, would I? Instead I gave them
something to chew on, in small pieces, but they wouldn't even want to bite.

Now that you have given them the spoon-fed answer, they are going to assume
it is always going to work that way. I think that is a Bad Thing in the
end.

Please leave in an attribution line for each quotation level.

Johannes Baagoe

unread,
Oct 20, 2009, 5:00:23 AM10/20/09
to
Johannes Baagoe :

> The shortest (except for whitespace) exact solution I have found is
>
> function insertArray(a1, a2, pos) {
> return a1.splice(0, a1.length,
> a1.slice(0, pos).concat(a2, a1.slice(pos))), a1;
> }
>
> but I rather hope it can be improved.

Oops, no. That changes a1 into an array whose sole member is the desired
array. ECMAScript is fun :)

--
Johannes

Thomas 'PointedEars' Lahn

unread,
Oct 20, 2009, 5:02:08 AM10/20/09
to
Csaba Gabor wrote:

> Thomas 'PointedEars' Lahn wrote:
>> Had the OP read the Reference (included in "RTFM") as (I) recommended,
>> and referred to by the FAQ, instead of waiting for someone to post the
>> spoon-fed answer, they would have had the answer several hours earlier.
>
> Another botched presumption about me. It would be so refreshing
> to see posts from you that are insult free, address issues head on,
> and
> are free of presumption about me.

If you think that my stating the fact that you have been too lazy here
is an insult to you, then maybe I have hit the problem at bull's eye.

If you want to avoid "botched presumptions" about you, tell us what you
tried and we can help you with that.

This is not a support forum. You are not entitled to anything, let alone
a straightforward answer no matter how stupid you act (_not_: are).

I have given you the reference to the FAQ already, where all this is
explained; here is a more direct explanation that is also linked there:

<http://www.catb.org/~esr/faqs/smart-questions.html>


PointedEars
--
Use any version of Microsoft Frontpage to create your site.
(This won't prevent people from viewing your source, but no one
will want to steal it.)
-- from <http://www.vortex-webdesign.com/help/hidesource.htm> (404-comp.)

Jake Jarvis

unread,
Oct 20, 2009, 5:05:17 AM10/20/09
to
Johannes Baagoe wrote:
[...]

> The shortest (except for whitespace) exact solution I have found is
>
> function insertArray(a1, a2, pos) {
> return a1.splice(0, a1.length,
> a1.slice(0, pos).concat(a2, a1.slice(pos))), a1;
> }
>
> but I rather hope it can be improved.

var a1 = [0, 1, 2],
a2 = ["a", "b", "c"];

insertArray(a1, a2, 1);
print(a1);
=>
0,a,b,c,1,2

looks good

print(a1.toSource());
=>
[[0, "a", "b", "c", 1, 2]]

doesn't look good

print(a1.length);
=>
1

should have been a1.length + a2.length

--
Jake Jarvis

Johannes Baagoe

unread,
Oct 20, 2009, 6:00:51 AM10/20/09
to
Johannes Baagoe :

>> There is a problem, though : the OP asks for a function "which will
>> splice the a2.length elements of array a2 INTO array a1", my capitals.
>> The proposed solution does not : a1 is left unchanged.

>> The shortest (except for whitespace) exact solution I have found is
>>
>> function insertArray(a1, a2, pos) {
>> return a1.splice(0, a1.length,
>> a1.slice(0, pos).concat(a2, a1.slice(pos))), a1;
>> }

>> but I rather hope it can be improved.

Thomas 'PointedEars' Lahn :

> I surely hope so, because it returns the value of `a1' unchanged :)

Not if the comma operator is evaluated left to right, as it should,
ECMA-262 3rd Edition - December 1999, 11.14.

But it has another fatal flaw. Jake Jarvis found it independently.

> The supposed nesting error aside, the obvious solution is to keep
> it as it is and update the documentation.

That means changing the problem instead of solving it. It may be
argued that it provides a *better* solution in most contexts since
side-effects are creatures of the darkness, but it doesn't solve the
problem as posed.

> Another one is to work with another
> object reference:
>
> function insertArray(o, a2, pos)
> {
> var a1 = o.a;
> return o.a.splice(0, a1.length, ...);
> }
>
> insertArray({a: [...]}, [...], 42);

The OP's solution, whith a minor change to correct a typo and another
one (using the comma operator) to provide the desired return value,
is even better, in my opinion :

function insertArray(a1, a2, pos) {
return a1.splice.apply(a1, [pos, 0].concat(a2)), a1;
}

>> Well, *you* could have posted an answer if you knew one,

> But I wouldn't be a good teacher (and we're all teachers here, right?
> ;-))

Not all, but I expect many of us are, or have been.

However, this newsgroup is about *discussion* of javascript, not
lecturing. RTFM :
http://www.jibbering.com/faq/faq_notes/cljs_charter.html

> Please leave in an attribution line for each quotation level.

I do.

I realise that placing each attribution immediately before the first
occurrence of its quotation level imposes some effort on subsequent
posters, but it makes correct attribution much easier for the reader,
especially if the quotations nest deeply. And I believe the comfort
of the reader is more important than that of the poster.

--
Johannes

Asen Bozhilov

unread,
Oct 20, 2009, 6:16:54 AM10/20/09
to
On 19 Окт, 22:44, Csaba Gabor <dans...@gmail.com> wrote:
> I'd like to write a
> function insertArray(a1, a2, pos) { ... }
> which will splice the a2.length elements of array a2 into array a1
> starting at index position pos, and return the resultant array.


function insertArray(a1, b1, pos)
{
Array.prototype.splice.apply(a1, [pos, 0].concat(b1));
return a1;
}

If you doesn't want change a1 array, initialize new array in local
execution context and returned reference to that `object'.

function insertArray(a1, b1, pos)
{
var res_arr = [].concat(a1);
Array.prototype.splice.apply(res_arr, [pos, 0].concat(b1));
return res_arr;
}

Johannes Baagoe

unread,
Oct 20, 2009, 6:26:44 AM10/20/09
to
Csaba Gabor :

> the OP (that would be me), already had an answer several hours before
> posting. I did not post the question for my benefit; it was rather
> meant as an excercise with an interesting point.

And I appreciated that, it is exactly the kind of things I would like to
see more of on this newsgroup. I am not particularly interested in
incompatibility issues in various browser's implementation of the DOM, and
even less in ego-related flames. I read and occasionally post on c.l.js
in order to learn and discuss *javascript*, that is, a computer language
with quite a few unique features and idioms.

(I use "javascript", uncapitalised, as an informal term for the more
formally defined ECMAScript and its predecessors or variants, I cannot
help agreeing with Brendan Eich that "ECMAScript" sounds like a skin
disease.)

--
Johannes

Jake Jarvis

unread,
Oct 20, 2009, 6:36:55 AM10/20/09
to
Csaba Gabor wrote:
[...]

> In any case, the OP (that would be me), already had an answer several
> hours before posting. I did not post the question for my benefit; it
> was rather meant as an excercise with an interesting point.

Why did you not actually say so?

--
Jake Jarvis

optimistx

unread,
Oct 20, 2009, 6:57:43 AM10/20/09
to
Johannes Baagoe wrote:
> Csaba Gabor :
>
>> the OP (that would be me), already had an answer several hours before
>> posting. I did not post the question for my benefit; it was rather
>> meant as an excercise with an interesting point.
>
> And I appreciated that, it is exactly the kind of things I would like
> to see more of on this newsgroup. I am not particularly interested in
> incompatibility issues in various browser's implementation of the
> DOM, and even less in ego-related flames.

Yes, that expresses my opinion too. Ego-related flames :).

The example is interesting, I like postings like that.

I can afford to read and write here about only the things which
I feel fun to have. I need not spoil my day by reading insults.

If some people try to have only 'expert level advanced'
QUESTIONS here, where the OP (original poster?) has first
tried to solve some years/months/weeks before posting,
I think that goal is going to fail.

So let us have fun instead. Let us have friendly and fun DISCUSSION.
Ideas. Experiences. Exercises. Right or wrong, not so important. We
learn by making mistakes.

Is c.l.j a help desk? Perhaps a help desk for some people to get their daily
ego boost and increase of their self esteem. If they need to insult
others to feel better and expertlike, we cannot prevent them doing
that, as little as we cannot prevent spam coming. Anyhow, we can ignore
spam, ignore ego boosting wars.

Johannes Baagoe

unread,
Oct 20, 2009, 7:01:01 AM10/20/09
to
Johannes Baagoe :

>> The shortest (except for whitespace) exact solution I have found is
>>
>> function insertArray(a1, a2, pos) {
>> return a1.splice(0, a1.length,
>> a1.slice(0, pos).concat(a2, a1.slice(pos))), a1;
>> }
>>
>> but I rather hope it can be improved.

Jake Jarvis :

> var a1 = [0, 1, 2],
> a2 = ["a", "b", "c"];
>
> insertArray(a1, a2, 1);
> print(a1);
> =>
> 0,a,b,c,1,2
>
> looks good
>
> print(a1.toSource());
> =>
> [[0, "a", "b", "c", 1, 2]]
>
> doesn't look good

Quite, I realised that thirty seconds after posting :)

The shortest (except for whitespace) solution for the problem as stated
seems to be

function insertArray(a1, a2, pos) {


return a1.splice.apply(a1, [pos, 0].concat(a2)), a1;
}

If one changes the problem to that of returning an array without changing
the value of the first argument as a side-effect, the following is
slightly shorter, clearer and possibly better :

function splicedArray((a1, a2, pos) {
return a1.slice(0, pos).concat(a2, a1.slice(pos));
}

(Note the change in the name of the function : "insertArray" is a verb,
"splicedArray" is a noun.)

--
Johannes

Thomas 'PointedEars' Lahn

unread,
Oct 20, 2009, 6:39:50 AM10/20/09
to
Johannes Baagoe wrote:

> Thomas 'PointedEars' Lahn :


>> Johannes Baagoe :
>>> There is a problem, though : the OP asks for a function "which will
>>> splice the a2.length elements of array a2 INTO array a1", my capitals.
>>> The proposed solution does not : a1 is left unchanged.
>>>
>>> The shortest (except for whitespace) exact solution I have found is
>>>
>>> function insertArray(a1, a2, pos) {
>>> return a1.splice(0, a1.length,
>>> a1.slice(0, pos).concat(a2, a1.slice(pos))), a1;
>>> }
>>>
>>> but I rather hope it can be improved.
>>

>> I surely hope so, because it returns the value of `a1' unchanged :)
>
> Not if the comma operator is evaluated left to right, as it should,

Yes, my mistake.

>> The supposed nesting error aside, the obvious solution is to keep
>> it as it is and update the documentation.
>

> That means changing the problem instead of solving it. [...]

No, it is just a different solution:

a1 = insertArray(a1, ...);

> [...]


>> Another one is to work with another
>> object reference:
>>
>> function insertArray(o, a2, pos)
>> {
>> var a1 = o.a;
>> return o.a.splice(0, a1.length, ...);
>> }
>>
>> insertArray({a: [...]}, [...], 42);
>
> The OP's solution, whith a minor change to correct a typo and another
> one (using the comma operator) to provide the desired return value,
> is even better, in my opinion :
>
> function insertArray(a1, a2, pos) {
> return a1.splice.apply(a1, [pos, 0].concat(a2)), a1;
> }

By which criterion is that better? It requires Function.prototype.apply()
(compatibility issue), a nested call (performance issue), and is less clear
(code reuse issue).



> However, this newsgroup is about *discussion* of javascript, not

> lecturing. [...]

Exactly. It is _not_ a support forum where you ask questions and are
entitled to an (straightforward, helpful) answer.

>> Please leave in an attribution line for each quotation level.
>
> I do.
>
> I realise that placing each attribution immediately before the first
> occurrence of its quotation level imposes some effort on subsequent
> posters, but it makes correct attribution much easier for the reader,
> especially if the quotations nest deeply. And I believe the comfort
> of the reader is more important than that of the poster.

In that case you would probably be interested to know that in my humble
opinion (and that of many others, including the creators of Usenet, and the
authors of the FAQ of this NG), in-between attribution lines in electronic
written discussions disturb the flow of reading. There is also no need to
repeat attribution lines or place them in-between once it has been made
clear which quotation level refers to the text of which person. And, may I
doubt that your quoting style is your Pan's default?

<http://pan.rebelbase.com/screenshots/posting.png>

VK

unread,
Oct 20, 2009, 7:02:23 AM10/20/09
to
Csaba Gabor wrote:
> > In any case, the OP (that would be me), already had an answer several
> > hours before posting.  I did not post the question for my benefit; it
> > was rather meant as an excercise with an interesting point.
Jake Jarvis wrote:
> Why did you not actually say so?

OP named it "Splicing exercise', that enough of a hint IMHO.


Thomas 'PointedEars' Lahn

unread,
Oct 20, 2009, 7:23:37 AM10/20/09
to
VK wrote:

It is evidently ambiguous. An exercise *for whom*? Also, one should not
assume the Subject header is read, and therefore should not use it alone
to convey the meaning of the posting. If that is not already mentioned
in the FAQ under #posting, it should be.


PointedEars
--
Danny Goodman's books are out of date and teach practices that are
positively harmful for cross-browser scripting.
-- Richard Cornford, cljs, <cife6q$253$1$8300...@news.demon.co.uk> (2004)

Asen Bozhilov

unread,
Oct 20, 2009, 7:48:59 AM10/20/09
to
On 20 Окт, 13:39, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
> Johannes Baagoe wrote:

> >   function insertArray(a1, a2, pos) {
> >     return a1.splice.apply(a1, [pos, 0].concat(a2)), a1;
> >   }
>
> By which criterion is that better?  It requires Function.prototype.apply()
> (compatibility issue), a nested call (performance issue), and is less clear
> (code reuse issue).

ECMA 262 - 3
15 Native ECMAScript Objects:
Every built-in function and every built-in constructor has the
Function prototype object, which is the initial value of
the expression Function.prototype (section 15.3.2.1), as the value of
its internal [[Prototype]] property.

> (performance issue)

It's wrong. If you compare:

function insertArray(a1, a2, pos) {
return a1.splice(0, a1.length,
a1.slice(0, pos).concat(a2, a1.slice(pos))), a1;
}

function insertArray1(a1, b1, pos)


{
Array.prototype.splice.apply(a1, [pos, 0].concat(b1));
return a1;
}

For 100000 times with:
var a = [1, 2, 3],
b = ['a', 'b', 'c'];

insertArray : 447ms
insertArray1 : 386ms

In Fx 3.5

Asen Bozhilov

unread,
Oct 20, 2009, 7:51:08 AM10/20/09
to
On 20 Окт, 14:48, Asen Bozhilov <asen.bozhi...@gmail.com> wrote:
> insertArray1 : 386ms

Apologies, little typo:
insertArray1 : 286ms


Thomas 'PointedEars' Lahn

unread,
Oct 20, 2009, 8:20:29 AM10/20/09
to
Asen Bozhilov wrote:

That doesn't prove anything either.

Thomas 'PointedEars' Lahn

unread,
Oct 20, 2009, 8:20:13 AM10/20/09
to
Asen Bozhilov wrote:

> Thomas 'PointedEars' Lahn wrote:
>> Johannes Baagoe wrote:
>> > function insertArray(a1, a2, pos) {
>> > return a1.splice.apply(a1, [pos, 0].concat(a2)), a1;
>> > }
>>
>> By which criterion is that better? It requires
>> Function.prototype.apply() (compatibility issue), a nested call
>> (performance issue), and is less clear (code reuse issue).
>
> ECMA 262 - 3
> 15 Native ECMAScript Objects:
> Every built-in function and every built-in constructor has the
> Function prototype object, which is the initial value of
> the expression Function.prototype (section 15.3.2.1), as the value of
> its internal [[Prototype]] property.

Entirely irrelevant to what I said.



>> (performance issue)
>
> It's wrong.

Hear, hear.

> If you compare:
>
> function insertArray(a1, a2, pos) {
> return a1.splice(0, a1.length,
> a1.slice(0, pos).concat(a2, a1.slice(pos))), a1;
> }
>
> function insertArray1(a1, b1, pos)
> {
> Array.prototype.splice.apply(a1, [pos, 0].concat(b1));
> return a1;
> }
>
> For 100000 times with:
> var a = [1, 2, 3],
> b = ['a', 'b', 'c'];
>
> insertArray : 447ms
> insertArray1 : 386ms
>
> In Fx 3.5

That doesn't prove anything.

Johannes Baagoe

unread,
Oct 20, 2009, 8:48:18 AM10/20/09
to
Johannes Baagoe :

>> I realise that placing each attribution immediately before the first
>> occurrence of its quotation level imposes some effort on subsequent
>> posters, but it makes correct attribution much easier for the reader,
>> especially if the quotations nest deeply. And I believe the comfort
>> of the reader is more important than that of the poster.

Thomas 'PointedEars' Lahn :

> In that case you would probably be interested to know that in my
> humble opinion (and that of many others, including the creators of
> Usenet, and the authors of the FAQ of this NG), in-between attribution
> lines in electronic written discussions disturb the flow of reading.
> There is also no need to repeat attribution lines or place them
> in-between once it has been made clear which quotation level refers
> to the text of which person. And, may I doubt that your quoting
> style is your Pan's default?

It is not Pan's default, obviously. It takes some work, and alas one
that cannot be entirely automatised even if it is not that difficult
to write helper scripts.

It results of thought and actual experiments which show that in the
case of even moderately nested threads (3 or 4 levels), subjects
presented with the traditional way of attributing quotes make more
errors in attributing the correct author to the right level of
quotation than in the way I propose, especially in colour-enhanced
user agents. Naïve subjects, on the whole, find it easier to remember
that if the attribution to Bob precedes something that has two angle
brackets and is red, then whatever has two angle brackets and is
red was written by Bob, rather than figuring it out from the fact
that the attribution to Bob was written by Alice or her user-agent,
as quoted in green with one angle bracket. (Repeating the attribution
at each quote does not increase reader performance significantly.)

I know of no empirical evidence that it disturbs the flow of reading,
nor of any spontaneous complaints of users. And while there has been
a lot of discussions from the very early days of Usenet onwards about
quotation styles, the consensus, as far as I know, is simply that
1. quotes should be attributed, 2. lengthy attributions should be
avoided, the name is enough, 3. top-posting is out of question.

I have over the years participated in too many debates on fufe
(fr.usenet.forums.evolution, the equivalent in the fr. hierarchy of
Big Eight's news.groups.proposals) to take appeals to the "creators of
Usenet" seriously, and so far, you are the only one to complain. So,
if you really believe that there is a consensus that, e.g.,

On Oct 19, 9:31 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
> kangax wrote:
> > David Mark wrote:
> >> On Oct 18, 7:14 pm, kangax <kan...@gmail.com> wrote:

is better, I suggest a RFD in order to change the charter :)

Of course, if others feel like you, we could also discuss it here,
or on another more suitable newsgroup. If a consensus is reached,
I shall comply with it. Otherwise, I shall continue quoting in the
way I find the best, without going to the extreme of reprimanding
others for not doing like me.

--
Johannes

Johannes Baagoe

unread,
Oct 20, 2009, 9:21:11 AM10/20/09
to
Thomas 'PointedEars' Lahn :

>>> function insertArray(o, a2, pos)
>>> {
>>> var a1 = o.a;
>>> return o.a.splice(0, a1.length, ...);
>>> }
>>>
>>> insertArray({a: [...]}, [...], 42);

Johannes Baagoe :

>> The OP's solution, whith a minor change to correct a typo and another
>> one (using the comma operator) to provide the desired return value, is
>> even better, in my opinion :
>>
>> function insertArray(a1, a2, pos) {
>> return a1.splice.apply(a1, [pos, 0].concat(a2)), a1;
>> }

Thomas 'PointedEars' Lahn :

> By which criterion is that better?

It answers the question, which calls for "a function insertArray(a1,
a2, pos) { ... } which will splice the a2.length elements of array a2


into array a1 starting at index position pos, and return the resultant

array". Not for a solution with another interface that imposes that the
first argument be wrapped in a new Object instance, with a solution-imposed
property name to boot.

And it does so a it single return statement, as requested if possible,
it may even be the "shortest" javascript function to fully comply with the
specifications, as requested.

Performance was no part of the exercise as stated, and as for clarity
and reuse, our opinions differ about which is the best, or the least awful.

--
Johannes

Thomas 'PointedEars' Lahn

unread,
Oct 20, 2009, 11:55:59 AM10/20/09
to
Johannes Baagoe wrote:

> Johannes Baagoe :
>> Thomas 'PointedEars' Lahn :


>>> I realise that placing each attribution immediately before the first
>>> occurrence of its quotation level imposes some effort on subsequent
>>> posters, but it makes correct attribution much easier for the reader,
>>> especially if the quotations nest deeply. And I believe the comfort
>>> of the reader is more important than that of the poster.
>>

>> In that case you would probably be interested to know that in my
>> humble opinion (and that of many others, including the creators of
>> Usenet, and the authors of the FAQ of this NG), in-between attribution
>> lines in electronic written discussions disturb the flow of reading.
>> There is also no need to repeat attribution lines or place them
>> in-between once it has been made clear which quotation level refers
>> to the text of which person. And, may I doubt that your quoting
>> style is your Pan's default?
>
> It is not Pan's default, obviously. It takes some work, and alas one
> that cannot be entirely automatised even if it is not that difficult
> to write helper scripts.

IOW: You are going to great lengths to modify your news client so that it
posts differently than any other news client by default, and different to
all Usenet recommendations. Some would consider that to be rather trollish
behavior, and your stating that you care for your readers to be a
hypocritical statement.

> [TLDR]


> if you really believe that there is a consensus that, e.g.,
>
> On Oct 19, 9:31 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
> wrote:
> > kangax wrote:
> > > David Mark wrote:
> > >> On Oct 18, 7:14 pm, kangax <kan...@gmail.com> wrote:
>
> is better, I suggest a RFD in order to change the charter :)
>
> Of course, if others feel like you, we could also discuss it here,
> or on another more suitable newsgroup. If a consensus is reached,
> I shall comply with it.

So far, the recommendations in the FAQ of this newsgroup displays what could
reasonably be called the consensus. The current FAQ maintainer has imposed
some of his views on it, but most of the FAQ appears acceptable to all whom
it may concern. To name one, Richard Cornford recently stated what he finds
acceptable when he replied to one of VK's postings, and with regard to the
position of the attribution that is precisely what is described in the FAQ.

> Otherwise, I shall continue quoting in the way I find the best, without
> going to the extreme of reprimanding others for not doing like me.

ISTM you overestimate your importance here.


F'up2 poster

Csaba Gabor

unread,
Oct 20, 2009, 8:37:10 PM10/20/09
to
On Oct 20, 1:01 pm, Johannes Baagoe <baa...@baagoe.com> wrote:
> Johannes Baagoe :
> The shortest (except for whitespace) solution for the problem
> as stated seems to be
>
>   function insertArray(a1, a2, pos) {
>     return a1.splice.apply(a1, [pos, 0].concat(a2)), a1;
>   }
>
> If one changes the problem to that of returning an array without changing
> the value of the first argument as a side-effect, the following is
> slightly shorter, clearer and possibly better :
>
>   function splicedArray((a1, a2, pos) {
>     return a1.slice(0, pos).concat(a2, a1.slice(pos));
>   }

Johannes, thanks for cleaning up my example code.
I find this use of the comma very interesting. It's the
only time I've ever seen it used outside a var statement
or for loop, thanks.

As a variation on a theme, one could also use:
function insertArray(a1, a2, pos) { return (
a1.splice.apply(a1, [pos, 0].concat(a2)).length || a1); }

Asen, thanks for pointing out that one can also use
Array.prototype.splice.apply in place of
a1.splice.apply above. Do you know offhand which of
the two versions is more efficient?

Asen Bozhilov

unread,
Oct 21, 2009, 4:44:10 AM10/21/09
to
On 21 Окт, 03:37, Csaba Gabor <dans...@gmail.com> wrote:

> Asen, thanks for pointing out that one can also use
> Array.prototype.splice.apply in place of
> a1.splice.apply above.

BTW, before my post with Array.prototype.splice.apply, i don't see
your code :)

> Do you know offhand which of
> the two versions is more efficient?

The only difference between two version is a way of prototype lookups.
In the two version lookups is 5. Your code make much more lookups
internal.

1: a1 is instance of Variable object in local execution context. a1
refer `object' who [[Prototype]] property referred to Array.prototype.
2: That `object' who referred from a1 doesn't have property with name
`splice'.
3: Look for `splice' in `object' who referred from a1.[[Prototype]].
4: `splice' property referred `object' who internal property
[[Prototype]] referred to Function.prototype. `Object' referred from
`splice' doesn't have property with the name `apply'. Going in
prototype chain.
5: Property `apply' will be in the `splice'.[[Prototype]]

In my code:

1: `Array' is instance from Variable object in global execution
context. `Array' referred `object' who internal [[Prototype]] referred
to Function.prototype. And `Array' internal [[Class]] value is
'Function'.
2: Object referred from `Array' have property with name `prototype',
because `prototype' property is instance property.
3: `splice' property will be in `object' referred from `prototype'
property.
4: Point 4 from before explained list.
5: Point 5 from before explained list.

Richard Cornford

unread,
Oct 21, 2009, 5:59:05 AM10/21/09
to
Asen Bozhilov wrote:

The first list included the steps involved in resolving - a1 - against
the scope chain, but here you have omitted the steps in involved in
resolving - Array - against the scope chain. those additional steps
are:-

1.Examine the Variable object to see if it has a property named
"Array"; it does not.
2 Examine the Variable object to see if it has a [[Prototype]], it
does not, so move on to the next object on the scope chain, which
is the global object.
3 Examine the global object to see if it has a property named
"Array", which it does.

- then, having read the "Array" property of the global object, your
steps begin.

> to Function.prototype. And `Array' internal [[Class]] value is
> 'Function'.
> 2: Object referred from `Array' have property with name `prototype',
> because `prototype' property is instance property.
> 3: `splice' property will be in `object' referred from `prototype'
> property.
> 4: Point 4 from before explained list.
> 5: Point 5 from before explained list.

So with the extra steps need to resolve - Array - we are at about 8
steps against 5 by the end. In practice each of those steps is so quick
that the odds are they are dwarfed by a single instance of the overheads
implied by a function call, so are not really worth worrying about at
all.

Richard.

abozhilov

unread,
Oct 21, 2009, 10:01:04 AM10/21/09
to
On 20 Окт, 11:34, Johannes Baagoe <baa...@baagoe.com> wrote:
> The shortest (except for whitespace) exact solution I have found is
>
>   function insertArray(a1, a2, pos) {
>     return a1.splice(0, a1.length,
>       a1.slice(0, pos).concat(a2, a1.slice(pos))), a1;
>   }

You can use more shortest:

function insertArray2(a1, a2, pos)
{
var len = a1.length;
a1.splice(0, len, a1.concat(a2, a1.splice(pos, len)));
}

If you doesn't want to change a1 is much more short:

function insertArray2(a1, a2, pos)
{
return a1.concat(a2, a1.splice(pos, a1.length));
}


abozhilov

unread,
Oct 21, 2009, 10:22:15 AM10/21/09
to
On 21 Окт, 17:01, abozhilov <fort...@gmail.com> wrote:
> If you doesn't want to change a1 is much more short:
>
> function insertArray2(a1, a2, pos)
> {
>         return a1.concat(a2, a1.splice(pos, a1.length));
>
> }

Actually that example is wrong. a1.splice will be change a1 and that
is not good.


Johannes Baagoe

unread,
Oct 21, 2009, 11:13:14 AM10/21/09
to
Csaba Gabor :

> Johannes, thanks for cleaning up my example code.

Thank you for providing an interesting and entertaining exercise.

Also, I liked your solution. (Asen Bozhilov published essentially the
same a bit later, I presume independently.) Not for practical use - I
avoid side effects whenever possible - but for providing insight into
some of the more esoteric sides of javascript: why simply reassigning
a1 in the function won't work, why a naive use of |splice| won't either,
how |apply| expands arrays into argument lists, and the cute trick of
using |concat| to provide some of the desired arguments.

> I find this use of the comma very interesting. It's the only time
> I've ever seen it used outside a var statement or for loop, thanks.

I understand it is usually frowned upon, and I only used it because it
allowed a single return statement. No practical advantage, just fun.
But we may perhaps re-examine its use, it could be a way to indicate
to the human reader that the instructions separated by commas are steps
in the higher order instruction that is terminated by a semicolon.

> As a variation on a theme, one could also use: function
> insertArray(a1, a2, pos) { return ( a1.splice.apply(a1, [pos,
> 0].concat(a2)).length || a1); }

> As a variation on a theme, one could also use:
> function insertArray(a1, a2, pos) { return (
> a1.splice.apply(a1, [pos, 0].concat(a2)).length || a1); }

That is plain naughty, in my opinion: no conceivable advantage at all,
just obscure. But still fun :)

--
Johannes

Johannes Baagoe

unread,
Oct 21, 2009, 11:14:20 AM10/21/09
to
Csaba Gabor :

> Johannes, thanks for cleaning up my example code.

Thank you for providing an interesting and entertaining exercise.

Also, I liked your solution. (Asen Bozhilov published essentially the same
a bit later, I presume independently.) Not for practical use - I avoid
side effects whenever possible - but for providing insight into some of
the more esoteric sides of javascript: why simply reassigning a1 in the
function won't work, why a naive use of |splice| won't either, how |apply|
expands arrays into argument lists, and the cute trick of using |concat|
to provide some of the desired arguments.

> I find this use of the comma very interesting. It's the only time I've


> ever seen it used outside a var statement or for loop, thanks.

I understand it is usually frowned upon, and I only used it because it


allowed a single return statement. No practical advantage, just fun. But
we may perhaps re-examine its use, it could be a way to indicate to the
human reader that the instructions separated by commas are steps in the
higher order instruction that is terminated by a semicolon.

> As a variation on a theme, one could also use: function insertArray(a1,


> a2, pos) { return (
> a1.splice.apply(a1, [pos, 0].concat(a2)).length || a1); }

That is plain naughty, in my opinion: no conceivable advantage at all,

kangax

unread,
Oct 21, 2009, 7:41:49 PM10/21/09
to

If we're talking about function code, where Variable Object is an
Activation Object, how do we know that it has no [[Prototype]]?

Isn't Activation Object just a specification mechanism, with unspecified
[[Prototype]]?

> 3 Examine the global object to see if it has a property named
> "Array", which it does.

However step #3 can actually be step #4 (or even #5), if function was
declared via function expression and had an identifier :)

In that case, object injected right before function's activation object
would be searched for property too, and since that object is created as
if by expression `new Object`, there's also a possibility of it having
[[Prototype]] (in fact, some versions of SpiderMonkey implement that
"extra" object exactly in such way).

[...]

--
kangax

Richard Cornford

unread,
Oct 21, 2009, 8:47:02 PM10/21/09
to
kangax wrote:
> Richard Cornford wrote:
<snip>

>> 1.Examine the Variable object to see if it has a property named
>> "Array"; it does not.
>> 2 Examine the Variable object to see if it has a [[Prototype]],
>> it does not, so move on to the next object on the scope
>> chain, which is the global object.
>
> If we're talking about function code, where Variable Object is
> an Activation Object, how do we know that it has no [[Prototype]]?

Possibly because of the absence of any assignment to [[Prototype]] in
association with the creation of the activation object, when every other
object creation (that I can think of right now) either specifies a
[[Prototype]] value/assignment or implies it (as in the use of "as if by
the expression new Object()").

> Isn't Activation Object just a specification mechanism, with
> unspecified [[Prototype]]?

Yes, but the activation object becomes the function call's Variable
object and if it did have a [[Prototype]] then that would always be
involved in Identifier resolution from within a function.

>> 3 Examine the global object to see if it has a property named
>> "Array", which it does.
>
> However step #3 can actually be step #4 (or even #5), if function
> was declared via function expression and had an identifier :)

Yes, extending the prototype chain is a possibility, but was not evident
in the posted code.

> In that case, object injected right before function's activation
> object would be searched for property too, and since that object
> is created as if by expression `new Object`, there's also a
> possibility of it having [[Prototype]] (in fact, some versions
> of SpiderMonkey implement that "extra" object exactly in such way).

They all should in order to be 'correct', though that has changed in ES
4 (as I recall).

Richard.

kangax

unread,
Oct 21, 2009, 11:30:21 PM10/21/09
to
Richard Cornford wrote:
> kangax wrote:
>> Richard Cornford wrote:
> <snip>
>>> 1.Examine the Variable object to see if it has a property named
>>> "Array"; it does not.
>>> 2 Examine the Variable object to see if it has a [[Prototype]],
>>> it does not, so move on to the next object on the scope
>>> chain, which is the global object.
>>
>> If we're talking about function code, where Variable Object is
>> an Activation Object, how do we know that it has no [[Prototype]]?
>
> Possibly because of the absence of any assignment to [[Prototype]] in
> association with the creation of the activation object, when every other
> object creation (that I can think of right now) either specifies a
> [[Prototype]] value/assignment or implies it (as in the use of "as if by
> the expression new Object()").

Fair enough.

>
>> Isn't Activation Object just a specification mechanism, with
>> unspecified [[Prototype]]?
>
> Yes, but the activation object becomes the function call's Variable
> object and if it did have a [[Prototype]] then that would always be
> involved in Identifier resolution from within a function.

Of course.

We can actually test if Activation Object has [[Prototype]] referencing
something like `Object.prototype` (or `Array.prototype`, etc.). However,
[[Prototype]] can also reference some "internal" entity, which we have
no way of checking for (and its existence probably doesn't really matter).

[...]

>
>> In that case, object injected right before function's activation
>> object would be searched for property too, and since that object
>> is created as if by expression `new Object`, there's also a
>> possibility of it having [[Prototype]] (in fact, some versions
>> of SpiderMonkey implement that "extra" object exactly in such way).
>
> They all should in order to be 'correct', though that has changed in ES
> 4 (as I recall).

Yep, (in ES5) they now say — "as if by the expression new Object() where
Object is the standard built-in constructor with that name."

IIRC, in ES5, AO/VO was something called Environment Records, but I
haven't yet looked into it throughly.

--
kangax

Garrett Smith

unread,
Oct 22, 2009, 1:22:15 AM10/22/09
to
kangax wrote:
> Richard Cornford wrote:
>> kangax wrote:
>>> Richard Cornford wrote:
>> <snip>
>>>> 1.Examine the Variable object to see if it has a property named
>>>> "Array"; it does not.
>>>> 2 Examine the Variable object to see if it has a [[Prototype]],
>>>> it does not, so move on to the next object on the scope
>>>> chain, which is the global object.
>>>
>>> If we're talking about function code, where Variable Object is
>>> an Activation Object, how do we know that it has no [[Prototype]]?
>>

See below.

>> Possibly because of the absence of any assignment to [[Prototype]] in
>> association with the creation of the activation object, when every
>> other object creation (that I can think of right now) either specifies
>> a [[Prototype]] value/assignment or implies it (as in the use of "as
>> if by the expression new Object()").
>
> Fair enough.
>
>>
>>> Isn't Activation Object just a specification mechanism, with
>>> unspecified [[Prototype]]?
>>
>> Yes, but the activation object becomes the function call's Variable
>> object and if it did have a [[Prototype]] then that would always be
>> involved in Identifier resolution from within a function.
>
> Of course.
>
> We can actually test if Activation Object has [[Prototype]] referencing
> something like `Object.prototype` (or `Array.prototype`, etc.). However,
> [[Prototype]] can also reference some "internal" entity, which we have
> no way of checking for (and its existence probably doesn't really matter).
>

And if the activation object has no property, scope chain and identifier
resolution takes to global object, which is a split object, which may
have Object.prototype on the scope chain (that is implementation-
dependent).

| The values of the [[Prototype]] and [[Class]] properties of the global
| object are implementation-dependent.

Interesting example Leithead posted up on whatwg, calling -
hasOwnProperty - on global object, a WindowProxy, yet expecting the
result to be based off global object itself.

Extra interesting is Blackberry9000 bug of resolving an Object.prototype
property on the Variable object.

We can test this by setting something in containing scope and see if the
identifier is resolved off global object.

http://github.com/GarrettS/ape-javascript-library/blob/master/adhoctest/activationo.html
(can be run using gitHubSource bookmarklet)

Example source:
<!doctype html>
<html>
<head>
<title>test activation object</title>
</head>
<body style="white-space: pre">
<script type="text/javascript">
var hasOwnProperty = 12;
this.hasOwnProperty = 14;
this.gProp = "g";
(function(){
function hasOwnProperty(a){return 1;}
var constructor = 123;
function toString() { return "local"; }
function testThis(){
document.write([
hasOwnProperty("gProp"),
constructor,
toString(),
this.toString()]);
}

return testThis;
})()();
</script>
</body>
</html>

Expected output would be something* like:
1,123,local,[object Window]

* "[object Window]" is not an expectation; everything else is.

Blackberry9000/9500:
true, function Object() { [native code for Object.Object, arity=1] }
,[object Window],[object Window]

The result of first hasOwnProperty("gProp") could be explained by
the identifier being resolved on activation object's scope chain and
calling hasOwnProperty using |null| as the |this| value for the function
call, as in s10.1.6.

| When the call operation is applied to a Reference value whose base
| object is an activation object, null is used as the this value of the
| call.

The implication this has is that any identifier name that coincides with
with an Object.prototype property will not be found on the enclosing
scope. Don't name you function "hasOwnProperty", etc.

Function decompilation that expects "[native code]" will fail.
(Function decompilation is best avoided altogether, for various other
reasons).
--
Garrett
comp.lang.javascript FAQ: http://jibbering.com/faq/

Richard Cornford

unread,
Oct 22, 2009, 9:51:34 AM10/22/09
to
kangax wrote:
> Richard Cornford wrote:
>> kangax wrote:
>>> Richard Cornford wrote:
>> <snip>
>>>> 1.Examine the Variable object to see if it has a property named
>>>> "Array"; it does not.
>>>> 2 Examine the Variable object to see if it has a [[Prototype]],
>>>> it does not, so move on to the next object on the scope
>>>> chain, which is the global object.
>>>
>>> If we're talking about function code, where Variable Object is
>>> an Activation Object, how do we know that it has no [[Prototype]]?
>>
>> Possibly because of the absence of any assignment to [[Prototype]]
>> in association with the creation of the activation object, when
>> every other object creation (that I can think of right now) either
>> specifies a [[Prototype]] value/assignment or implies it (as in
>> the use of "as if by the expression new Object()").
>
> Fair enough.

Well, reasonable but I would happily entertain the idea that this was
not good enough. Whether the Activation object has a [[Prototype]] or
not becomes very importation as soon as it becomes the Variable object
as if (or even when) it does you effectively start 'inheriting'
unexpected local variables, and it seems a good idea to know whether
that is possible/allowed or forbidden. (Indeed, it seems like a good
idea to be very explicit about forbidding it.)

I was fairly sure that somewhere in the spec there was an assertion that
would apply to this object's [[Prototype]], but I could not find one.
However, there is an assertion that a [[Prototype]] property must exist
for all objects (including host objects) (Section 8.6.3, paragraph 5 of
the text) and that the [[Prototype]] property must be either an object
or be null (paragraph 6 of the same section).

>>> Isn't Activation Object just a specification mechanism, with
>>> unspecified [[Prototype]]?
>>
>> Yes, but the activation object becomes the function call's Variable
>> object and if it did have a [[Prototype]] then
>> that would always be involved in Identifier resolution from
>> within a function.
>
> Of course.
>
> We can actually test if Activation Object has [[Prototype]]
> referencing something like `Object.prototype` (or
> `Array.prototype`, etc.). However, [[Prototype]] can also
> reference some "internal" entity, which we have no way of checking for
> (and its existence probably doesn't
> really matter).

yes, and if that 'internal entity' entity only had properties with names
that could not qualify as Identifiers then there would be nothing that
could be done to test for implications of its existence.

> [...]
>>> In that case, object injected right before function's activation
>>> object would be searched for property too, and since that object
>>> is created as if by expression `new Object`, there's also a
>>> possibility of it having [[Prototype]] (in fact, some versions
>>> of SpiderMonkey implement that "extra" object exactly in such
>>> way).
>>
>> They all should in order to be 'correct', though that has changed
>> in ES 4 (as I recall).
>
> Yep, (in ES5) they now say — "as if by the expression new Object()
> where Object is the standard built-in constructor with that name."
>
> IIRC, in ES5, AO/VO was something called Environment Records, but I
> haven't yet looked into it throughly.

Yes, there is a lot of new terminology to come from ES 5. I can imagine
a re-write of my article on closers employing the ES 5 terminology in
place of the ES 3 terminology. The two documents would be very
different, and each effectively meaningless to anyone only familiar with
the other version of the spec.

Richard.

kangax

unread,
Oct 22, 2009, 1:28:59 PM10/22/09
to
Garrett Smith wrote:
> kangax wrote:
>> Richard Cornford wrote:
>>> kangax wrote:
>>>> Richard Cornford wrote:
>>> <snip>
>>>>> 1.Examine the Variable object to see if it has a property named
>>>>> "Array"; it does not.
>>>>> 2 Examine the Variable object to see if it has a [[Prototype]],
>>>>> it does not, so move on to the next object on the scope
>>>>> chain, which is the global object.
[...]

>>>> Isn't Activation Object just a specification mechanism, with
>>>> unspecified [[Prototype]]?
>>>
>>> Yes, but the activation object becomes the function call's Variable
>>> object and if it did have a [[Prototype]] then that would always be
>>> involved in Identifier resolution from within a function.
>>
>> Of course.
>>
>> We can actually test if Activation Object has [[Prototype]]
>> referencing something like `Object.prototype` (or `Array.prototype`,
>> etc.). However, [[Prototype]] can also reference some "internal"
>> entity, which we have no way of checking for (and its existence
>> probably doesn't really matter).
>>
>
> And if the activation object has no property, scope chain and identifier
> resolution takes to global object, which is a split object, which may
> have Object.prototype on the scope chain (that is implementation-
> dependent).
>
> | The values of the [[Prototype]] and [[Class]] properties of the global
> | object are implementation-dependent.
>
> Interesting example Leithead posted up on whatwg, calling -
> hasOwnProperty - on global object, a WindowProxy, yet expecting the
> result to be based off global object itself.
>
> Extra interesting is Blackberry9000 bug of resolving an Object.prototype
> property on the Variable object.

Ahha! I knew one of them (browsers) would do something like that :)

Thanks.

I also made a much simpler test, only to see if Object.prototype is
indeed in prototype chain of variable object in Blackberry.

Object.prototype.x = 'Resolved on activation object\'s [[Prototype]]';
(function(){
var x = 'Resolved on outer scope\'s activation object';
document.write(function(){
return x;
}());
})();

Blackberry outputs — "Resolved on activation object's [[Prototype]]";
every other browser I have ends up resolving identifier on outer scope's
activation object.

>
> Expected output would be something* like:
> 1,123,local,[object Window]
>
> * "[object Window]" is not an expectation; everything else is.
>
> Blackberry9000/9500:
> true, function Object() { [native code for Object.Object, arity=1] }
> ,[object Window],[object Window]
>
> The result of first hasOwnProperty("gProp") could be explained by
> the identifier being resolved on activation object's scope chain and
> calling hasOwnProperty using |null| as the |this| value for the function
> call, as in s10.1.6.
>
> | When the call operation is applied to a Reference value whose base
> | object is an activation object, null is used as the this value of the
> | call.

Interesting.

We can also see that [[Prototype]], quite expectedly, "intercepts"
same-named identifier in NFE (since it's injected after AO/VO):

Object.prototype.x = 1;
(function(){
document.write(function x(){
/*
{ x: <function> }

^
^
[[Prototype]] === Object.prototype <== found it there!

^
^
Activation Object
*/
return x; // returns 1, not function object
}());
})();

>
> The implication this has is that any identifier name that coincides with
> with an Object.prototype property will not be found on the enclosing
> scope. Don't name you function "hasOwnProperty", etc.
>
> Function decompilation that expects "[native code]" will fail.

Yep. I mentioned this blackberry representation some time ago —
http://thinkweb2.com/projects/prototype/those-tricky-functions/

Also note that Rhino returns string of a similar pattern.

[...]

--
kangax

kangax

unread,
Oct 22, 2009, 5:53:42 PM10/22/09
to

Yes.

There must be also security implications, such as someone "hijacking"
local, otherwise unreachable (except when using other extensions, such
as SpiderMonkey's `eval` with second arg) variables by augmenting
`Object.prototype`.

I never considered activation object to be something resembling plain
native Object object, which is why your statement brought my attention
in the first place.

>
> I was fairly sure that somewhere in the spec there was an assertion that
> would apply to this object's [[Prototype]], but I could not find one.

Me neither.

> However, there is an assertion that a [[Prototype]] property must exist
> for all objects (including host objects) (Section 8.6.3, paragraph 5 of
> the text) and that the [[Prototype]] property must be either an object
> or be null (paragraph 6 of the same section).

That + section on Activation Object makes for a somewhat ambiguous
interpretation. I'm not surprised. This kind of ambiguity is quite
common in ES3.

>
>>>> Isn't Activation Object just a specification mechanism, with
>>>> unspecified [[Prototype]]?
>>>
>>> Yes, but the activation object becomes the function call's Variable
>>> object and if it did have a [[Prototype]] then
>>> that would always be involved in Identifier resolution from
>>> within a function.
>>
>> Of course.
>>
>> We can actually test if Activation Object has [[Prototype]]
>> referencing something like `Object.prototype` (or
>> `Array.prototype`, etc.). However, [[Prototype]] can also
>> reference some "internal" entity, which we have no way of checking for
>> (and its existence probably doesn't
>> really matter).
>
> yes, and if that 'internal entity' entity only had properties with names
> that could not qualify as Identifiers then there would be nothing that
> could be done to test for implications of its existence.

Good point. Unless, of course, there's proprietary extension allowing to
access Activation Object (making it possible to just use plain property
access).

In Rhino:

(function outer(){
var x = 1;
return (function inner(){
return inner.__parent__['x'];
})();
})();

returns `1` ;)

[...]


--
kangax

0 new messages