I'm with you on setenv/getenv being better. Maybe we can add those
also, and those who value correctness will use them.
In the meantime,
https://github.com/joyent/node/commit/e3074689f501eea413c29b99defac29... fixes 90% of the weirdness. Having process.env behave like an object
is indeed too damn convenient, but if we're going to do that, we
should accept that it's worth giving up a slight amount of correctness
in exchange for convenience.
On Sun, Jun 24, 2012 at 3:26 PM, Bert Belder <bertbel...@gmail.com> wrote:
> On Sunday, June 24, 2012 3:17:23 AM UTC+2, Mikeal Rogers wrote:
>> You and Bert are technically correct but what you're correct about doesn't
>> matter.
>> Should node cause an exception on accessing this prototype which many
>> people expect to be there?
>> The answer is obviously "no" only because it's much easier to make it not
>> a problem that anyone ever sees than it is to explain this to everyone who
>> gets this error.
>> If you reply with another email explaining to me how JavaScript works I'm
>> seriously going to flip out.
>> -Mikeal
> Let me elaborate on my reservations a little more:
> * Calling .hasOwnProperty() (or any other prototype method) on an object
> that's used as a hash table and where the keys are defined outside of the
> program's control is an anti pattern. People shouldn't do it. The question
> is really whether node wants to get in the way of the user when he tries to
> do it anyway. That's debatable - I could live with fixing the prototype. But
> really, if I were to redo node, I would make all of these guys -
> process.env, http headers, querystring args - prototype-less object.
> * process.env does not in any way behave like a normal object. For example
> all values are coerced to string, and setting a value to "" (empty string)
> might actually delete the key. Also, on Windows, keys are case insensitive;
> changing that is going to break much more than it fixes. There's probably
> more weirdness that I am not even aware of, which is all caused by the fact
> that the environment *is* not a JS object. The "proper" way to do it would
> probably be to remove `process.env` and expose the functions
> `process.setenv()` and `process.getenv()`, but the way it works now is too
> damn convenient to remove. People should just accept the fact that
> process.env behaves a little different sometimes, and if you really need JS
> object semantics, make a copy of it.
What this really indicates is, given a time machine, is that process.env should have been implemented as get and set functions. Object.prototype.getOwnProperty.call(obj, key) will work correctly on any JS object, and these days it'll actually work correctly on most/all DOM objects in a browser. So even setting the object as having no prototype doesn't really solve the problem. The problem is that it's not a JS object in any sense of the word, nor has an API that fulfills the contracts that JS objects are supposed to fill.
I've been following this conversation closely, but one thing that I'm still unclear about is _why_ process.env not a JS object (by new Object definition, that is).
There are some obvious guesses, but I'm mostly interested in actual documentation or historical fact, and not at all interested in opinion or more guesses - thanks!
On Wed, Jun 27, 2012 at 4:00 AM, Rick Waldron <waldron.r...@gmail.com> wrote:
> I've been following this conversation closely, but one thing that I'm still
> unclear about is _why_ process.env not a JS object (by new Object
> definition, that is).
> There are some obvious guesses, but I'm mostly interested in actual
> documentation or historical fact, and not at all interested in opinion or
> more guesses - thanks!
Because it's not. It's a front for a bunch of libc functions. It just
looks like an object, mostly.
Here is the original commit[1]. Before that, process.env was a simple
copy of the environment (granted, as a pure JS object). I didn't want
to break the interface so I hacked up the thing we have today.
On Tuesday, June 26, 2012 at 10:23 PM, Ben Noordhuis wrote:
> On Wed, Jun 27, 2012 at 4:00 AM, Rick Waldron <waldron.r...@gmail.com> wrote:
> > I've been following this conversation closely, but one thing that I'm still
> > unclear about is _why_ process.env not a JS object (by new Object
> > definition, that is).
> > There are some obvious guesses, but I'm mostly interested in actual
> > documentation or historical fact, and not at all interested in opinion or
> > more guesses - thanks!
> Because it's not. It's a front for a bunch of libc functions. It just
> looks like an object, mostly.
> Here is the original commit[1]. Before that, process.env was a simple
> copy of the environment (granted, as a pure JS object). I didn't want
> to break the interface so I hacked up the thing we have today.
Just as a distraction from work I should be doing instead, I made a module that exports the EnvGetter, EnvSetter, EnvEnumerator, and EnvDeleter as functions. It also optionally, if Proxy is available, exports an Environment constructor that creates objects that are similar to process.env but more closely follow semantics of real objects. I may expand it to support management of env of other process, but this is more complicated and for now it's just an experiment that sticks to node's existing functionality.
I like this! It's a shame that it requires --harmony. When/if Proxy
lands in our normal V8 by default, we should consider replacing
process.env with this.
<brandon.ben...@gmail.com> wrote:
> Just as a distraction from work I should be doing instead, I made a module
> that exports the EnvGetter, EnvSetter, EnvEnumerator, and EnvDeleter as
> functions. It also optionally, if Proxy is available, exports an Environment
> constructor that creates objects that are similar to process.env but more
> closely follow semantics of real objects. I may expand it to support
> management of env of other process, but this is more complicated and for now
> it's just an experiment that sticks to node's existing functionality.
Yeah this is definitely one of those places where proxies show their real value. Being able to represent a heap external interface without having to leave JS except for the very minimum amount required. With the Direct Proxies API it'll go from "doable" to "trivial" to implement virtual objects that mostly obey the rules of regular objects and don't blow up if you try to use that as a prototype or use some rarely used but normal JS API (the amount of C++ modules that explode if you do something like Object.getOwnPropertyNames(Object.getPrototypeOf(cplusplusModuleObject)) is actually quite ridiculous).
An interesting use-case I want to try out is that of representing near-synced objects between parent/child/sibling processes. process.env is a good example here as well because it's not generally time critical, but still useful... "near objecst". Something that is usually around a single event loop turn away, because it's out of process or in a js external memory storage, or not in the JS heap for whatever reason, but close enough that the limitation is simply having to post a callback to get at it.
Sometimes these things are time critical and C++ apis support that, but usually you just build/use an async API around it. These objects are close enough though that with some creative synchronization a useful proxy interface could be provided that is "close enough" to provide the best of both worlds. A child's process process.env would be an example where the gap could be bridged by a proxy that provided local in-heap access and was semi-lazily synced as needed. This captures the best of both worlds I think, offloading the need to treat an API as asynchronous without resorting to those things which shall not be named.
> (...) This captures the best of both worlds I think, offloading the need to treat an API as asynchronous without resorting to those things which shall not be named.
I don't understand this at all. I'd really appreciate a link, because all Google talks about are errors. How are Unterminated string literals "offloading the need to treat an API as asynchronous".