<!-- 
RSS generated by JIRA (4.4#649-r158309) at Wed Jun 19 07:19:40 CDT 2013

It is possible to restrict the fields that are returned in this document by specifying the 'field' parameter in your request.
For example, to request only the issue key and summary add field=key&field=summary to the URL of your request.
For example:
http://dev.clojure.org/jira/si/jira.issueviews:issue-xml/CLJS-297/CLJS-297.xml?field=key&field=summary
-->
<rss version="0.92" >
<channel>
    <title>Clojure JIRA</title>
    <link>http://dev.clojure.org/jira</link>
    <description>This file is an XML representation of an issue</description>
    <language>en-us</language>    <build-info>
        <version>4.4</version>
        <build-number>649</build-number>
        <build-date>25-07-2011</build-date>
    </build-info>

<item>
            <title>[CLJS-297] Eliminate :meta, :vector, :set, and :map ops</title>
                <link>http://dev.clojure.org/jira/browse/CLJS-297</link>
                <project id="10040" key="CLJS">ClojureScript</project>
                        <description>&lt;p&gt;The attached patch eliminates the :meta, :set, :vector, and :map ops.&lt;/p&gt;

&lt;p&gt;These four operations can be defined more simply in terms of&lt;br/&gt;
calls to with-meta, set, vector, and hash-map respectively.&lt;/p&gt;

&lt;p&gt;The compiler was optimizing construction of vectors and maps. Now,&lt;br/&gt;
those optimizations are implemented as macros. Additionally, sets&lt;br/&gt;
are optimized in much the same way.&lt;/p&gt;

&lt;p&gt;3 files changed, 52 insertions&lt;img class=&quot;emoticon&quot; src=&quot;http://dev.clojure.org/jira/images/icons/emoticons/add.gif&quot; height=&quot;16&quot; width=&quot;16&quot; align=&quot;absmiddle&quot; alt=&quot;&quot; border=&quot;0&quot;/&gt;, 99 deletions&lt;img class=&quot;emoticon&quot; src=&quot;http://dev.clojure.org/jira/images/icons/emoticons/forbidden.gif&quot; height=&quot;16&quot; width=&quot;16&quot; align=&quot;absmiddle&quot; alt=&quot;&quot; border=&quot;0&quot;/&gt;&lt;/p&gt;

&lt;p&gt;Also worth mentioning: as macros instead of ops &amp;amp; emit methods, these optimizations can apply to any backend. The macros create ClojureScript forms, rather than manually generating JavaScript.&lt;/p&gt;</description>
                <environment></environment>
            <key id="15508">CLJS-297</key>
            <summary>Eliminate :meta, :vector, :set, and :map ops</summary>
                <type id="4" iconUrl="http://dev.clojure.org/jira/images/icons/improvement.gif">Enhancement</type>
                                <priority id="5" iconUrl="http://dev.clojure.org/jira/images/icons/priority_trivial.gif">Trivial</priority>
                    <status id="1" iconUrl="http://dev.clojure.org/jira/images/icons/status_open.gif">Open</status>
                    <resolution id="-1">Unresolved</resolution>
                                <assignee username="-1">Unassigned</assignee>
                                <reporter username="bbloom">Brandon Bloom</reporter>
                        <labels>
                        <label>patch</label>
                        <label>patch,</label>
                    </labels>
                <created>Sun, 3 Jun 2012 20:17:47 -0500</created>
                <updated>Fri, 31 Aug 2012 09:24:51 -0500</updated>
                                                                            <due></due>
                    <votes>0</votes>
                        <watches>2</watches>
                        <comments>
                    <comment id="28850" author="bbloom" created="Sun, 17 Jun 2012 16:40:19 -0500"  >&lt;p&gt;I&apos;d also like to extend this for Symbols and Keywords.&lt;/p&gt;

&lt;p&gt;I&apos;ve been experimenting with fleshed out Symbol and Keyword objects with interning. I&apos;ve found that I need emitters, macros, and functions. With the approach here, I could eliminate the emitters and instead have the analyzer produce invocation forms.&lt;/p&gt;</comment>
                    <comment id="28861" author="raph_amiard" created="Mon, 18 Jun 2012 13:20:24 -0500"  >&lt;p&gt;I think this is an interesting patch. It would be worth adapting it to the decoupled emitters. It raises the question of how it would be possible to share part of the emitters between backends.&lt;/p&gt;</comment>
                    <comment id="28864" author="dnolen" created="Mon, 18 Jun 2012 15:25:23 -0500"  >&lt;p&gt;I don&apos;t see many benefits falling out of this patch. How to best emit language primitives like literals and constants may vary from host to host - perhaps emitting bytecode directly will work best for some implementations. &lt;/p&gt;</comment>
                    <comment id="28870" author="bbloom" created="Mon, 18 Jun 2012 17:18:46 -0500"  >&lt;p&gt;Couldn&apos;t macros emit bytecode via a mechanism similar to the js* form?&lt;/p&gt;

&lt;p&gt;My goals with this are:&lt;/p&gt;

&lt;p&gt;1) Move some optimizations from the emit phase further down the pipeline. For example, consider choosing the best associative data structure to create. Why should {:foo &quot;bar&quot;} be optimized to an ObjMap or ArrayMap but (hash-map :foo &quot;bar&quot;) not be? Why should that optimization be implemented in such a way that it can not be reused by alternative backends?&lt;/p&gt;

