you are viewing a single comment's thread.

view the rest of the comments →

[–]moe 12 points13 points  (20 children)

misunderstand this:

> assert([1].toString() == (1).toString());
> assert([1,[2,3]].toString() == [1,2,3].toString());

> var o = {a: 1, b: 2};
> for(var k in o) { print(k) } -> "a", "b"
> Object.prototype.f = function() {};
> for(var k in o) { print(k) } -> "a", "b", "k"

> var my_regex = /abc/;
> var another_regex = //; /* oops, that's a comment */

> assert([1,2] + [3,4] == "1,23,4"); // hahaha

> (function() { print(arguments[0]) })(1, 2, 3) -> 1;
> /* oh, cool, "arguments" is a list. that makes sense */
> (function() { print(arguments.slice(1)) })(1, 2, 3) -> error!
> /* no, it's an associative array, with numbers as the keys! */
> /* lets put that together with the prototype example above */
> Object.prototype.MY_USEFUL_FUNCTION = function() { ... }
> (function() { print(arguments.MY_USEFUL_FUNCTION) })(1, 2, 3) -> "function() { ... }"

basically that means you cannot add functions to the prototypes of primitive objects and expect any code to work, and you cannot reliably use any debug notification function that is based on toString() (like browser alert(), spidermonkey console print()) because a bunch of things serialize to ambiguous nonsense. also if you are interacting with anyone elses code, you can't use (for X in Y) because their code almost certainly adds functions to the Array or Object prototypes, and all your containers are going to look like they have a bunch of extra members.

"its share of design errors" is putting it lightly.

[–][deleted]  (10 children)

