# JavaScript. Array "extras" in detail.

Discussion in 'Javascript' started by Dmitry A. Soshnikov, Feb 23, 2011.

1. ### Dmitry A. SoshnikovGuest

Dmitry A. Soshnikov, Feb 23, 2011

2. ### Dr J R StocktonGuest

In comp.lang.javascript message <ik3a4c$sng$-
september.org>, Wed, 23 Feb 2011 18:46:05, Dmitry A. Soshnikov
<> posted:

>A new article written specially for Opera software:
>
>JavaScript. Array "extras" in detail.
>
>http://dev.opera.com/articles/view/javascript-array-extras-in-detail/

Interesting.

Reminds me of <http://en.wikipedia.org/wiki/Jensen%27s_Device>.

increase my chances of finding it again.

--
(c) John Stockton, nr London, UK. ?@merlyn.demon.co.uk Turnpike v6.05.
Website <http://www.merlyn.demon.co.uk/> - w. FAQish topics, links, acronyms
PAS EXE etc. : <http://www.merlyn.demon.co.uk/programs/> - see in 00index.htm
Dates - miscdate.htm estrdate.htm js-dates.htm pas-time.htm critdate.htm etc.

Dr J R Stockton, Feb 24, 2011

3. ### Dmitry A. SoshnikovGuest

On 24.02.2011 23:22, Dr J R Stockton wrote:
> In comp.lang.javascript message<ik3a4c$sng$-
> september.org>, Wed, 23 Feb 2011 18:46:05, Dmitry A. Soshnikov
> <> posted:
>
>> A new article written specially for Opera software:
>>
>> JavaScript. Array "extras" in detail.
>>
>> http://dev.opera.com/articles/view/javascript-array-extras-in-detail/

>
> Interesting.
>
> Reminds me of<http://en.wikipedia.org/wiki/Jensen%27s_Device>.
>

Yeah, actually roots of this idea (of the parametrized list handling)
went to also to math. There, mathematician are used to operate with the
concept of _a sum_ (regardless the sum of _what_ exactly). They have a
special higher-order function (HOF) of summation with the known sign --
âˆ‘ (∑).

My example with a generic sum is exactly a direct reflection of this
math concept. And as a consequence, higher-order functions can be
applied for any manipulation on the sequences/lists/arrays. That's the
reason they are available in all functional programming langauges
(including JS which supports this style of programming, since all
functions here are "first-class" and can be passed to HOFs).

> increase my chances of finding it again.
>

Yeah, thanks.

Dmitry.

Dmitry A. Soshnikov, Feb 25, 2011
4. ### Michael Haufe (\TNO\)Guest

On Feb 25, 5:30 am, "Dmitry A. Soshnikov" <>
wrote:
[...]
> My example with a generic sum is exactly a direct reflection of this
> math concept. And as a consequence, higher-order functions can be
> applied for any manipulation on the sequences/lists/arrays. That's the
> reason they are available in all functional programming langauges
> (including JS which supports this style of programming, since all
> functions here are "first-class" and can be passed to HOFs).

[...]

It is unfortunate that JavaScript couldn't be a bit less clunky in the
functional style:

["1","2","3"].map(parseInt); //[1, NaN, NaN]

Michael Haufe (\TNO\), Feb 25, 2011
5. ### Lasse Reichstein NielsenGuest

"Michael Haufe (\"TNO\")" <> writes:

> It is unfortunate that JavaScript couldn't be a bit less clunky in the
> functional style:
>
> ["1","2","3"].map(parseInt); //[1, NaN, NaN]

Don't blame your tools. The map function passes three arguments to
the function, and parseInt expects two. What you want is probably:
["1","2","3"].map(function(x) { return parseInt(x, 10); });

/L
--
Lasse Reichstein Holst Nielsen
'Javascript frameworks is a disruptive technology'

Lasse Reichstein Nielsen, Feb 25, 2011
6. ### Michael Haufe (\TNO\)Guest

On Feb 25, 11:05 am, Lasse Reichstein Nielsen <>
wrote:
> "Michael Haufe (\"TNO\")" <> writes:
>
> > It is unfortunate that JavaScript couldn't be a bit less clunky in the
> > functional style:

>
> > ["1","2","3"].map(parseInt); //[1, NaN, NaN]