&lt;p&gt;2) Operate at a higher level. Prefer working with Clojure forms over target-language code fragments (either strings or byte codes). This is where the code length savings is coming from.&lt;/p&gt;

&lt;p&gt;If we continue with this approach, I see 4 or 5 more places where analyzer &amp;amp; emitter code can be replaced with shorter, simpler macros, which are more readily reused by alternate backends.&lt;/p&gt;

&lt;p&gt;The one implication (downside?) this approach has on consumers of the analyzer or API is that they may need to do a little extra work when considering :invoke operations for static analysis and the like. However, that seems likely for most analyzers anyway, so this would be a matter of (defmethod handle-special-form :map) vs (defmethod handle-invoke :hash-map)&lt;/p&gt;</comment>
                    <comment id="28871" author="michalmarczyk" created="Mon, 18 Jun 2012 17:53:32 -0500"  >&lt;p&gt;Re: 1, I don&apos;t think we should be &quot;optimizing&quot; &lt;tt&gt;hash-map&lt;/tt&gt; or &lt;tt&gt;array-map&lt;/tt&gt; (or similar) calls. These functions are a documented way of requesting a map of a particular type (see the docstrings) which I think should not be removed. If anything, we might want to introduce an &lt;tt&gt;obj-map&lt;/tt&gt; function to create arbitrarily large ObjMaps on request (in fact I&apos;ll look into that, but that is a separate discussion).&lt;/p&gt;

&lt;p&gt;Additionally, the fact that {} is optimized to be a ObjMap in CLJS goes to show that any map-emitting macro will need to be rewritten for each target platform (ObjMap only makes sense when targeting JS, so this optimization simply won&apos;t be applicable to other backends). If so and assuming &lt;tt&gt;hash-map&lt;/tt&gt; &amp;amp; Co. retain the behaviour advertised in their docstrings, there&apos;s not much gain to implementing this in a macro over just writings a bunch of emitters.&lt;/p&gt;

&lt;p&gt;As for decoupling emitters &amp;#8211; I think it&apos;s perfectly fine for them not to be decoupled, they are the layer closest to the platform after all. Certainly if there&apos;s some code which turns out to look the same across multiple platforms it might be worth it to move it upwards in the stack (not necessarily, though &amp;#8211; moving it sideways, to a utility namespace / library, might turn out to be more appropriate), but I have a feeling this is an issue best decided once there actually are multiple backends in place and the various costs and benefits can be judged properly.&lt;/p&gt;

&lt;p&gt;Now, the story might well be different if we were to introduce some generic factory functions &amp;#8211; &quot;create a map of some type&quot;, &quot;create a set of some type&quot; etc. &amp;#8211; if (and only if!) they would be meant for public consumption. Then implementing a bunch of compiler macros around those new factories and letting them handle data structure literals would save some duplicate work. I don&apos;t want to pronounce an opinion on the usefulness of such generic factory functions at this time &amp;#8211; just pointing out the possibility.&lt;/p&gt;</comment>
                    <comment id="28893" author="bbloom" created="Sat, 23 Jun 2012 17:14:31 -0500"  >&lt;p&gt;&amp;gt; These functions are a documented way of requesting a map of a particular type&lt;/p&gt;

&lt;p&gt;D&apos;oh! You&apos;re right.&lt;/p&gt;

&lt;p&gt;&amp;gt; we might want to introduce an obj-map&lt;/p&gt;

&lt;p&gt;I see you did just that with &lt;a href=&quot;http://dev.clojure.org/jira/browse/CLJS-322&quot; title=&quot;Introduce an obj-map function as an analogue of array-map&quot;&gt;&lt;del&gt;CLJS-322&lt;/del&gt;&lt;/a&gt; &amp;#8211; nice.&lt;/p&gt;

&lt;p&gt;&amp;gt; the story might well be different if we were to introduce some generic factory functions&lt;/p&gt;

&lt;p&gt;There are already &lt;b&gt;some&lt;/b&gt; generic factory functions. &apos;set, for example, is documented as &quot;Returns a set of the distinct elements of coll.&quot; despite always returning a PersistentHashSet. Similar for vector and some others. It seems like map is the only core data structure that realistically has several reasonable choices for a default representation.&lt;/p&gt;

