{"id":228,"date":"2011-04-25T15:12:40","date_gmt":"2011-04-25T23:12:40","guid":{"rendered":"http:\/\/www.wirfs-brock.com\/allen\/?p=228"},"modified":"2011-04-29T09:59:41","modified_gmt":"2011-04-29T17:59:41","slug":"experimenting-with-mirrors-for-javascript","status":"publish","type":"post","link":"https:\/\/wirfs-brock.com\/allen\/posts\/228","title":{"rendered":"Experimenting with Mirrors for JavaScript"},"content":{"rendered":"<p>A common capability of many dynamic languages, such as JavaScript, is the ability of a program to inspect and modify its own structure.\u00a0 This capability is generally called <em>reflection<\/em>.  Examples of reflective capabilities of JavaScript include things like the <code>hasOwnProperty<\/code> and <code>isPrototypeOf<\/code> methods. ECMAScript 5 extended the reflection capability to JavaScript via functions such as <code>Object.defineProperty<\/code> and <code>Object.getOwnPropertyDescriptor<\/code>. There are many reasons you might use reflection but two very common uses are for creating development\/debugging tool and for meta-programming.<br \/>\n<a href=\"http:\/\/www.wirfs-brock.com\/allen\/wp-content\/uploads\/2011\/04\/mirrors.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignright size-medium wp-image-234\" title=\"mirrors\" src=\"http:\/\/www.wirfs-brock.com\/allen\/wp-content\/uploads\/2011\/04\/mirrors-225x300.jpg\" alt=\"\" width=\"225\" height=\"300\" srcset=\"https:\/\/wirfs-brock.com\/allen\/wp-content\/uploads\/2011\/04\/mirrors-225x300.jpg 225w, https:\/\/wirfs-brock.com\/allen\/wp-content\/uploads\/2011\/04\/mirrors.jpg 768w\" sizes=\"(max-width: 225px) 100vw, 225px\" \/><\/a><br \/>\nThere are many different ways you might define a reflection API for a programming language. For example, in JavaScript <code>hasOwnProperty<\/code> is a method defined by <code>Object.prototype<\/code> so it is, in theory,  available to be called as a method on all objects. But there is a problem with this approach.  What happens if an application object defines its own method named <code>hasOwnPro<\/code><code>perty<\/code>?  The application object definition will override the definition of <code>hasOwnProperty<\/code> that is normally inherited from <code>Object.prototype<\/code>.  Unexpected results are likely to occur if such an object is passed to code that expects to do reflection using the built-in <code>hasOwnProperty<\/code> method.  This is one of the reasons that the new reflection capabilities in ES5 are defined as functions on <code>Object<\/code> rather than as methods of <code>Object.prototype<\/code>.<\/p>\n<p>Another issue that arises with many reflection APIs is that they  typically only work with local objects.  Consider a tool that gives application developers the ability to graphically browse and inspect the objects in an application. If such a tool is effective, developers might want to use it in other situations.  For example, they  might want to inspect the objects on a remote server-based JavaScript application or to inspect a diagnostic JSON dump of objects produced when an application crashed. If JavaScript&#8217;s existing reflection APIs were used to create the tool there is no direct way it can be used to inspect such objects because the JavaScript reflection APIs only operate upon local objects within the current program.<\/p>\n<p>There is also a tension between the power of reflection and security concerns within applications.  Many of the reflection capabilities that are most useful to tool builders and meta-programmers can also be exploited for malicious purposes.  Reflection API designers sometimes exclude potentially useful features in order to eliminate the potential of such exploits.<\/p>\n<p><em>Mirrors<\/em> is the name of  an approach to reflection API design that attempts to address many of the issue that have been encountered with various programming languages that support reflection. The basic idea of mirrors is that you never perform reflective operations directly upon application objects.  Instead all such operations are performed upon distinct &#8220;mirror&#8221; objects that &#8220;reflect&#8221; the structure of corresponding application objects.  For example, instead of coding something like:<\/p>\n<p style=\"padding-left: 30px;\"><code>if (someObj.hasOwnProperty('customer')) {...<\/code><\/p>\n<p>you might accomplish the same thing via mirrors via something like:<\/p>\n<p style=\"padding-left: 30px;\"><code>if (Mirror.on(someObj).hasOwnProperty('customer')) {...<\/code><\/p>\n<p>Mirrors don&#8217;t have the sort of issues I discussed above because when using them you never directly reflect on application objects. There is never any problem\u00a0 if the application just happens to define a method that\u00a0 has the same name as a reflection API method.\u00a0 Because reflection-based tools only indirectly interact with the underlying objects via mirror objects, it is possible to create different mirrors that use a common interface to access either local object, remote objects, or static objects stored in a file. Similar, it is possible to have have mirrors that present a common interface but differ in terms how much reflection they allow.\u00a0 A trusted tool might be given access to a mirror that supports the must power reflective operations while an untrusted plug-in might be restricted to using mirrors that support only a limited set of reflective operations.<\/p>\n<p>Gilad Bracha and David Ungar are the authors of a paper that explain the principals behind mirror-based reflection: <a href=\"http:\/\/bracha.org\/mirrors.pdf\">Mirrors: Design Principles for Meta-level Facilities of Object-Oriented Programming Languages<\/a>.  I highly recommend it if you are interested in the general topic of reflection.<\/p>\n<p>Mirrors were originally developed for the <a title=\"selflanguage.org\" href=\"http:\/\/selflanguage.org\/\" target=\"_blank\">self<\/a> programming language, one of the languages that influenced the original design of JavaScript. Recently, I&#8217;ve been experimenting with defining a mirror based reflection interface for JavaScript.\u00a0 An early prototype of this interface named <a href=\"https:\/\/github.com\/allenwb\/jsmirrors\">jsmirrors<\/a> is now up on github.\u00a0 It uses a common interface to support reflection on both local JavaScript objects and on a JSON-based object encoding that could be used for remote or externally stored objects. It also supports three levels of reflection privilege.<\/p>\n<p>In my <a title=\"Looking into Mirrors\" href=\"http:\/\/www.wirfs-brock.com\/allen\/posts\/245\">next post<\/a> I&#8217;ll explain more of the usage and design details of jsmirrors.\u00a0 In the meantime, please feel free to take a look at the prototype.<\/p>\n<p><span class=\"fontsizexsmall\">(<a href=\"http:\/\/www.flickr.com\/photos\/dichohecho\/4259487517\/\" target=\"_blank\">Photo<\/a> by &#8220;dichohecho&#8221;, Creative Commons Attribution License)<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A common capability of many dynamic languages, such as JavaScript, is the ability of a program to inspect and modify its own structure.\u00a0 This capability is generally called reflection. Examples of reflective capabilities of JavaScript include things like the hasOwnProperty and isPrototypeOf methods. ECMAScript 5 extended the reflection capability to JavaScript via functions such as [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,45],"tags":[32,15,43,60,13,41,42,40,44],"_links":{"self":[{"href":"https:\/\/wirfs-brock.com\/allen\/wp-json\/wp\/v2\/posts\/228"}],"collection":[{"href":"https:\/\/wirfs-brock.com\/allen\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wirfs-brock.com\/allen\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wirfs-brock.com\/allen\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wirfs-brock.com\/allen\/wp-json\/wp\/v2\/comments?post=228"}],"version-history":[{"count":18,"href":"https:\/\/wirfs-brock.com\/allen\/wp-json\/wp\/v2\/posts\/228\/revisions"}],"predecessor-version":[{"id":310,"href":"https:\/\/wirfs-brock.com\/allen\/wp-json\/wp\/v2\/posts\/228\/revisions\/310"}],"wp:attachment":[{"href":"https:\/\/wirfs-brock.com\/allen\/wp-json\/wp\/v2\/media?parent=228"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wirfs-brock.com\/allen\/wp-json\/wp\/v2\/categories?post=228"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wirfs-brock.com\/allen\/wp-json\/wp\/v2\/tags?post=228"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}