>
> Don't blame your tools. The map function passes three arguments to
> the function, and parseInt expects two. What you want is probably:
>  ["1","2","3"].map(function(x) { return parseInt(x, 10); });

Alternatively for this example: ["1","2","3"].map(Number);

The point is that it is often the case that solutions like yours are
necessary in these types of methods which I find clunky.

Michael Haufe (\TNO\), Feb 25, 2011
7. ### Ry NohrybGuest

On Feb 25, 7:03 pm, "Michael Haufe (\"TNO\")"
<> wrote:
> On Feb 25, 11:05 am, Lasse Reichstein Nielsen <>
> wrote:
>
> > "Michael Haufe (\"TNO\")" <> writes:

>
> > > It is unfortunate that JavaScript couldn't be a bit less clunky in the
> > > functional style:

>
> > > ["1","2","3"].map(parseInt); //[1, NaN, NaN]

>
> > Don't blame your tools. The map function passes three arguments to
> > the function, and parseInt expects two. What you want is probably:
> >  ["1","2","3"].map(function(x) { return parseInt(x, 10); });

>
> Alternatively for this example: ["1","2","3"].map(Number);
>
> The point is that it is often the case that solutions like yours are
> necessary in these types of methods which I find clunky.

Not clunky, no, if you put garbage in you get garbage out.
--
Jorge.

Ry Nohryb, Feb 26, 2011
8. ### Michael Haufe (\TNO\)Guest

On Feb 26, 4:50 am, Ry Nohryb <> wrote:

> Not clunky, no, if you put garbage in you get garbage out.

If a construct is not intuitive and requires extra boilerplate to make
it work, it can be considered clunky. Having to use "function()
{ return ... }" or similar to massage parameters is not something to
smile at. \be's shorter function syntax will help a bit in this area
"#(x) { x * x }", but even this only dulls the pain of having to do it
in the first place. Compare code similar to the above with other
functional languages such as Miranda, Haskell, OCaml, SML, F#, popular
Lisp languages and others, and you'll see what I mean. These array
"extras" and "Array generics" go quite far to help enable a more
functional programming style in JS but with the choices made in their
signatures it has made it painful to perform one of the most important
important aspects of developing in the functional style : composition.
irt being non-intuitive, if you've used one or more of the above
languages little things like this are probably going to bite you more
than once. I'm not trying to rally against these new array methods,
but simply showing that there is another side of the coin.

Michael Haufe (\TNO\), Feb 26, 2011
9. ### Lasse Reichstein NielsenGuest

"Michael Haufe (\"TNO\")" <> writes:

> On Feb 26, 4:50 am, Ry Nohryb <> wrote:
>
>> Not clunky, no, if you put garbage in you get garbage out.

>
>
> If a construct is not intuitive and requires extra boilerplate to make
> it work, it can be considered clunky.

What part of the construct is it that is not intuitive here?

My guess is the fact that map actually passes three arguments, not
just one, which differs from, e.g., Lisp's map-car or Scheme's map.
But that's actually very much a Javascript-like feature.

> Having to use "function()
> { return ... }" or similar to massage parameters is not something to
> smile at. \be's shorter function syntax will help a bit in this area
> "#(x) { x * x }", but even this only dulls the pain of having to do it
> in the first place. Compare code similar to the above with other
> functional languages such as Miranda, Haskell, OCaml, SML, F#, popular
> Lisp languages and others, and you'll see what I mean.

Notice that neither of those languages allow you to call a function with
fewer or more arguments than what you expect. That means that you won't
even typecheck (for the statically typed langauges) if your map passed
three arguments and you function expected two.

The same function would fail in Lisp and Scheme, if map passed three
arguments.

If you had a map function passing three arguments in SML, you would
still have to write
map myList (fn (x,i,l) => myUnaryFunction(x))
to use it with an unary function.

Javascript is unique among the functional languages you mention in that
you can pass too few or too many arguments to a function. That's why they
allowed themselves to let map pass three arguments instead of just one.

If you have a function expecting just one argument, then it still works.

What you did here was to pass a function that expected two arguments
(but would work with only one) and you got predictably incorrect
results to a function calling it with three arguments, where the second
did not work as a second argument for the first function.

> These array "extras" and "Array generics" go quite far to help
> enable a more functional programming style in JS but with the
> choices made in their signatures it has made it painful to perform
> one of the most important important aspects of developing in the
> functional style : composition.

