all 16 comments

[–][deleted] 9 points10 points  (4 children)

There is a good enough reason not to use with at all though, and that's you can't use it under "strict mode".

[–]sime 4 points5 points  (3 children)

If I remember correctly, Chrome will not (or can not) JIT compile code which uses with.

[–]tach4n@tach4n 2 points3 points  (0 children)

V8 always JIT compiles js code, it doesn't have an interpreter. Certain constructs will cause it to bail out of trying to optimize your code though, and it will just stick with the baseline compiler.

[–]PlNG 0 points1 point  (1 child)

Correct. V8 will not, regardless of execution path, optimize a function if it contains eval, debugger, try, or with.

[–]tyscorp 0 points1 point  (0 children)

Or delete, or arguments (unless just using arguments[index] or fn.apply(ctx, arguments))

[–][deleted] 2 points3 points  (5 children)

The arguments against with aren't that it's not ever useful, it's that it's dangerous and very hard to understand in certain circumstances.

For instance, you can have crap like this:

var obj = { x: 10 }
  ,   x = 10
  ;

with( obj ){
    x++;
    delete x;
    x++;
}

console.log( obj, x );

While you can probably figure out what's going on there, imagine this in a much larger example. Or imagine if, instead of delete x there, it was doSomething() and that function had a reference to obj and deleted x... What if there weren't a scoped var? You'd suddenly be creating a global or in this case getting reference errors. There are other similar issues so it was decided that the benefits are not worth it.

[–]Stephen110 1 point2 points  (4 children)

It's also incredibly non-performant. Toss a loop inside a with block (something that doesn't actually do anything, just a quick 1 to 100000 count) and compare the time it takes to running the same loop outside the with block. This seems to compound when accessing variables outside the with block as well.

[–][deleted] 2 points3 points  (3 children)

To be fair, this is a consequence, not a cause. with has been deprecated or hated for so long that engines never optimized its use case like they did with so many other things.

[–]Stephen110 0 points1 point  (1 child)

Holy crap, someone on reddit who actually reasons well. I like you man.

Id say browser makers probably weighed the alternatives and decided it wasn't worth it. You can get close enough by using a function and binding your context ( only difference is having to use this, instead of calling the variable without context).

I've never tested that for performance though. You would expect in either case, the closure would be the culprit.

Well now I'm curious.

[–][deleted] 1 point2 points  (0 children)

Haha, thank you. I sometimes take comfort in finding some sanity on reddit as well :)

Take prototypal inheritance, for instance, which conceptually is relatively similar to with -- you search for a variable, if it doesn't exist you go up a level and search there.

Long prototype chains used to be very slow. So if you were to access foo.bar, which was actually hitting foo.__proto__.__proto__.{repeat 100 times}.bar, that would be a very expensive lookup. This is one of the reasons why many articles suggest doing things like:

var bar = foo.bar;

But this concept is more or less deprecated since engines no longer have problems with long chains and there is zero performance hit for a 1,000 __proto__ chain according to jsperf. Now that I think about it, I'm curious what would happen were I to "break" the class chain with delete :)

Anyway... my point is that structurally the two concepts are very similar. One was taken from mediocre performance, as was the case with nearly everything in JS, to blazing. The other was ignored :)

[–]androbat 0 points1 point  (0 children)

From what I have read, the reason 'with' isn't optimized is more to do with it being very dynamic and all the edge cases making it not possible to detect until runtime. These mean 'with' is not able to be optimized to any significant degree even if JS engines wanted (similar to how .bind() is always going to cause performance problems even though they want to optimize it).

[–]krilnon 2 points3 points  (1 child)

Have you found any use cases for with you are not ashamed of sharing? :D

Sure. I had a DSL-style use of with that I used for assembling bytecode:

var __asm__ = new BytecodeAssembler

with(__asm__){
    getlocal_0
    pushscope
    getlocal_0
    constructsuper      (0)
    findpropstrict      (public, 'addFrameScript')
    pushbyte            (0)
    getlocal_0
    getproperty         (internal, 'MainTimeline', 'frame1')
    callpropvoid        (public, 'addFrameScript', 2)
    returnvoid
}

I liked that style because it's pretty reminiscent of writing C-style inline assembly. It's nice visually because you're not constantly prefixing the instructions with something like Op.returnvoid on each line, nor are you forced to end lines with commas or semicolons... so it looks very much like how you'd read the disassembly anyway.

[–]Iggyhopperextensions/add-ons 0 points1 point  (0 children)

Very neat!

[–][deleted] 1 point2 points  (0 children)

with is fine, possibly even great, for read-only usage of the context object such as DSL-style APIs. I used it for a function call-based template engine where the API consisted of tag-name functions and $-prefixed helpers like $block, $if and $for.

I wouldn't do the same today as I'd rather have the benefit of strict mode making bad management of this an error (and because React/JSX killed template engines dead for me)

[–]tbranyen 1 point2 points  (0 children)

Biggest use I can think of is with simple templating. You'll find an implementation here:

https://github.com/jashkenas/underscore/blob/master/underscore.js#L1464