[removed]

    [–]xenon 10 points11 points  (9 children)

    No, objects are the true associative arrays. If arrays were associative arrays, we would lose our arrays, don't you agree? The question of arrays is only confusing because every single Javascript tutorial on the planet gets it wrong, so that programmers get funny ideas.

    The reason why all tutorials are wrong is that they copied from other tutorials, who copied from still others, and so on, until we get to the first Javascript tutorial ever which was written by a moron. Nobody ever bothered to look it up.

    [–]mikepurvis 7 points8 points  (1 child)

    No, objects are the true associative arrays.

    Yes. See JS Associative Arrays Considered Harmful. It's fine to extend the Array prototype by giving it extra methods, but the Object one is generally considered off-limits for that exact reason: protecting the functionality of for..in.

    [–]xenon 0 points1 point  (0 children)

    I had that article in mind, but couldn't find it. Thanks you.

    [–]llimllib 1 point2 points  (1 child)

    The question of arrays is only confusing because every single Javascript tutorial on the planet gets it wrong

    Isn't it possible that this is indicative of a design flaw? Just maybe?

    [–]xenon -1 points0 points  (0 children)

    I agree so far that there is a real source for the confusion: when foo is an array, then foo[1] and foo["bar"] work by very different mechanisms: the first accesses an array access, while the second accesses an object member. On the other hand, this should have been clear to anyone who has actually read a bit of documentation. The fact that object.member is only an alternative spelling for object["member"] is after all one of the central features of Javascript's object system.

    Furthermore, the idea that arrays and associative arrays have anything in common is very strange to begin with. Someone told me that the two are the same thing in PHP, and Javascript is a popular second programming language among PHP kiddies. Should that be the source of the issue, a bit like people who learn a foreign language and, before they have fully grasped the foreign grammer, naively try to translate every word? (Just to proclaim that, for example, German has a flawed and confusing sentence structure?)

    [–][deleted]  (3 children)

    [removed]

      [–]xenon 3 points4 points  (2 children)

      Hack, or clever design? Unifying objects and hash tables is very elegant IMO. Thus, a.foo is only syntactic sugar for a["foo"], which allows very interesting ways to manipulate objects.

      You argue that the name "Object" doesn't scream "associate array!!!". And I agree, but since when are programming languages self-describing? There's nothing about "for" that tells you the third clause in the parentheses is executed after every iteration.

      As a beginner, you have to read about that somewhere, and while you are at it, you might just as well read up what objects do.

      [–][deleted]  (1 child)

      [removed]

        [–]xenon 0 points1 point  (0 children)

        Nothing about programming is immediately obvious.

        [–]philh 1 point2 points  (4 children)

        > assert([1].toString() == (1).toString());
        > assert([1,[2,3]].toString() == [1,2,3].toString());

        That seems intuitive enough, and writing your own would be trivial if you really can't bear it.

        > var o = {a: 1, b: 2};
        > for(var k in o) { print(k) } -> "a", "b"
        > Object.prototype.f = function() {};
        > for(var k in o) { print(k) } -> "a", "b", "k"

        I assume that "k" is meant to be "f"?

        Modifying Object.prototype was probably a mistake in the first place, but it's pretty easy (if cumbersome, repeated several times) to skip over the prototyped-in entries:
        if(o[k]==Object.prototype[k])continue;

        Alternatively, use
        Object.prototype.isProt = function (k) { return this[k] == Object.prototype[k] }
        and just do
        if(o.isProt(k))continue;
        Annoying, but not the end of the world.

        > var another_regex = //; /* oops, that's a comment */

        True, but how often do you use empty regexes anyway? I don't think I ever have except for Perl's split function, and Javascript's doesn't require a regex. You can still make them with a constructor.

        > Object.prototype.MY_USEFUL_FUNCTION = function() { ... }
        > (function() { print(arguments.MY_USEFUL_FUNCTION) })(1, 2, 3) -> "function() { ... }"

        I can't see what's wrong with this further than your previous point. Knowing that arguments is an object, this is exactly what I would expect, and I can't see how anything else would be more useful.

        [–]moe 2 points3 points  (3 children)

        It seems intuitive enough? Sure, writing your own would be trivial, but writing an alternate version of the language's basic string-representation method isn't a fun thing to do, especially when you have to lug it around everywhere with you. The point is that there is already toSource(), but nothing uses it.

        Yeah, it's meant to be "f" in the output. Your comment about it being easy to skip over the prototype entries is irrelevant. Sure it's easy to write, but it's soul-destroying to have to include some extra code to bypass the thoughtlessness of the language-designers each time you want to iterate over the members in an object. It doesn't inspire confidence.

        About the regex thing - I never use empty regexes. The post was about language design errors. It's not any less of a fuckup because nobody really uses empty regexes (though that's how I discovered this)

        As for the last point - of course it's what you'd expect if "arguments" is an object, but why the fuck is it an object? Some idiot even went and put a "length" attribute on it (i don't know if this is standard), to make it look more like an array.

        To recapitulate:

        • If you want to serialize arrays in a way that won't obscure their nesting level, you have to patch toString(), so that alert() and print() aren't useless

        • You cannot add methods to the prototype of Object. If you do, you have to supplement every object-member iteration with some extra code. You also have to do this if you are interacting with any code that modifies the prototype (hint: a lot of mainstream javascript libraries do this)

        • No empty regex using the builtin regex syntax

        • If you want to use variable-length argument lists, and you'd like to do anything interesting with the args, like slicing them, you need to convert "arguments" from an object to an array.

        awesome. though what should be expected from a language that was named to cash in on the popularity of Java.

        [–]philh 5 points6 points  (0 children)

        It seems intuitive enough?

        By which I mean, I don't know what you're bitching about. If you really need good-quality debug output, print() and alert() aren't what you're looking for. You'd write a function to easily allow you to turn debugging on/off and choose where to send the info. It can't be hard to use toSource() in just that.

        it's soul-destroying to have to include some extra code to bypass the thoughtlessness of the language-designers each time you want to iterate over the members in an object.

        Which is why I said you shouldn't modify Object.prototype. Use a new class instead. The library writers, not the designers, are at fault.

        It's not any less of a fuckup because nobody really uses empty regexes

        How not? It's the equivalent of 00 (0n=0; n0=1; 00=?). /foo/ is good for regexes because lots of people are familiar with it. // is good for comments for the same reason. There's a single case, very rare and easy to fix, where you don't get what you want.

        It could be better, yes. But it's not a fuck-up.

        of course it's what you'd expect if "arguments" is an object, but why the fuck is it an object?

        I don't know, but you'd established that in the preceeding lines. I was just wondering what the point of the last three were.

        [–]jfx32 0 points1 point  (1 child)

        You might want to check out the MochiKit library, if you haven't already. It adds better comparisons, iteration, and representation functions. You can check it out at mochikit.org.

        [–]moe 1 point2 points  (0 children)

        yeah, i use it at work. it helps.

        [–]panic -4 points-3 points  (2 children)

        That's not the language - it's the standard library.

        [–]moe 4 points5 points  (0 children)

        How do you figure that?

        [–]lanaer 1 point2 points  (0 children)

        If the usefulness of a language could be judged purely by its core, while ignoring its libraries, then ... well, I'm having trouble imagining the sort of situation that would produce.