If your functions don't allow a variable number of arguments, then
there is no problem - it will ignore any surplus arguments.

The way Javascript is designed, that's sadly not something you can
rely on.

> irt being non-intuitive, if you've used one or more of the above
> languages little things like this are probably going to bite you more
> than once. I'm not trying to rally against these new array methods,
> but simply showing that there is another side of the coin.

The Javascript array functions differ from similar list-functions in
other languages. That's both good and bad - they actually fit
Javascript well, since the language allows optional arguments so
easily, but they bite you when you combine two different ways of being
optional (passing potentially unnecessary extra arguments to a
function expecting optional arguments, where the user thinks just of
the one-argument case).

/L 'Never call parseInt with only one argument'.
--
Lasse Reichstein Holst Nielsen
'Javascript frameworks is a disruptive technology'

Lasse Reichstein Nielsen, Feb 27, 2011
10. ### Michael Haufe (\TNO\)Guest

On Feb 27, 6:16 am, Lasse Reichstein Nielsen <>
wrote:
> "Michael Haufe (\"TNO\")" <> writes:
>
> > On Feb 26, 4:50 am, Ry Nohryb <> wrote:

>
> >> Not clunky, no, if you put garbage in you get garbage out.

>
> > If a construct is not intuitive and requires extra boilerplate to make
> > it work, it can be considered clunky.

>
> What part of the construct is it that is not intuitive here?
>
> My guess is the fact that map actually passes three arguments, not
> just one, which differs from, e.g., Lisp's map-car or Scheme's map.

Yes

> But that's actually very much a Javascript-like feature.
>
> > Having to use "function()
> > { return ... }" or similar to massage parameters is not something to
> > smile at. \be's shorter function syntax will help a bit in this area
> > "#(x) { x * x }", but even this only dulls the pain of having to do it
> > in the first place. Compare code similar to the above with other
> > functional languages such as Miranda, Haskell, OCaml, SML, F#, popular
> > Lisp languages and others, and you'll see what I mean.

>
> Notice that neither of those languages allow you to call a function with
> fewer or more arguments than what you expect.

Fewer is allowed, but not more. (currying) Unless you are referring to
Lisp/Scheme only by saying "neither"?

> That means that you won't
> even typecheck (for the statically typed langauges) if your map passed
> three arguments and you function expected two.
>
> The same function would fail in Lisp and Scheme, if map passed three
> arguments.
>
> If you had a map function passing three arguments in SML, you would
> still have to write
>    map myList (fn (x,i,l) => myUnaryFunction(x))
> to use it with an unary function.

Of course since mutability is avoided, the third argument would have
little reason to exist. For the second it's a little meaningless since
the use case are hard to find. In fact I don't think there is even an
(indexof foo) style function in the standard lib.

> Javascript is unique among the functional languages you mention in that
> you can pass too few or too many arguments to a function.

Not quite... <http://mlton.org/Fold>

Unless you want to compare arbitrary size tuples to JS arguments.

> That's why they
> allowed themselves to let map pass three arguments instead of just one.
>
> If you have a function expecting just one argument, then it still works.
>
> What you did here was to pass a function that expected two arguments
> (but would work with only one) and you got predictably incorrect
> results to a function calling it with three arguments, where the second
> did not work as a second argument for the first function.

Yes. It looks like a similar discussion as this one is going on here:
<http://www.wirfs-brock.com/allen/posts/166>.
Also here <http://whereswalden.com/2011/02/26/the-proper-way-to-call-

> > These array "extras" and "Array generics" go quite far to help
> > enable a more functional programming style in JS but with the
> > choices made in their signatures it has made it painful to perform
> > one of the most important important aspects of developing in the
> > functional style : composition.

>
> If your functions don't allow a variable number of arguments, then
> there is no problem - it will ignore any surplus arguments.
>
> The way Javascript is designed, that's sadly not something you can
> rely on.

The identity crises strikes again.

> > irt being non-intuitive, if you've used one or more of the above
> > languages little things like this are probably going to bite you more
> > than once. I'm not trying to rally against these new array methods,
> > but simply showing that there is another side of the coin.

>
> The Javascript array functions differ from similar list-functions in
> other languages. That's both good and bad - they actually fit
> Javascript well, since the language allows optional arguments so
> easily, but they bite you when you combine two different ways of being
> optional (passing potentially unnecessary extra arguments to a
> function expecting optional arguments, where the user thinks just of
> the one-argument case).

