-
Notifications
You must be signed in to change notification settings - Fork 7.3k
Cannot extend global prototypes in the REPL #771
Comments
Extending globals won't work when NODE_MODULE_CONTEXTS is turned on, What you're describing is an intentional feature. On Thu, Mar 10, 2011 at 16:31, TooTallNate
|
Ok sure, then just to clarify, NODE_MODULE_CONTEXTS is turned on by default in the REPL, but turned off by default when executing a node script? Because that's the behavior I'm experiencing... In any case, I'll just export a modified version of the |
Yeah. That's how .clear is implemented. On Thu, Mar 10, 2011 at 21:43, TooTallNate
|
I also ran into this and would like to re-request it. I can understand the reasoning (thanks for providing it!), but it would be nice to have consistent behavior between the shell and files. Just a basic tenant of good software I guess -- it shouldn't surprise you or behave in unexpected ways. Perhaps that means that modules in Node just should also be in their own context, without the ability to mess with globals. That would eliminate some valuable use cases though, like TJ's should.js. So here's a strawman:
Thanks for your consideration! |
What if you create a test.js that loads the REPL. Doesn't work for testing? |
In my opinion, we should just make NODE_MODULE_CONTEXTS the default. Relying on shared access to the same global context is an antipattern that browsers foisted on us. We have better tools now. |
|
That would cause other unintended effects, consider:
This evaluates true with NODE_MODULE_CONTEXTS=0, and false with NODE_MODULE_CONTEXTS=1... Of course you can't be talking the same object if each of them have different methods. Exactly the effects that such isolation would have isn't quite intuitive: |
When creating several contexts, V8 rebuilds the default objects (Object, Array, Date, Math, etc.). Even if what you describe is unintuitive, this is what contexts mean. |
@isaacs "In my opinion, we should just make NODE_MODULE_CONTEXTS the default." This will never get through. Performance. I mean, not performance, every module is loaded once and then cache-served, but startup time. @isaacs "Relying on shared access to the same global context is an antipattern that browsers foisted on us. We have better tools now." I'd disagree. (and, what did you exactly mean by "better tools"?) I would say what you blame the browsers is not their fault, this is written entirely in the foundations of JS as a langauge - it is mix of functional {heavy use of closures) and OO. This means, you should be able to use polymorphism to its full extent inside the code you pass around in closures - and this is the true point where you need to be able to augment Object, Number, Array and String. It's true that some things can be done in pure "functional" way by calling the function on an object, but there are lots of things that OO and its polymorphism is the right tool to use (and this may be really personal or philosophical, but I was taught that polymorphism should be used heavily, since it is clear way to solve "do this differently based on object type", which is far too common (lots of switch statements could be rewritten with good results for the readablity and maintainability to use polymorphism instead; not all, of course)). |
To sum my subsequent lines of throught on this matter:
|
Have you guys ever considered support for optional params/args to pass when require()-ing modules? This would let you change the default but have clients explicitly pass in the global context (or objects/prototypes within it) if they want the module to change it.
This would be an awesome feature IMHO! A safe default with explicit and elegant opt-in. And it would solve this issue as well. What are your thoughts? |
Btw, I just realized something weird: if modules run in a different context when require()-ed from the shell, how is my module able to monkey-patch console.dir?
Is there something special about the console object? |
@aseemk The require() API is a pseudo-standard implemented by more than just Node.js with the goal of being able to share modules between platforms, so it's is not recommended that platforms extend it. Furthermore, this specific extension doesn't make much sense because require() is expected to execute only once and always return the same object. Given those semantics, what would this mean:
I think a better solution for this specific case is you export a function that will modify the object and you explicitly ask it to, e.x.
|
@tlrobinson Great point! Thanks for the reminder. I had been thinking of the same idea, but generalized, e.g.
Thanks! |
This whole thing seems like such a non-issue. Repls are very rarely perfect 1:1 replicas of the system they represent. (Have you ever really looked hard at the Webkit console or Firebug environments? They're insane.) Even bash is significantly different in interactive mode than it is from inside a script. Having |
Fair points! It's indeed a minor issue, so no big deal. Thanks for your consideration. =) |
Taken literally, it is a non-issue. |
I ran into this issue, as well. Weird. If I run 'node foo.js', it prints true. If I run 'node', the the contents of foo.js verbatim, I get false (even if I manually do NODE_MODULE_CONTEXTS=0). Come on... NODE_MODULE_CONTEXTS=0 should work, right? ...foo.js ...bar.js |
I think maybe 5 "wtf" bugs is enough. Reopening this, so that it can be yet another issue closed by the commit that fixes #1484. |
Fix nodejs#1484 Fix nodejs#1834 Fix nodejs#1482 Fix nodejs#771 It's been a while now, and we've seen how this separate context thing works. It constantly confuses people, and no one actually uses '.clear' anyway, so the benefit of that feature does not justify the constant WTFery. This makes repl.context actually be a getter that returns the global object, and prints a deprecation warning. The '.clear' command is gone, and will report that it's an invalid repl keyword. Tests updated to allow the require, module, and exports globals, which are still available in the repl just like they were before, by making them global.
Thanks, @isaacs. Yeah, using a separate context for the REPL is an interesting idea, but when people are testing their modules using the REPL, it adds an extra layer of confusion. Anyway, thanks for taking the time to put a pull request together. |
If I understand this correctly the REPL no longer uses a different context? My monkey patch methods are still not recognized in the REPL? is that intentional? |
@still-dreaming-1 Hi! This is a pretty old issue, basically all new discussion happens over at https://github.com/nodejs/node. That being said, nodejs/node#5703 which was released in Node v6.3.0 changed it to using a different context, but that unfortunately had some unintended side effects (x x x x) so it ended up getting reverted in v6.3.1.
You’ll probably have to be more specific – the fact the REPL does use the same context should allow you to monkey-patch JS globals, not the other way around. |
See this gist: https://gist.github.com/865250
When running a regular node script via
node script.js
, other modules can extend the global prototype's of the built-in JavaScript classes (Object
,String
, etc.). But when trying to load a module from the REPL that does the same, the global prototypes remain untouched.This isn't a huge deal as the REPL is only used for testing, and the expected functionality works when running a script normally. But it would be nice to be able to test the extensions through the REPL as well...
The text was updated successfully, but these errors were encountered: