Spot the bug: javascript queue


  • Discourse touched me in a no-no place

    @Gaska said:

    TRWTF is of course "meaningful" undefined.

    There are languages that state that a value is either present, or it is absent, but it is never undefined (or null). Javascript is not one of those languages.


  • đźš˝ Regular

    @Gaska said:

    Why doesn't V8 do the same? V8, not JS, because it's implementation detail - unless deleted value and undefineded value make semantical difference that actually affects code.

    var arr1 = [], arr2 = [];
    arr1['key'] = arr2['key'] = "something";
    
    delete arr1['key'];
    arr2['key'] = undefined;
    
    console.log(Object.keys(arr1).indexOf('key'));  // -1
    console.log(Object.keys(arr2).indexOf('key'));  //  0
    

    Edit: yes, everyone that already. I just checked.



  • @Zecc said:

    arr['key'] = arr['key'] =

    ???


  • đźš˝ Regular

    Copy+paste error from previous test, where I reused the variable. I fixed the post.



  • @cartman82 said:

    Fields that hold undefined and empty fields act differently with reflection and iteration.

    ... and access. Reading a non-existent property does not necessarily return undefined. If the object has a prototype which defines the property, you get that value instead. Arrays are no different in this regard.



  • @Planar said:

    there's null, and then there's undefined, and then there's "really undefined"

    IMHO undefined is the JS equivalent of a compile time error. In a sense undefined is "nuller" than null. The property/method/parameter/return value is not only unknown; it doesn't even exist at all. It's not part of the program.



  • @Gaska said:

    unless deleted value and undefineded value make semantical difference that actually affects code

    Object.prototype[0] = 42;
    x = [123];
    alert(x);
    x[0] = undefined;
    alert(x);
    delete x[0];
    alert(x);
    

    Filed Under: My brain hurts!


  • Banned

    @fatbull said:

    IMHO undefined is the JS equivalent of a compile time error. In a sense undefined is "nuller" than null. The property/method/parameter/return value is not only unknown; it doesn't even exist at all. It's not part of the program.

    Unless you assigned undefined somewhere - then it exists, as shown above.



  • Except that you can't assign undefined because it's read-only on modern browsers.



  • 🎏 pendant



  • Fun fact: VBA has four five kinds of null.



  • @cartman82 said:

    Nope. He just screwed up.

    Easy mistake to make, since assigning NIL or Nothing or some similar looking thing to an object reference is a fairly common idiom for freeing unwanted objects; the fact that Javascript has an actual global object named undefined was just wrong from the start.

    But in any case, languages that blur the distinction between pointers and the things that they point to are TRWTF.



  • @ben_lubar said:

    you can't assign undefined because it's read-only on modern browsers.

    You can no longer assign another value to it (razzafrazzin modern browsers spoiling good clean fun... mumble). The point at issue here is that you can certainly assign undefined to another variable, and having done so, you end up with a variable containing an actual object reference to the global undefined object.

    If the variable in question happens to be a member of an array, this is not at all the same thing as deleting that member.


  • Discourse touched me in a no-no place

    @flabdablet said:

    If the variable in question happens to be a member of an array, this is not at all the same thing as deleting that member.

    Though the value that previously had a reference to it stored in that array member might be garbage collected if there are no other references to it. IOW, the memory leak is “slow” and due to the array structure itself.



  • Yes, but inexorable since no array members ever get re-used. The queue just leaves a trail of pointers-to-undefined slime behind it as it moves.

    Also, these are Javascript arrays, not real ones, so as well as the pointer-to-undefined value stored in the actual array slot, the slot itself is a whole key->value structure with a string key, and that uses space as well.


  • Discourse touched me in a no-no place

    @flabdablet said:

    Also, these are Javascript arrays, not real ones, so as well as the pointer-to-undefined value stored in the actual array slot, the slot itself is a whole key->value structure with a string key, and that uses space as well.

    The keys are guaranteed to be strings? Ah, that might explain a few things I've seen written about JS performance, and why JS compilers are so necessary to actually get things to go fast enough. (Not that there's anything wrong as such with using strings; I do that a lot as it is very convenient indeed. I don't pretend that it's fast though.)



  • @dkf said:

    The keys are guaranteed to be strings?

    Javascript objects are just key->value hashmaps attached to a function; keys can only be strings, and values can be strings, numbers, object references or nulls (technically, a null is a special form of object reference that doesn't actually reference any object). Attempting to access the value behind a nonexistent key gets you a special internal value which is also the value of the global object undefined and for which the typeof operator and string conversion both return "undefined".

    Javascript arrays are just Javascript objects with a sprinkling of syntactic sugar and a handful of methods and conventions for manipulating keys that happen to be parseable as integers. If you create a Javascript array like

    var foo = ["blort", "meep", "zorp", "foon"]

    then the underlying hashmap will contain "0"->"blort", "1"->"meep", "2"->"zorp", "3"->"foon", "length"->4.

    Javascript's array-indexing operator [ ] is also a generalized object property lookup operator: foo.ping means the same thing as foo["ping"]. You can use the ["name"] form when accessing a property whose key doesn't conform to the rules for Javascript identifiers, which makes the .name form illegal.

    You can also use it to access a property whose name is contained in another variable:

    var stuff = "gleet";
    var ick = pustule[stuff]

    does the same thing as

    var ick = pustule.gleet;.

    Strings parseable as integers are not valid identifiers, so you have to use the [ ] form to access properties with such strings as their keys. Finally, any key handed to the [ ] operator will be cast to string. Together, these rules let you write stuff like foo[3] which would be an array lookup in any sane language, but is actually a lookup for a property named "3" of object foo in Javascript.

    There is also nothing stopping you from then doing foo.ping = quack (or the equivalent foo["ping"] = quack) and stuffing a value with a non-numeric key into your array. Such a value will come out if you use for .. in to iterate over array members, just as it would for using for .. in to iterate over object properties - because that's exactly what you are doing: arrays are objects.

    The .length property on arrays doesn't show up in a for .. in loop because it's marked internally as non-enumerable, but if somebody has been careless with adding properties to Array.prototype, you can still get array "indices" you weren't anticipating. This, along with the lack of a guaranteed order of iteration for for .. in, is why Javascript best practice for iterating over arrays is to use for (i = 0; i < whatever.length; ++i) instead; that way you only see numeric indexes and you see them in the expected order.

    Of course, that can be very inefficient for large sparse arrays. Probably better to use for .. in along with a hasOwnProperty() test for those.







  • You generated a new URL for the exact same code example, congratulations. Get out the champagne.

    Look, to spell it out, I was trying to reconcile your statements:

    @flabdablet said:

    Javascript objects are just key->value hashmaps attached to a function; keys can only be strings,

    @flabdablet said:

    Javascript arrays are just Javascript objects with a sprinkling of syntactic sugar

    With the fact that dozens of times in the past I've used DOM objects as keys in arrays. Unless you consider a crucially-important feature like being able to use a non-string key as "syntactic sugar", I think we got a problem here.



  • Sorry, I have a visual processing disorder that lowers jsfiddle's usability for me. Why the fuck can't it have a decent CLI? Edited.



  • @blakeyrat said:

    dozens of times in the past I've used DOM objects as keys in arrays

    Then I hope for your employers' sake that each such object has had a unique string representation. As I mentioned:

    @flabdablet said:

    any key handed to the [ ] operator will be cast to string



  • I'm not sure what I did differently but it worked.

    Huh. Oh well, I don't work in JS much anymore.



  • @blakeyrat said:

    I'm not sure what I did differently but it worked.

    Any clue here?

    http://jsfiddle.net/nmwfn2kb/2/



  • ... I also don't care.



  • But it's crucially important!

    Filed under: blakey said it and that makes it true


  • đźš˝ Regular

    @blakeyrat said:

    I've used DOM objects as keys in arrays

    #D-8



  • @RaceProUK said:

    If the queue is used often enough, you'll get integer overflow.

    Ironically enough, a silent integer overflow would have worked. But since JS doesn't use integers, you get something much more fun: https://jsfiddle.net/h7hkL94d/


  • BINNED



  • If I were the King of Javascript, I'd get rid of the ReferenceError exception and the global undefined object and add an extra primitive value called nonexistent.

    Any attempt to retrieve the value of a nonexistent variable or object property would result in a value of nonexistent rather than raising an exception, thus removing the special case treatment for variables and allowing their true nature as properties of either the enclosing function's ActivationObject or the global object to shine through, and removing the ambiguity that presently exists between the results of attempting to read a never-created object property vs. one that has been created but never assigned a value.

    undefined would be a reserved word used solely for expressing the undefined value literally. Comparing things to undefined would still work (and it would still be falsy, allowing the if (!foo) foo = "defined now" pattern) but any attempt to assign undefined to anything would raise an UndefinedError exception: the meaning of undefined is that no value has ever been assigned to the associated item, which makes assigning undefined an oxymoron (you want an explicit "has no value" value? That's what null is for). Nor would it be allowed in object and array literals. If you wanted an object literal to include properties that have no initial values, it would look like this:

    var whatever = {
        blank,
        empty,
        "nothing in this one either",
        foo = "bar",
        "are we having fun yet" = "yow!"
    }    
    

    (note the use of = instead of : because I can see no reason why object property initializers ought to use a different assignment operator from variable declarations).

    Array literals would allow indexes to be explicitly set as well as multiple successive commas, making for convenient creation of sparse arrays:

    var sparse = [
        "zero",
        "one",,,
        "four",
        62 = "fifty-twelve!",
        "sixty-three"
    ]
    

    Assigning nonexistent would be legal and would result in the destruction of the assignee, letting me lose the delete operator to unreserve a useful word.

    Lèse-majesté would be punishable by having your keytops set to AZERTY pattern, your keyboard map set to Dvorak, and double-quote remapped as a compose key for umlauts.



  • @flabdablet said:

    (note the use of = instead of : because I can see no reason why object property initializers ought to use a different assignment operator from variable declarations).

    var x = 1;
    var y = [
        x = x + 1,
        x = x + 1,
        x = x + 1,
        x = x + 1,
        x = x + 1,
        x = x + 1,
        x = x + 1
    ];
    

    ???


  • FoxDev

    ....... multi assignment in array creation?



  • Syntax error; indexes to the left of an = in an array literal have to be literal numbers. If you want to add array elements with computed indexes, you'll need to do that explicitly after assigning the literal.



  • var x = null;
    var y = {x: x = new Date};
    


  • var x = 1;
    var y = [
    (x = x + 1),
    (x = x + 1),
    (x = x + 1),
    (x = x + 1),
    (x = x + 1),
    (x = x + 1),
    (x = x + 1)
    ];

    would be perfectly legal, and equivalent to

    var x = 8;
    var y = [2, 3, 4, 5, 6, 7, 8];
    

    I don't think the use of assignment expressions inside array literals is likely to be common enough to warrant precluding the otherwise elegant use of = for index assignment.


  • đźš˝ Regular

    You could change that example to an object literal. And then throw an error for having repeated assignments to the same key.

    @ben_lubar: the sensible semantics is for the RHS expressions to use values before any of the assigment. Compare to:

    [x, y] = [y, x]; // swap values
    

    Hanzo'd. But I stand by my opinion.



  • @ben_lubar said:

    var x = null;
    var y = {x: x = new Date};

    That one should read

    var x = null;
    var y = {x = x = new Date};
    

    and deserves a spanking in meatspace but no complaint from the parser.


  • FoxDev

    @Zecc said:

    [x, y] = [y, x]

    ... :wtf:



  • x = x = y doing something different from x = y scares me.



  • @Zecc said:

    You could change that example to an object literal. And then throw an error for having repeated assignments to the same key.

    This proposal has royal assent.


  • đźš˝ Regular

    @accalia said:

    ... :wtf:


    No repro (but I defined a :Ρ)



  • @ben_lubar said:

    x = x = y doing something different from x = y scares me.

    Which is why you'll get a spanking for doing that.


  • đźš˝ Regular

    @flabdablet said:

    spanking

       👑
    <span>


  • FoxDev

    apparently that's not portable javascript (i'd defined a previously, it was out of screenshot)


  • đźš˝ Regular

    It's possible FF uses ES6 by default.

    Come to think of it, ISTR it already had destructuring assigments before it was proposed.


  • FoxDev

    @Zecc said:

    ES6

    oooh.

    that reminds me i want to play with that, but i'm waiting for node.js to have a bit better support (well namely for the linters to have better support)




  • FoxDev

    yes, yes. go has that functionality. so does python and i'd rahter python than go.

    :-P



  • @ben_lubar said:

    x = x = y doing something different from x = y scares me.

    On second thought, you're right. They should do the same thing.

    Be it hereby decreed that property names appearing to the left of the first = operator of a property definition inside an object literal shall be treated for expression evaluation purposes as variables whose scope is restricted to the literal, the whole literal and nothing but the literal.

    Oyez, they shall be hoisted, and if read in expressions occurring before their point of definition within the literal, shall evaluate as undefined in the customary blakey-enraging fashion.



  • Can python compile to JavaScript?


Log in to reply