In one of the links above there was a suggestion of adding
Function.prototype.only(...) as a solution. Though I find that just as
bad since in the case of parseInt you still have to know there was a
problem in the first place requiring this type of solution.

Michael Haufe (\TNO\), Feb 27, 2011
11. ### Thomas 'PointedEars' LahnGuest

Lasse Reichstein Nielsen wrote:

> "Michael Haufe (\"TNO\")" <> writes:
>> It is unfortunate that JavaScript couldn't be a bit less clunky in the
>> functional style:
>>
>> ["1","2","3"].map(parseInt); //[1, NaN, NaN]

>
> Don't blame your tools. The map function passes three arguments to
> the function, and parseInt expects two. What you want is probably:
> ["1","2","3"].map(function(x) { return parseInt(x, 10); });

Or

/* [1, 2, 3] */
[,, "1","2","3"].map(parseInt).slice(2);

PointedEars
--
realism: HTML 4.01 Strict
evangelism: XHTML 1.0 Strict
-- Bjoern Hoehrmann

Thomas 'PointedEars' Lahn, Mar 27, 2011
12. ### VKGuest

On Feb 23, 7:46 pm, "Dmitry A. Soshnikov" <>
wrote:
> A new article written specially for Opera software:
>
> JavaScript. Array "extras" in detail.
>
> http://dev.opera.com/articles/view/javascript-array-extras-in-detail/

An interesting outcome for forEach from some Javascript features:
1) JavaScript Array allowed to be sparse
2) An array element can be
a) initialized and value assigned such as arr[1] for arr=[1,2,3]
b) initialized but no value assigned (Empty by VBA) such as arr[10]
for arr=new Array(100)
c) not initialized (undefined) such as arr[10] for arr=[1,2,3]
but Javascript takes a) and b) as the same case
3) Javascript allows to assign undefined values so it allows to
produce epistemologically mysterious variables with assigned value
"variable has not been assigned a value".

All this together makes the fact that in Javascript array an elision
and undefined mean different things and act differently. In the
particular, in array [1,,2] forEach method will see only two elements
to deal with and in array [1,undefined,3] forEach will see three
elements.
Respectively in Javascript array [1,2,3]
delete arr[0]; // 2 members forEach
and
arr[0] = undefined; // still 3 members forEach
are different things with different results.

All this may seem very obvious and logical for people who really
understand Javascript. For others (like myself) mentioning that in

VK, Mar 29, 2011
13. ### VKGuest

On Mar 29, 11:48 am, VK <> wrote:
> takes a) and b) as the same case

takes b) and c) as the same case

VK, Mar 29, 2011
14. ### VKGuest

On Mar 29, 1:21 pm, Stefan Weiss <> wrote:
> Depends on what you mean by "initialized". Going from the examples you
> give, it looks like you call an element "initialized" when its index is
> less than the array's length.

Right. More formally: an element that is located within the currently
defined array borders. This is what reported as Empty (as opposed to
Undefined or Null) in Visual Basic and VBA.

> That may be significant in other
> languages, but it isn't in JavaScript. The .length property, whether set
> explicitly via 'arr.length' and 'new Array(n)', or implicitly by
> assigning to arr[largerNumber], has nothing to do with creating or
> initializing any indices (properties) in the array.

It is true for any language. I am not aware of a language that on say
its analogy for
new Array(4294967294)
would loop 4,294,967,294 times making some preliminary
initializations

> Case in point: your example in b), new Array(100), does not create all
> the elements from 0 to 99, it only sets the .length property of the
> array. That's all. arr[10] evaluates to undefined for the same reason
> that arr["ten"] would: the property doesn't exist.

Once I had a discussion on it in this group. It all depends on the
level of abstraction one chooses. One can look at Array as an array.
One can look at it as a regular object with a fancy auto-updating
property added. One can say that
var arr = new Array(100);
creates an array with 100 elements in it which are all initialized but
not assigned.
The other can say that that creates a generic Object, sets its
prototype to Array prototype and sets its auto-updating property
"length" to 100.
Both are right but IMO the second one doesn't exactly speak about
Javascript: she is one level lower than needed.
It's just like with types in Javascript. Javascript is a dynamically
typed ("loosely typed" as haters call it) language. That means that
any variable at some given moments has certain type but this type can
be dynamically changed by assigning value of another type. That is
different from VBScript which is typeless or more exactly any variable
is of the same universal type Variant.
Yet an XPCOM programmer will say that in Gecko's JavaScript all
variables are of the same universal type, just like in VBScript. She
will be right as well but from her level which is again one level
lower than needed to talk about a programming language as about a
programming language per se.