&lt;p&gt;&amp;gt; implementing a bunch of compiler macros around those new factories and letting them handle data structure literals would save some duplicate work&lt;/p&gt;

&lt;p&gt;So all this was somewhat inspired by tagged_literals.clj &amp;#8211; You&apos;ll see that those functions are effectively macros which take a form and, generally, return an invocation form.&lt;/p&gt;

&lt;p&gt;In my mind, I see Clojure&apos;s sugar syntax as a strict expansion transformation.&lt;/p&gt;

&lt;p&gt;For example, ^:m {:x &lt;span class=&quot;error&quot;&gt;&amp;#91;@y &amp;#39;z/w true&amp;#93;&lt;/span&gt;} is simply a shortcut for:&lt;/p&gt;

&lt;p&gt;(with-meta (make-map (keyword &quot;x&quot;) (vector (deref y) (symbol &quot;z&quot; &quot;w&quot;) Boolean/TRUE)) (make-map (keyword &quot;m&quot;) Boolean/TRUE))&lt;/p&gt;

&lt;p&gt;This sort of thing already happens for @ derefs, # lambdas, etc.&lt;/p&gt;

&lt;p&gt;In theory, this could be implemented at a level lower than the compiler. You could, for instance, define a reader &quot;desugar&quot; mode which only returns lists and primitives instead of vectors, maps, etc. This would greatly reduce the number of special forms in the compiler, since all of these boil down to invocations with macros.&lt;/p&gt;

&lt;p&gt;Emit methods could be replaced with macros for at least these things: vars, maps, vectors, sets, nil, bools, regexes, keywords, symbols, metadata, and empty lists.&lt;/p&gt;

&lt;p&gt;The result would be a significant reduction in the amount of code in the compiler for a proportionally smaller increase in the amount of code in per-language macros and maybe the reader.&lt;/p&gt;

&lt;p&gt;&amp;gt; I have a feeling this is an issue best decided once there actually are multiple backends in place&lt;/p&gt;

&lt;p&gt;I&apos;ll grant you that.&lt;/p&gt;

&lt;p&gt;I&apos;ve said my piece on the topic and don&apos;t feel very strongly about this particular patch. I just wanted to spark the discussion about reusing more bits of the compiler between backends. In my mind, it&apos;s almost always preferable to transform lists than it is to emit strings. I tried that, and the result was a reduction in responsibilities for the analyzer and macros that were easier to work with than emit methods.&lt;/p&gt;</comment>
                    <comment id="28894" author="michalmarczyk" created="Sun, 24 Jun 2012 19:41:51 -0500"  >&lt;p&gt;Some further discussion here:&lt;/p&gt;

&lt;p&gt;&lt;tt&gt;&lt;a href=&quot;http://clojure-log.n01se.net/date/2012-06-24.html#20:30a&quot;&gt;http://clojure-log.n01se.net/date/2012-06-24.html#20:30a&lt;/a&gt;&lt;/tt&gt;&lt;/p&gt;</comment>
                    <comment id="29199" author="bbloom" created="Thu, 16 Aug 2012 21:34:30 -0500"  >&lt;p&gt;One other advantage of function application over special casing maps/sets/etc is that argument evaluation order is well defined for function application (left-to-right). The Clojure reader returns un-ordered maps &amp;amp; sets, so without changing the reader, we have no way of being able to know what order map key-value-pairs or set elements were originally in. I filed a bug on that. I think we need to make the reader extensible to say to create the return values from their children expressions. In the case of the ClojureScript compiler, we do care about order, so we&apos;d want to return either a (make-map ...) form directly, or a sorted-map by read-order. Same goes for sets.&lt;/p&gt;</comment>
                    <comment id="29321" author="dnolen" created="Fri, 31 Aug 2012 09:24:51 -0500"  >&lt;p&gt;There&apos;s not enough rationale for this one.&lt;/p&gt;</comment>
                </comments>
                    <attachments>
                    <attachment id="11289" name="emit-ds-via-macros.patch" size="10052" author="bbloom" created="Sun, 3 Jun 2012 20:17:47 -0500" />
                </attachments>
            <subtasks>
        </subtasks>
                <customfields>
                                                                                            <customfield id="customfield_10010" key="com.pyxis.greenhopper.jira:gh-global-rank">
                <customfieldname>Global Rank</customfieldname>
                <customfieldvalues>
                    
                </customfieldvalues>
            </customfield>
                                            <customfield id="customfield_10000" key="com.atlassian.jira.plugin.system.customfieldtypes:select">
                <customfieldname>Patch</customfieldname>
                <customfieldvalues>
                        <customfieldvalue key="10001">Code</customfieldvalue>

                </customfieldvalues>
            </customfield>
                                                                                        </customfields>
    </item>
</channel>
</rss>