Fork me on GitHub
isolate.js via AST analysis
interactivate
Recent changes in SDK
nodeconf 2012
Write logic, not mechanics
protocol based polymorphism
(clojurescripting :intro)
namespaces

I have previously blogged about inability of haveing properties with limited, controlled accessibility & described a hack I prototyped to overcome this limitation. Unfortunately I have failed to explain why one would need such properties, so I plan to explain it in this post. In addition, we already have a WeakMaps in spidermonkey (and also in V8) that made it possible to implement sharable privates in a proper way, you’ll find more details about how we did it in Add-on SDK also in this post.

Why do we need privates

Sometimes program is written to work with third party, potentially malicious, code which may use variety of in order to escalate privileges and do something harmful. This is exact scenario we have in add-on SDK, where we wrap sudo powered browser internals into higher level APIs with reduced capabilities, such that by looking at add-on’s module graph we’re able to say what it’s capable of doing. For example if add-on only requires notifications module we know that at most it can spam user with notifications. Now if we’ve just stored sudo powered components used to implement these API under pseudo private (_ prefixed) properties we would’ve had no way of saying what it’s capable of. There would be no guarantee that add-on code won’t use those pseudo privates to wipe users hard drive (accidentally or intentionally).

This is not the only scenario where one would need to have controlled access to the implementation details. Any JS library may be used in an environment where it’s exposed to code that wishes to override it’s behavior by monkey-patching it’s pseudo privates, which is absolutely fine as long as, there is no other code that tries to do the same in a conflicting way. It’s not to say that we should be paranoid about it, it’s just there may be things that are not meant to be exposed in order to guarantee desired behavior.

Controlled access via namespaces

In Add-on SDK we have a namespace module, that may be used to create a namespace functions. These functions are used to access any objects namespaced sub-objects where properties, that are not part of public interface, may be saved:

let { ns } = require('namespace')
let foo = ns()

foo(myObject).secret = secret

Now only parties that have access to both foo and myObject are capable of seeing a secret. This approach allows us to create groups of internal properties that may be shared with other components of the program by giving access to the namespace functions. Also note that not only we can use foo namespace with multiple objects, but we also can use multiple namespaces with the same object:

let bar = ns()

bar(myObject).baz = secret.baz

This way we can create namespace per role that objects play in the program and associate properties to that objects in groups based on the roles. As a side effect we also eliminated naming conflicts with in the role object plays as properties are defined in different namespaces. This is very powerful, as we can define event emitter and many other APIs that may work with a same object safely no matter what’s their prototypes or own properties look like and no matter how many roles they play at the same time in program.

Under the hood

Implementation under the hood is very trivial. In nutshell namespace functions are sugared wrappers around WeakMap instances, each holding a reference to a WeakMap instance, which are used to map objects to an associated “namespaced sub-objects”, where namespaced properties are stored. Also, since objects are used as keys associated “namespaced sub-objects” can be claimed by garbage collector as soon as objects are collected. As an early adopters we had to face a platform bug requiring an ugly workaround, but now it’s fixed and it’s just matter of time when it ships!

Future

While this is a good enough solution that we plan to migrate all the existing SDK code to, it still has limitations. For example properties are instance specific, or in other words namespaced properties of ancestors (objects in the prototype chain) are not inherited and have to be explicitly accessed, which may feel bit awkward:

let decedent = Object.create(myObject);
'secret' in foo(decedent) // => false

In a future we may have even better solution via private names, implementation for spidermonkey is in progress so we’re looking forward!

JS Guards
Packageless modules
Addons in multi process future
Yet another take on inheritance
Shareable private properties
Evolving VS Adjusting
oh my zsh
Git status in bash prompt
CommonJS based Github library
Taskhub
Gist plugin for Bespin
Reboot
narwzilla
JSDocs
bespin - JavaScript Server
bespin chromend
Bespin to Helma
bespin multibackend mockup
Adjectives | Ubiquity + Bugzilla love
Some Mock-up around Ubiquity
Mozshell
Ubiquity command Say
ubiquity command dictionary
Picasa Photo Viewer (Linux port) - Updated
Ubiquity command for JIRA & Crucible
Picasa Photo Viewer (Linux port)
VirtualBox
KeyZilla 0.1
XUL Development