> An index (property) will only exist if you create it by assigning
> something to it. This can be done by assigning to arr[n], or by giving
> it a value in an array literal.
> (There's also the alternative Array constructor form with more than one
> argument, but the less said about that the better. I suppose
> Object.defineProperty() might also be used, but I can't test that at the
> moment).
>
> None of this has much to do with the length of the array, except that it
> will be automatically adjusted behind the scenes when you assign to an
> index greater or equal to the value of the .length property.

So you prefer to talk from behind the scene and I do on the scene

> It may help to keep the difference between indices (=properties) and
> values in mind. Remember, undefined is a value, too. In your last
> example, something like 'arr[3] = undefined' would actually increase the
> length of the array instead of removing an element.

As I said, my problems with
var x = undefined;
and the like are epistemological and not technical. I do understand
the programmatic outcome yet I refuse to take as sensual "variable
with assigned value 'variable has not been assigned a value'".

> The elision syntax is a special case. IMHO, elisions are unintuitive and
> generally not very useful. I think it's best to avoid them altogether.

They are definitely a very rare bird, just like named for{} loops. Yet
it might be a situation when one needs to create (automatically server-
side for instance) sparse array with gaps here and there and to make
sure that forEach will work only with assigned array members. Then she
needs to know that elisions will do the work
[0,1,2,3,,,6,,8]
and undefined will not
[0,1,2,3,undefined,undefined,6,undefined,8]

VK, Mar 29, 2011
15. ### John G HarrisGuest

On Tue, 29 Mar 2011 at 05:52:27, in comp.lang.javascript, VK wrote:

<snip>
>I am not aware of a language that on say
>its analogy for
> new Array(4294967294)
>would loop 4,294,967,294 times making some preliminary
>initializations

<snip>

Try C++.

John
--
John Harris

John G Harris, Apr 5, 2011
16. ### VKGuest

On Apr 5, 1:50 pm, John G Harris <> wrote:
> On Tue, 29 Mar 2011 at 05:52:27, in comp.lang.javascript, VK wrote:
>
>   <snip>>I am not aware of a language that on say
> >its analogy for
> > new Array(4294967294)
> >would loop 4,294,967,294 times making some preliminary
> >initializations

>
>   <snip>
>
> Try C++.

Uhm... I am not a C++ memory management expert but this article says:
http://www.cplusplus.com/doc/tutorial/arrays/
"When declaring a regular array of local scope (within a function, for
example), if we do not specify otherwise, its elements will not be
initialized to any value by default, so their content will be
undetermined until we store some value in them."

From the point of view of the sanity for say
long double arr[4294967294];
the maximum I would expect is an early warning from the compiler that
the current RAM size doesn't allow to initialize all 4,294,967,294
elements of the given type. If the engine indeed loops 4,294,967,294
times for the above statement then it is not wonder at all that C++ers
escaping to Javascript left and right

VK, Apr 5, 2011
17. ### Lasse Reichstein NielsenGuest

VK <> writes:

> On Apr 5, 1:50 pm, John G Harris <> wrote:
>> On Tue, 29 Mar 2011 at 05:52:27, in comp.lang.javascript, VK wrote:
>>
>>   <snip>>I am not aware of a language that on say
>> >its analogy for
>> > new Array(4294967294)
>> >would loop 4,294,967,294 times making some preliminary
>> >initializations

>>
>>   <snip>
>>
>> Try C++.

>
> Uhm... I am not a C++ memory management expert but this article says:
> http://www.cplusplus.com/doc/tutorial/arrays/
> "When declaring a regular array of local scope (within a function, for
> example), if we do not specify otherwise, its elements will not be
> initialized to any value by default, so their content will be
> undetermined until we store some value in them."

That might hold for local arrays of primitive values, but try doing
it for a type with a default constructor.

> From the point of view of the sanity for say
> long double arr[4294967294];
> the maximum I would expect is an early warning from the compiler that
> the current RAM size doesn't allow to initialize all 4,294,967,294
> elements of the given type.

