Closed Bug 514511 Opened 17 years ago Closed 15 years ago

Static namespaces

Categories

(Core :: JavaScript Engine, defect)

defect
Not set
normal

Tracking

()

RESOLVED WONTFIX

People

(Reporter: luke, Unassigned)

References

Details

Bug 460904 currently does a very limited form of a feature that could be generally useful for the front end, both for performance and security. Currently, in a "self hosted" compile in the js shell, one can write: s.#builtin#StringMatchAll(p) And "#builtin#" acts as the namespace for the "StringMatchAll" method. The result is that instead of inserting an operation which does lookup at runtime (and therefore costs cycles and introduces the possibility of finding the wrong name), we can insert an instruction that is "hard coded" to call the StringMatchAll builtin found at compile time. The idea is to spruce up the syntax and add an API so that js users can register their own namespaces and perform their own compile-time name resultion. Thus, a user could register the namespace "ff", and when the following JS was compiled: o.ff::foo() the user would be called back and asked "what JSFunction should I call for identifier "foo" in your namespace?".
E4X namespaces ftw! Kidding, mostly. But the C++ namespace syntax is sweet and beats #ugly# any day. The static-ness is extreme but appropriate for self-hosting and high performance XPCOM bindings. We are reinventing pieces of ActionScript 3 in doing this, and namespaces will never be standardized, but it still looks like the best course to me. /be
(In reply to comment #1) > The static-ness is extreme but appropriate for > self-hosting and high performance XPCOM bindings. We are reinventing pieces of > ActionScript 3 in doing this, and namespaces will never be standardized, but it > still looks like the best course to me. Erm, read the proposal clearly. Luke's suggesting JS code *itself* be called in order to provide namespace-resolution services, not just spruce up the syntax. Changing the syntax to be less ugly is fine, but he's also suggesting going *exactly* down the AS3 path -- actually further -- and that's a Very Bad Idea. This bug is about making namespaces *less* static. I'm strongly, seriously opposed to any system of feedback between name resolution and execution. It's a nightmare and I've only seen extremely dubious or contrived demonstrations of possible uses, never one that became more comprehensible or obvious through the use of this sort of feature. Given that the purpose of this whole "namespaced call" facility is to pre-bind JS code *in the C++ build environment*, I'd strongly prefer excluding *any* facility for defining a namespace in JS. It's superfluous, and requires much more machinery than just having a table in a C++ file exposing functions in particular namespaces. It's clearly an extra-spec, non-user-facing facility, let's make most of it happen outside the language, with only the smallest and least invasive possible contact point (the resolution syntax). If you absolutely *have* to have a system for defining or declaring namespaces in JS -- and arguing that is a serious point in itself, not something to just take for granted -- then I strongly prefer it is a parse-time lexical construct, not something that involves calling back into the interpreter. But even that is a big "if". I see no reason to produce such a system at all. (Sorry for freaking out on this, but it's like ... *the* bullet that cost ES4 its semantics; it's impossible to define any other static construct in the language at all if you go down this road.)
(In reply to comment #2) > (In reply to comment #1) > > The static-ness is extreme but appropriate for > > self-hosting and high performance XPCOM bindings. We are reinventing pieces of > > ActionScript 3 in doing this, and namespaces will never be standardized, but it > > still looks like the best course to me. > > Erm, read the proposal clearly. Luke's suggesting JS code *itself* be called in > order to provide namespace-resolution services, not just spruce up the syntax. No Sir! Sorry for any ambiguous wording above, but when I say the "user", I mean JS embedder, as in, C/C++ code. Although its good to see your spider-senses are in working order.
(In reply to comment #3) And to be eminently clear, when I say "compile time" and "static", I mean "before the JS runs". When used, this should have a *simplifying* effect on the semantics.
(In reply to comment #4) > (In reply to comment #3) > > And to be eminently clear, when I say "compile time" and "static", I mean > "before the JS runs". When used, this should have a *simplifying* effect on > the semantics. Huh. Ok. I'm still not sure this "simplifies", in the sense that you're still talking about a C++ call during JS-script-compilation instead of a lookup in a fixed-at-JS-library-build-time table; still seems like "more dynamic", as your embedder can change bindings post-JS-library-build. But that might make interfacing the XPCOM interfaces easier, I guess. So long as namespace definition and resolution is out of the hands of JS code, I'm happy.
(In reply to comment #5) > Huh. Ok. I'm still not sure this "simplifies", in the sense that you're still > talking about a C++ call during JS-script-compilation instead of a lookup in a > fixed-at-JS-library-build-time table; still seems like "more dynamic", as your > embedder can change bindings post-JS-library-build. "o.foo()" is re-resolved every time (modulo caching) it is run in a runtime littered with content js. "o.firefox::foo()" is resolved once, when it is compiled, with a fixed set of embedders (namely, Firefox) with a fixed set of namespaces with fixed contents. I don't see how that isn't simpler or static-er.
Now it's me who's been unclear. I'm saying that given: 1. o.#firefox#foo(...) resolved at JS script compilation time by looking up the string "#firefox#foo" in an associative table mapping strings to JSFunctions, with the associations fixed at C++ JS library compile time. 2. o.firefox::foo() resolved at JS script compilation time by calling a C++ function with the string "firefox::foo", that returns a JSFunction, via a association logic possibly determined at runtime, but not during JS script execution. That #2 is slightly, but not seriously, less static than #1. We have #1 now, if I read correctly you want #2. That's fine. It's not so serious a dynamic-ness for me to object. It might make binding to XPCOM easier. I was only concerned if it fed back into the interpreter, which I misunderstood to be the proposal.
That sounds good. I only quibbled in order to defend the static-ness of the approach since, ordered by static-ness and assuming #3 is what we currently have and #4 is the scary JS-resolution mechanism you described, while #1 < #2 < #3 < #4, #2 is a lot closer to #1 than #3.
Graydon: I am behind all this namespace madness, I remember the lessons of ES4 too well (I'll be talking next week at the Ajax Experience about 'em), but this was only ever about native code hooking namespaces up for self-hosting. We never want any way for JS to do likewise. This is all Mozilla-specific native magic, and it seems magic::foo beats #magic#foo or __magic_foo__, not surprising. /be
(In reply to comment #7) > I was only concerned > if it fed back into the interpreter, which I misunderstood to be the proposal. In the interest of clarifying the proposal, should we tighten up some wording to exclude runtime namespace qualification? Probably my wording about "ActionScript 3" :-(. /be
I'm a bit leery about the syntax of these extensions being the same as something an embedding could use. #foo# might be ugly, but c'mon, we're men (manly men!), we can handle a little eye-gouging for the cause of being absolutely sure our internal-use-only extensions don't leak out.
Waldo's point is good if we are optimizing only for ultimate safety against web leaks or spoofs. But the platform hackers want mozilla::, builtin::, etc. and we are in a platform competition. We have to please to serve. /be
Yeah, please no #foo#. If all goes well, we'll see mozilla:: all over firefox and toolkit code, and it's much friendlier looking to newbies (well, assuming they can wrap their heads around o.mozilla:foo() :-).
Wait. Why do we want to see o.mozilla::foo() all over the codebase? Is it that static binding is faster than dynamic binding? Or does it maybe have to do with code integrity? I'm extremely skeptical that o.mozilla::foo() is really something we want. Surely we can offer something prettier and just as effective, if we know what the design goals are. Luke gave a motivating example, and for that I would propose: import jsinternals; // compiler sees this jsinternals.stringMatchAll(s, p); // and statically binds this (Sure, we once had an import keyword that probably meant something else--but unlike E4X we ripped that out, so it's actually, ahem, available for reuse.) I really don't want people to stop writing foo.bar() and start writing foo.magicturd::bar() because they think the latter is faster.
(In reply to comment #14) > Wait. Why do we want to see o.mozilla::foo() all over the codebase? Is it that > static binding is faster than dynamic binding? Or does it maybe have to do > with code integrity? Both. > I really don't want people to stop writing foo.bar() and start writing > foo.magicturd::bar() because they think the latter is faster. (1) they can't just throw it in wherever they want; if 'bar' has not actually been a priori put into 'magicturd', they would get a compile-time error. (2) it would be faster, as in, JSOP_CALLPROP vs. JSOP_CALLBUILTIN faster; if they *can* write it, and they *should* write it. (That assumes they didn't want polymorphic behavior from 'bar', but seeing as putting 'bar' in a static namespace is like making a member function non-virtual in C++, 'bar' must have been designed not be polymorphic.)
(In reply to comment #15) > > I really don't want people to stop writing foo.bar() and start writing > > foo.magicturd::bar() because they think the latter is faster. > > (1) they can't just throw it in wherever they want; if 'bar' has not actually > been a priori put into 'magicturd', they would get a compile-time error. (2) it > would be faster, as in, JSOP_CALLPROP vs. JSOP_CALLBUILTIN faster; if they > *can* write it, and they *should* write it. I'm sure it'll be slightly faster, but I'm not convinced the win would be measurable, let alone compelling. And I dispute that developers should type extra funny symbols because then we can save a few machine instructions. Have method lookups been showing up on profiles? We have standing opportunities to make all JavaScript faster--including our existing code and the Web--without modifying the language. Static binding is a fine thing to have in a language. I just want to know precisely what Vlad's after, in case there's maybe a nicer way of providing it. I admit I don't care for ActionScript 3 namespaces or for the idea of layering new meaning on top of E4X syntax. :-P
Forget AS3 and E4X. This is about C++ mozilla::... new-style APIs and how they show up in our "system JS" dialect, which is not to be standardized or leaked onto the web (as noted earlier, leak-proofing if we cared would use #ugly# not ns:: but that bombs for human factors/aesthetics reasons). These really are much more static than anything in AS3 or E4X. I get nervous around :: too, many people dislike it. But if we are in for a pound with it in mozilla:: C++ APIs, why not in JS? The import idea is not going to give static joy and best performance, but it does remind me that modules are coming along at commonjs.org, feeding into the Harmony ES agenda. A fallback from :: is to use modules in some similar or matching way, and optimize, as jorendorff suggests, both our "systems JS" and "web JS" till we don't care about the dynamic lookup costs. /be
(In reply to comment #17) > The import idea is not going to give static joy and best performance [...] What I had in mind was pretty static: the compiler would see import foo; and request the "foo" library from the embedding. From then on, - qualified names like foo.bar.baz would be resolved at compile time - foo.mispelld_name would be a compile-time SyntaxError - using 'mozilla' in any other way would be a SyntaxError A completely different alternative is just to make the compiler constant-fold really aggressively. Suppose we're in compile-n-go mode and the compiler sees: const mylib = _import("mylib"); mylib.foo.bar(); Suppose _import has a bit that says "call me at compile-time if my arguments are constants". If the properties involved are all nonconfigurable, the compiler can statically bind mylib.foo.bar without any changes to the language. It can also warn at compile-time about misspellings. Igor wanted something like this for switch case labels. We could just make it happen everywhere. > A fallback from :: is to use modules in some similar or > matching way, and optimize, as jorendorff suggests, both our "systems JS" and > "web JS" till we don't care about the dynamic lookup costs. Just to clarify my position: I think we should continue optimizing all JS till we *do* care about the dynamic lookup costs (i.e. until they're the next bottleneck, if ever).
> - using 'mozilla' in any other way would be a SyntaxError Er, I meant 'foo' there of course.
Sorry I'm late to the party. I lean pretty strongly against any kind of namespace mechanism at least until we see how many of our uses cases are already satisfied by modules. Namespace systems tend to seem to me like not-quite-enough approximations of module systems. Modules will give us statically-known, immutable bindings, which goes a long way towards the kinds of semantic security and compiler optimization we want. Dave
A brief "state of the union" follow-up: the modules semantics is beginning to stabilize, and I believe we can start building before long. It's post-FF4, but I think Andreas is keen to start implementing once the Q4 madness relents. In the meantime, though, one of the elements of the module system I had in mind was a global, DontDelete/ReadOnly binding called |modules| that reflects the current set of globally defined modules, so that legacy code could get dynamic access to Harmony modules. Since we know that once any such binding exists, the semantics of modules mandates that it be permanent and immutable, the implementation is free to hard-wire references to it, constant-propagate, etc. Would that be a useful stopgap for some core Mozilla-specific locations of builtins until we have fuller support for modules? Dave
Assignee: lw → general
WONTFIXing in lieu of modules.
Status: ASSIGNED → RESOLVED
Closed: 15 years ago
Resolution: --- → WONTFIX
You need to log in before you can comment on or make changes to this bug.