Not if compiling for 64-bit (although you might want to make the constant
either unsigned or long). The compiler won't know the size of memory on
the computer where it will be run, so at best it can give a warning.

But why guess. I just happen to have a C++ compiler lying around

-- bigarray.cc --
class ByteBox {
public:
ByteBox() : byte(0) { }
unsigned char byte;
};

int main(int argc, char* argv) {
ByteBox big_array[4294967294u];
return big_array[0].byte;
}
--

It compiles happily as 64-bit code. It won't run (the stack's not big enough
to stack-allocate that, that would require 16Gb stack in this case).
Disassembling the code, you can see that it actually would have tried to
initialize the entire array.

Now try non-stack allocation, which arguably better matches the JS example:

-- bigarray2.cc --
class ByteBox {
public:
ByteBox() : byte(0) { }
unsigned char byte;
};

int main(int argc, char* argv[]) {
ByteBox* big_array = new ByteBox[4294967294u];
unsigned char res = big_array[0].byte;
delete[] big_array;
return res;
}
--

Try to run that, and it will spend a gazillion years initializing
memory, while swapping a lot. But it will run.

> If the engine indeed loops 4,294,967,294 times for the above
> statement then it is not wonder at all that C++ers escaping to
> Javascript left and right

In C++, you get what you ask for, no hands held, no holds barred.
Rope enough to both hang yourself and still have wiggle-room enough to
shoot yourself in the foot too.

/L
--
Lasse Reichstein Holst Nielsen
'Javascript frameworks is a disruptive technology'

Lasse Reichstein Nielsen, Apr 6, 2011
18. ### John G HarrisGuest

On Wed, 6 Apr 2011 at 18:16:45, in comp.lang.javascript, Lasse
Reichstein Nielsen wrote:
>VK <> writes:

<snip>
>> If the engine indeed loops 4,294,967,294 times for the above
>> statement then it is not wonder at all that C++ers escaping to
>> Javascript left and right

>
>In C++, you get what you ask for, no hands held, no holds barred.
>Rope enough to both hang yourself and still have wiggle-room enough to
>shoot yourself in the foot too.

True. C++ is not for bad programmers. They prefer to write bad libraries
for web pages that stop people buying things.

John
--
John Harris

John G Harris, Apr 7, 2011
19. ### VKGuest

Reichstein Nielsen wrote:
> >In C++, you get what you ask for, no hands held, no holds barred.
> >Rope enough to both hang yourself and still have wiggle-room enough to
> >shoot yourself in the foot too.

I see your "ideal programming environment" to be a kind of a pigheaded
yet highly dutiful solder who does everything literally as being said:
In this case assembly language leaves far behind not only C++ but C as
well. And the whole history of the programming becomes the story of
lost freedom and going away from the ideal

John G Harris wrote:
> True. C++ is not for bad programmers. They prefer to write bad libraries
> for web pages that stop people buying things.

Oh yes. This is why only bad Javascript libraries exist while any C++
library is a superior quality product by the very nature of the
language. ) The only real difference is that Javascript source code
is always available for viewing and analyzing when C++ source is
usually mercifully hidden from our eyes by the compiler. I am saying
"mercifully" because otherwise jQuery soon become for you a sample of
programming culture and professionalism

VK, Apr 18, 2011
20. ### John G HarrisGuest

On Mon, 18 Apr 2011 at 12:13:35, in comp.lang.javascript, VK wrote:

<snip>
>John G Harris wrote:
>> True. C++ is not for bad programmers. They prefer to write bad libraries
>> for web pages that stop people buying things.

>
>Oh yes. This is why only bad Javascript libraries exist while any C++
>library is a superior quality product by the very nature of the
>language. ) The only real difference is that Javascript source code
>is always available for viewing and analyzing when C++ source is
>usually mercifully hidden from our eyes by the compiler. I am saying
>"mercifully" because otherwise jQuery soon become for you a sample of
>programming culture and professionalism

On the contrary. A C++ library's header files have to be visible to the
user, so revealing much of the design. That's why so many people said
Yuk! about Microsoft's MFC windows library. The difference from JQuery
is that Microsoft made sure their compilers stayed compatible with MFC.
And they didn't boast about it being good enough, and scream at anyone
who didn't like it.

John
--
John Harris

John G Harris, Apr 19, 2011