tag:blogger.com,1999:blog-42621473914884259502024-03-03T18:25:49.230-06:00ClojureCLRNews about ClojureCLR, a port of the Clojure programming languageDavid Millerhttp://www.blogger.com/profile/07657040519395296684noreply@blogger.comBlogger20125tag:blogger.com,1999:blog-4262147391488425950.post-50567015305187692882014-10-12T00:17:00.000-05:002014-10-12T00:17:11.239-05:00Reflecting propertiesA recently posted issue (<a href="http://dev.clojure.org/jira/browse/CLJCLR-45">CLJCLR-45</a>) raises the question of the behavior of ClojureCLR with respect to properties in interfaces The example is:<br />
<br />
<pre class="brush: clojure">(def o
(reify IAsyncResult
(get_AsyncState [_] (println "Hello") 7)))
(.AsyncState o)
</pre>
<br />
The question is why the <span style="font-family: Courier New, Courier, monospace;">.AsyncState</span> interop call generates a missing method exception. There is also an assertion that calling <span style="font-family: Courier New, Courier, monospace;">AsyncState</span> on <span style="font-family: Courier New, Courier, monospace;">o</span> from C# code (by pulling in the AOT-compiled code) works okay.<br />
<div>
<br /></div>
<div>
Well, yes and no. Equivalent operations in C# and ClojureCLR yield the same results; in fact, they yield essentially identical IL code.</div>
<div>
<br /></div>
<div>
Let's start with C#. The recommended method for accessing a <span style="font-family: Courier New, Courier, monospace;">Var</span> is via the methods in the <span style="font-family: Courier New, Courier, monospace;">clojure.clr.api.Clojure</span> class. (See <a href="https://github.com/clojure/clojure-clr/wiki/Using-ClojureCLR-in-a-C%23-project">Using ClojureCLR in a C# project</a>.) Assume the code above is the <span style="font-family: Courier New, Courier, monospace;">clojure.junk</span> namespace. You would write:</div>
<br />
<pre class="brush: clojure">// load clojure.junk
IFn require = Clojure.var("clojure.core", "require");
require.invoke(Clojure.read("clojure.junk"));
// access o
IFn deref = Clojure.var("clojure.core", "deref");
dynamic o = deref.invoke(Clojure.var("clojure.junk", "o"));
</pre>
<br />
The method <span style="font-family: Courier New, Courier, monospace;">Clojure.var</span> returns an <span style="font-family: Courier New, Courier, monospace;">IFn</span>. To access a non-function value, the recommended method is to deref the value, as shown.
<br />
<div>
<br /></div>
<div>
Note that I have declared the C# variable <span style="font-family: Courier New, Courier, monospace;">o</span> as <span style="font-family: Courier New, Courier, monospace;">dynamic</span>. If I had declared it as <span style="font-family: Courier New, Courier, monospace;">Object</span>, the only way to call <span style="font-family: Courier New, Courier, monospace;">AsyncState </span>or <span style="font-family: Courier New, Courier, monospace;">get_AsyncState </span>on <span style="font-family: Courier New, Courier, monospace;">o </span>would be to cast it to an <span style="font-family: Courier New, Courier, monospace;">IAsyncResult</span>--this is the magic sauce that makes the calls work in C# -- and in ClojureCLR. Declaring <span style="font-family: Courier New, Courier, monospace;">o</span> as <span style="font-family: Courier New, Courier, monospace;">dynamic </span>allows us call those methods directly -- which is what makes our life interesting.</div>
<div>
<br /></div>
<div>
Consider the following ways of making the calls in C#:</div>
<div>
<br /></div>
<pre class="brush: csharp">((IAsyncResult)o).get_AsyncState(); // 1
((IAsyncResult)o).AsyncState; // 2
o.get_AsyncState(); // 3
o.AsyncState // 4
</pre>
<br />
The calls in lines 1 and 2 work, as you would expect. What you might not know is that the compiler generates identical IL code for the calls: the call in line 2 becomes a call to the <span style="font-family: Courier New, Courier, monospace;">get_AsyncState </span>method. The call in line 3 works. It turns into a dynamic callsite (<span style="font-family: Courier New, Courier, monospace;">System.Runtime.CompilerServices.CallSite</span><t>) with an <span style="font-family: Courier New, Courier, monospace;">InvokeMember </span>binder looking for <span style="font-family: Courier New, Courier, monospace;">get_AsyncState</span>. The call in line 4, however, fails with a missing member exception. That call also turns into a dynamic callsite with a <span style="font-family: Courier New, Courier, monospace;">GetMember </span>binder looking for <span style="font-family: Courier New, Courier, monospace;">AsyncState</span>. This binder does not work for properties.
</t><br />
<div>
<br /></div>
What is the equivalent code in ClojureCLR? Assuming x is a local variable, look at:<br />
<div>
<br />
<pre class="brush: clojure">(.get_AsyncState ^IAsyncResult x) ; 1
(.AsyncState ^IAsyncResult x) ; 2
(.get_AsyncState x) ; 3
(.AsyncState x) ; 4
</pre>
<br />
The type hints in lines 1 and 2 allow the calls to be resolved at compile-time, thus avoiding reflection. The generated IL is identical to that produced by the C# compiler. The calls in lines 3 and 4 will generate reflection warnings. In ClojureCLR, this type of reflection results in the generation of dynamic callsites, as with <span style="font-family: Courier New, Courier, monospace;">dynamic </span>in C#. The binders used are ones developed for ClojureCLR, but the results are identical: the call in line 3 succeeds, and the call in line 4 fails with a missing method exception.
<br />
<br />
Moral: Use properties only with type hinting. Otherwise, use the <span style="font-family: Courier New, Courier, monospace;">get_XXX </span>and <span style="font-family: Courier New, Courier, monospace;">set_XXX </span>methods.<br />
<br /></div>
David Millerhttp://www.blogger.com/profile/07657040519395296684noreply@blogger.com2tag:blogger.com,1999:blog-4262147391488425950.post-33492912962425049732012-06-23T18:15:00.003-05:002012-06-23T18:15:54.797-05:00ClojureCLR 1.4 released with code gen redoneI just pushed version 1.4.0 of ClojureCLR.<br />
<br />
This version matches all fixes and enhancements in the same version of Clojure/JVM/TheMotherShip. It also sports, at long last, the new non-DLR-based code generation phase for the compiler. My earlier post titled "<a href="http://clojureclr.blogspot.com/2012/03/code-gen-redo-preview.html">Code gen redo preview</a>". The benefits outlined in that post--smaller assemblies, faster startup, some speedup--are now available in this release.<br />
<br />
In the preview post, I mentioned attempting to re-implement 'light compilation' in the new compiler. The previous (DLR-based) version of the compiler has a special compilation mode used during evaluation (but not during AOT-compilation) for any function that does not need to have its own class defined. It used DynamicMethods, a lighter weight version of IL generation that can be significantly faster than methods generated to assemblies.<br />
<br />
The way the DLR generated DynamicMethods allowed live constants to be embedded in a way that full compilation did not; as a result, there were some constructs that would load evaluated but would not AOT-compile. It never happened to me, but I know of one person who got bit by that (and who asked me to leave light compilation out of this version). That person need not worry -- I have not yet finished coding light compilation and it is not active in this release.<br />
<br />
Does it matter? Most likely not. You could see some speedup loading very large files, such as clojure/core.clj. However, I'm pretty sure light compilation was massively speeding up running the Clojure test suite. For some reason, with the current version, if you start up ClojureCLR under the debugger and run the full test suite, msvsmon.exe, the Visual Studio Remote Debugging Monitor, goes absolutely nuts allocating memory. It appears to max at about 6GB on my PC with 8GB. One sees some serious thrashing at that point. I have no idea why. I have no problem compiling the entire clj source bootstrap code, which starts off evaluating core.clj and friends first and then going back to compile it, with not a hiccup from msvsmon.<br />
<br />
So, at present, I run the test suite from the command line. If I need to debug on the tests, I just load the test file in question and run the tests for it only.<br />
<br />
If you see this kind of memory-hogging behavior in mvsmon.exe, let me know. <br />
<br />
The near-term roadmap for ClojureCLR development, in no particular order, is:<br />
<br />
<ol>
<li>Catch up with Clojure 1.5.x-alpha changes, particularly the new work on reducers.</li>
<li>Examine the perf of the test suite and see what's going on there.</li>
<li>Work on a single assembly distribution of ClojureCLR (using nested assembly loading), following the trail blazed by aaronc and Ralph Moritz.</li>
<li>Work on running ClojureCLR on Mono. (Some <i>very</i> positive reports from Robert Johnson on his experiments).</li>
<li>(Maybe) finish implementing light compile, for my own sense of fulfillment if nothing else.</li>
</ol>
<div>
The work on reducers on the JVM side has introduced version-specific implementation (using Fork/Join in JVM 7 or falling back to other means on earlier versions). I suspect a similar 3.5/4.0 .Net distinction could be made to take advantage of the Task Parallel Library (or whatever it is called these days). If you've played with TPL under ClojureCLR, I'd love to hear about it.</div>
<div>
<br /></div>
<div>
Cheers.</div>
<div>
<br /></div>
<br />
<br />
<br />
<br />
<br />David Millerhttp://www.blogger.com/profile/07657040519395296684noreply@blogger.com7tag:blogger.com,1999:blog-4262147391488425950.post-51243845138618013792012-03-26T11:44:00.003-05:002012-03-26T11:44:53.445-05:00Code gen redo previewRewriting the code generation phase of a compiler is not for the faint of heart. Nor, perhaps, for the sound of mind.<br />
<br />
I've nearly completed a rewrite of the code gen code of the ClojureCLR compiler. There are still a few things on my punch list (see below), but all the clojure.test-clojure.* tests run now. I hope an intrepid few will give it a spin before I push the changes to master. The new code can be found in the <span style="font-family: 'Courier New', Courier, monospace;">nodlr</span> branch in the github repo.<br />
<br />
When I wrote the ClojureCLR compiler, I was interested in seeing what kind of mileage I could get out of the Dynamic Language Runtime, specifically the DLR's expression tree mechanism. The DLR's ETs extended the ETs used in Linq by providing enhanced control flow capabilities. They are central to other dynamic language implementations on the CLR such as IronPython and IronRuby. <br />
<br />
The first version of the ClojureCLR compiler mimicked the JVM compiler through its initial phases. The Lisp reader translates source code to Lisp data structures that are parsed to generate abstract syntax trees. The ClojureJVM compiler traverses the ASTs to produce JVM bytecodes. The ClojureCLR compiler instead generates DLR ETs from the ASTs. Those ETs are then asked to generate MSIL code.<br />
<br />
I got a lot of mileage out of using the DLR for code generation. I got to avoid some of the hairier aspects of MSIL and the CLR-- things like value types, generic types, nullable types, for example, are handled nicely by ETs. I also found it easier to experiment. However, using ETs had at least two drawbacks. One was that going from ASTs to MSIL through ETs likely nearly doubles the work of MSIL generation. Another was that ETs were restricted to producing static methods only. Working around this restriction introduced several inefficiencies in the resulting code.<br />
<br />
The Clojure model for functions maps each defined function to a class. For example, compiling<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace;">(defn f</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> ([x] ... )</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> ([x y] ... ))</span><br />
<br />
yields a class named something like <span style="font-family: 'Courier New', Courier, monospace;">user$f__1295</span> that implements <span style="font-family: 'Courier New', Courier, monospace;">clojure.lang.IFn</span>, with overrides for virtual methods <span style="font-family: 'Courier New', Courier, monospace;">invoke(Object)</span> and <span style="font-family: 'Courier New', Courier, monospace;">invoke(Object,Object)</span>. (The actual value to which <span style="font-family: 'Courier New', Courier, monospace;">f</span> would be bound would be an instance of this class.)<br />
<br />
Note that the <span style="font-family: 'Courier New', Courier, monospace;">invoke</span> overrides of necessity are instance methods. Recall from above that DLR ETs cannot produce instance methods. Toss in a another little problem referring to unfinished types. Shake and stir. You end up with the following abomination: Where Clojure/JVM generates one class and two methods for the example above, ClojureCLR would have to generate two classes and four methods. An <span style="font-family: 'Courier New', Courier, monospace;">invoke</span> override method is just a passthrough to a DLR-generated static method taking the function object as a first paramenter.<br />
<br />
For several years I hoped that the DLR team would get around to looking into class and instance method generation. This now seems unlikely. So I finally decided to rewrite the code generation phase to eliminate most uses of the DLR.<br />
<br />
The new code gen code yields significant improvements in compilation time and code size. Compiling the bootstrap clojure core environment is roughly twice as fast. The generated assemblies are about 20% smaller. Startup time (<a href="http://clojureclr.blogspot.com/2011/12/using-ngen-to-improve-clojureclr.html">non-NGEN'd</a>) is 11% faster. A few benchmarks I've run show speedups ranging from 4% to 16%. This is in line with my best hopes.<br />
<br />
One other benefit: with code generation more closely modeled after the JVM version, future maintainers will need less knowledge of the DLR.<br />
<br />
There are drawbacks to this move. The DLR guys know a lot more about about generating MSIL code than I do. Some wonderful goodness with names like <span style="font-family: 'Courier New', Courier, monospace;">Expression.Convert</span> and <span style="font-family: 'Courier New', Courier, monospace;">Expression.Call</span> were my best friends They are (mostly) gone now. And, oh, the beauty of DebugView for ETs for debugging code gen--this will be missed. My new best friends are <i>peverify</i> and .Net Reflector, the caped duo for rooting out bad MSIL. Wonderful in their own way, but I have a sense of loss.<br />
<br />
So, where are we? I have a little more work to do before putting this on the master branch. I plan to make one last traversal of the old code looking at all occurrences of my former best friends to make sure I've been consistent in handling the complexities they hid. I also plan to reimplement a 'light compile' variation to be used during evaluation. The current version has it. (What this is and why it matters I leave to another time.) Neither task will take long.<br />
<br />
In the meantime, the <span style="font-family: 'Courier New', Courier, monospace;">nodlr</span> branch is ready for a workout by those who care and dare. Have at it.<br />
<br />
<br />
P.S. The DLR is still being used to provide CLR interop and polymorphic inline caching. Another topic-for-another-day.<br />
<br />
<br />David Millerhttp://www.blogger.com/profile/07657040519395296684noreply@blogger.com19tag:blogger.com,1999:blog-4262147391488425950.post-89490844904334349672012-02-03T00:00:00.000-06:002012-02-03T00:00:05.760-06:00vsClojure: It's alive!vsClojure is alive (again)!<br /><br /><div>
The ability to do Clojure(CLR) development in a Visual Studio context has been a fairly constant demand. vsClojure, a VS extension supporting ClojureCLR projects, had been fulfilling this need. </div>
<div>
However, the project had gone quiet for a while and dormancy does not inspire confidence in the OSS world.</div>
<div>
<br /></div>
<div>
Jon, AKA jmis, the author of vsClojure, and I discussed how to move vsClojure forward. The upshot is that Jon will continue contributing to vsClojure and we''ll transition the maintainer role to me. What that's meant so far: Jon's been working hard these last few weeks mowing the lawn and pulling some weeds. I've been applauding his efforts. Time to invite the neighbors over for a lawn party. Here's what we're celebrating:</div>
<div>
<br /></div>
<div>
<b>vsClojure has a new home. </b> The repo has been moved to <a href="https://github.com/vsclojure/vsclojure">https://github.com/vsclojure/vsclojure</a>. The README there has instructions for installing and for building from source. (Installation is easy: use the VS extension manager to pull vsClojure from the Visual Studio Gallery.)</div>
<div>
<br /></div>
<div>
<b>vsClojure has a new release. </b>Several outstanding issues were closed. The big advance is that ClojureCLR 1.3 is now supported.</div>
<div>
<br /></div>
<div>
<div>
If you have the old version of vsClojure installed, you will see a notification of vsClojure's new home if you update the deprecated version. (I'm not sure if VS will automatically notify you.)<br /><br /><img src="https://mail.google.com/mail/images/cleardot.gif" /><br /><b>vsClojure is being actively developed.</b> Jon and I are working on a development plan for enhancements to vsClojure. Features currently supported include:</div>
<div>
<br /></div>
<ul>
<li>Clojure project type</li>
</ul>
<blockquote class="tr_bq">
<ul>
<li>Building and running clojure projects </li>
</ul>
</blockquote>
<ul>
<li>Clojure source editor</li>
</ul>
<blockquote class="tr_bq">
<ul>
<li>Syntax highlighting</li>
</ul>
</blockquote>
<blockquote class="tr_bq">
<ul>
<li>Brace matching</li>
</ul>
<ul>
<li>Auto-indentation</li>
</ul>
<ul>
<li>Source formatting </li>
</ul>
<ul>
<li>Block commenting</li>
</ul>
<ul>
<li>Hippie completion</li>
</ul>
</blockquote>
<ul>
<li>Integrated REPL </li>
</ul>
<blockquote class="tr_bq">
<ul>
<li>Load all project files into REPL </li>
</ul>
<ul>
<li>Load active editor file into REPL</li>
</ul>
<ul>
<li>Switch to active file's namespace </li>
</ul>
<ul>
<li>History </li>
</ul>
</blockquote>
</div>
<div>
Let us know what features you'd like to see added or what needs work. You can create issues on the github repo. Feel free to start discussions on <a href="http://groups.google.com/group/vsclojure-extension">the discussion group</a>. And, of course, feel free to dive in and hack away.</div>
<div>
<br /></div>
<div>
My thanks to Jon for all the effort he's put in to vsClojure to date. I'm even more thankful he's willing to keep going. I'm looking forward to it.</div>
<div>
<br /></div>
<div>
<br /></div>David Millerhttp://www.blogger.com/profile/07657040519395296684noreply@blogger.com6tag:blogger.com,1999:blog-4262147391488425950.post-22501606448514576522012-01-23T00:00:00.000-06:002012-01-23T00:00:10.393-06:00Compiling and loading in ClojureCLRWherein I document environment variables and other factors influencing compiling and loading files in ClojureCLR and how ClojureCLR differs from Clojure in this regard.<br />
<br />
<span style="font-size: large;">Compiler variables</span><br />
<br />
During AOT-compilation, the following vars are consulted to control aspects of the compilation process:<br />
<br />
<table border="1">
<tbody>
<tr><th>Var</th><th>doc says</th></tr>
<tr><td><pre>*compile-path*</pre>
</td>
<td>Specifies the directory where 'compile' will write out .class
files. This directory must be in the classpath for 'compile' to
work. Defaults to "classes"</td></tr>
<tr><td><pre>*unchecked-math*</pre>
</td>
<td>While bound to true, compilations of +, -, *, inc, dec and the
coercions will be done without overflow checks. Default: false.</td></tr>
<tr><td><pre>*warn-on-reflection*</pre>
</td>
<td>When set to true, the compiler will emit warnings when reflection is
needed to resolve Java method calls or field accesses. Defaults to false.</td></tr>
</tbody></table>
<br />
If you compile by invoking the <span style="font-family: 'Courier New', Courier, monospace;">compile </span>function, such as from a REPL, you will have had a chance to set these vars to appropriate values. However, when compiling from the command line by running <span style="font-family: 'Courier New', Courier, monospace;">Clojure.Compile.exe</span>, you do not have a chance to run Clojure code to initialize these vars. Instead, you can set environment variables to initialize these vars prior to compilation.<br />
<br />
The same is true for Clojure. In fact, ClojureCLR and Clojure used the same environment variables for these variables until just recently. Starting with the 1.4.0-alpha5 release (already in the master branch), ClojureCLR has changed the environment variable names to be strict POSIX-compliant. This is due to problems with periods in environment variable names in Cygwin's bash -- see <a href="ttp://groups.google.com/group/clojure/browse_thread/thread/bcb2ff96d9bcbebc/6bc0f46180dc2683?hl=en">this thread</a> for more information. Here are the names:
<br />
<br />
<table border="1">
<tbody>
<tr><th>Clojure & older ClojureCLR</th><th>new in ClojureCLR</th></tr>
<tr><td><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">clojure.compile.path</span></td><td><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">CLOJURE_COMPILE_PATH</span></td></tr>
<tr><td><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">clojure.compile.unchecked-math</span></td><td><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">CLOJURE_COMPILE_UNCHECKED_MATH</span></td></tr>
<tr><td><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">clojure.compile.warn-on-reflection</span></td><td><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">CLOJURE_COMPILE_WARN_ON_REFLECTION</span></td></tr>
</tbody></table>
<br />
BTW, ClojureCLR defaults <span style="font-family: 'Courier New', Courier, monospace;">*compile-path*</span> to <span style="font-family: 'Courier New', Courier, monospace;">"."</span>. <span style="font-family: 'Courier New', Courier, monospace;">"classes"</span> didn't seem to make sense given that ClojureCLR creates assemblies. <br />
<br />
<span style="font-size: large;">Locating files</span><br />
<div>
<br /></div>
For identifying libraries for loading, Clojure relates the symbol naming the library to a Java package name and uses Java's mapping of package name to a classpath-relative path. For example, evaluating <span style="font-family: 'Courier New', Courier, monospace;">(compile 'a.b.c)</span> causes Clojure to look for a file <span style="font-family: 'Courier New', Courier, monospace;">a/b/c.clj</span> relative to some root listed on the classpath. The result of the compilation will be a set of classfiles, written to <span style="font-family: 'Courier New', Courier, monospace;">classes/a/b/c</span>.<br />
<div>
<br /></div>
<div>
ClojureCLR follows Clojure in mapping dotted symbol names to relative paths. Not having classpaths, ClojureCLR instead uses the value of the environment variable <span style="font-family: 'Courier New', Courier, monospace;">CLOJURE_LOAD_PATH</span> to supply roots for the file probes. In addition, it will look (first) in the current directory and directory of the entry assembly.</div>
<div>
<br /></div>
<div>
The same holds for <span style="font-family: 'Courier New', Courier, monospace;">load</span>, <span style="font-family: 'Courier New', Courier, monospace;">use</span>, <span style="font-family: 'Courier New', Courier, monospace;">require</span> and other lib-loading functions.</div>
<div>
<div>
<div>
<br /></div>
<div>
<span style="font-size: large;">Assembly output</span></div>
<div>
<br /></div>
<div>
The Clojure compiler outputs (many) class files. The ClojureCLR compiler outputs (not as many) assemblies. All classes resulting from <span style="font-family: 'Courier New', Courier, monospace;">(compile 'a.b.c)</span> will go into an assembly named <span style="font-family: 'Courier New', Courier, monospace;">a.b.c.clj.dll</span> located in <span style="font-family: 'Courier New', Courier, monospace;">*compile-path*</span>.</div>
<div>
<br /></div>
<div>
When evaluating <span style="font-family: 'Courier New', Courier, monospace;">(load "a/b/c")</span>, ClojureCLR will look for both <span style="font-family: 'Courier New', Courier, monospace;"><AppDomain.CurrentDomain.BaseDirectory>\a.b.c.clj.dll</span> and <span style="font-family: 'Courier New', Courier, monospace;"><any_load_path_root>\a\b\c.clj</span>, and load the assembly if it exists and has a timestamp newer than the <span style="font-family: 'Courier New', Courier, monospace;">.clj</span> file (if it exists). At the moment the same set of roots (as named above) is used for assemblies and source code. <br />
<br />
<span style="font-family: 'Courier New', Courier, monospace;">AppDomain.CurrentDomain.BaseDirectory</span> is used as the root for ClojureCLR assembly probes as that is also the CLR's root for resolving assembly references. </div>
<div>
<br /></div>
<div>
<span style="font-size: large;">Too many assemblies</span></div>
<div>
<br /></div>
<div>
Each file loaded during compilation will go into its own assembly. I find this terribly inelegant. The distribution for ClojureCLR itself needs <span style="font-family: 'Courier New', Courier, monospace;">Clojure.Main.exe</span>, <span style="font-family: 'Courier New', Courier, monospace;">Clojure.Compile.exe</span>, and the DLR support assemblies, of course, but also thirty-plus assemblies resulting from compiling the Clojure source that defines the initial environment. The <i>pprint</i> lib alone contributes eight assemblies. They are not really independent. Conceivably that code all could go into one assembly. </div>
<div>
<br /></div>
<div>
I've not been able to think of a way to make this work. I know that the eight files making up <i>pprint</i> are related. They get compiled because the main <i>pprint</i> file loads each of them, and loading a file while compiling cause that file to be compiled also. I could very easily write the compiler to output the code into the same assembly as the parent. However, <i>pprint</i> could load support code that should not be part of its assembly, that should have its own assembly. In fact, it does; <i>pprint</i> loads <i>clojure.walk</i>. It happens to do this with a <span style="font-family: 'Courier New', Courier, monospace;">:use</span> clause in its <span style="font-family: 'Courier New', Courier, monospace;">ns</span> form, but it doesn't have to. Without a mechanism in Clojure that allows us to distinguish these uses of <span style="font-family: 'Courier New', Courier, monospace;">load</span>, I'm afraid we're stuck with some inelegance.</div>
</div>
</div>David Millerhttp://www.blogger.com/profile/07657040519395296684noreply@blogger.com10tag:blogger.com,1999:blog-4262147391488425950.post-17155618140628914782012-01-17T00:30:00.000-06:002012-01-22T17:49:00.404-06:00Porting effort for Clojure contrib libsLooking for Clojure contrib lib projects to port to ClojureCLR? <br />
<br />
I looked at the most popular libs on <a href="https://github.com/clojure">https://github.com/clojure</a>, the official libs of the clojure project. I defined popularity by the number of watchers, lacking a better criterion. Here are the top projects sorted by number of watchers when I looked recently. Ignoring those in single digits and all java.* projects, here they are:<br />
<br />
<table style="text-align: center;">
<tbody>
<tr><th>Watchers</th><th>Project</th><th></th><th>Watchers</th><th>Project</th></tr>
<tr><td><div style="text-align: center;">
129</div>
</td><td><div style="text-align: center;">
core.logic</div>
</td><td style="text-align: center;"></td><td><div style="text-align: center;">
23</div>
</td><td><div style="text-align: center;">
test.generative</div>
</td></tr>
<tr><td><div style="text-align: center;">
69</div>
</td><td><div style="text-align: center;">
core.match</div>
</td><td style="text-align: center;"></td><td><div style="text-align: center;">
20</div>
</td><td><div style="text-align: center;">
core.cache</div>
</td></tr>
<tr><td><div style="text-align: center;">
60</div>
</td><td><div style="text-align: center;">
tools.nrepl</div>
</td><td style="text-align: center;"></td><td><div style="text-align: center;">
19</div>
</td><td><div style="text-align: center;">
core.memoize</div>
</td></tr>
<tr><td><div style="text-align: center;">
37</div>
</td><td><div style="text-align: center;">
tools.cli</div>
</td><td style="text-align: center;"></td><td><div style="text-align: center;">
18</div>
</td><td><div style="text-align: center;">
algo.monads</div>
</td></tr>
<tr><td><div style="text-align: center;">
36</div>
</td><td><div style="text-align: center;">
data.finger-tree</div>
</td><td style="text-align: center;"></td><td><div style="text-align: center;">
15</div>
</td><td><div style="text-align: center;">
data.xml</div>
</td></tr>
<tr><td><div style="text-align: center;">
35</div>
</td><td><div style="text-align: center;">
tools.logging</div>
</td><td style="text-align: center;"></td><td><div style="text-align: center;">
11</div>
</td><td><div style="text-align: center;">
test.benchmark</div>
</td></tr>
<tr><td><div style="text-align: center;">
32</div>
</td><td><div style="text-align: center;">
core.unify</div>
</td><td style="text-align: center;"></td><td><div style="text-align: center;">
10</div>
</td><td><div style="text-align: center;">
core.incubator</div>
</td></tr>
<tr><td><div style="text-align: center;">
28</div>
</td><td><div style="text-align: center;">
data.json</div>
</td><td style="text-align: center;"></td><td><div style="text-align: center;">
10</div>
</td><td><div style="text-align: center;">
data.csv</div>
</td></tr>
<tr><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td><td><div style="text-align: center;">
10</div>
</td><td><div style="text-align: center;">
tools.macro</div>
</td></tr>
</tbody></table>
<div style="text-align: center;">
<br /></div>
There are some fairly trivial edits that are required in porting most libs. These include:<br />
<br />
<ol>
<li>Substituting an appropriate CLR exception class. For example, <span style="font-family: 'Courier New', Courier, monospace;">InvalidArgumentException</span> becomes <span style="font-family: 'Courier New', Courier, monospace;">ArgumentException</span>. If a throw uses <span style="font-family: 'Courier New', Courier, monospace;">Exception</span>, that will work as is.</li>
<li>Substituting interop method names. For example, <span style="font-family: 'Courier New', Courier, monospace;">toString </span>becomes <span style="font-family: 'Courier New', Courier, monospace;">ToString</span>, <span style="font-family: 'Courier New', Courier, monospace;">hashCode </span>becomes <span style="font-family: 'Courier New', Courier, monospace;">GetHashCode</span>, etc. Most <span style="font-family: 'Courier New', Courier, monospace;">String </span>methods and some I/O methods just need capitialization. BTW, ClojureCLR preserves case on most clojure.lang class method names so they don't need to be changed. (You're welcome.) Also, method names on protocols won't need to be changed.</li>
</ol>
<br />
I'll refer to these kinds of changes below as <i>the usual</i>.<br />
<br />
I did a quick scan of the source of each project to estimate the effort required to port the project to ClojureCLR. In the order given above, here are some comments on each.
<br />
<br />
<b><span style="font-size: large;">core.logic: </span></b>This is one of the larger projects. The usual, and not that much of it. The only thing I saw that might take a little more investigation is that the deftype <span style="font-family: 'Courier New', Courier, monospace;">Pair </span>implements <span style="font-family: 'Courier New', Courier, monospace;">java.util.Map$Entry</span>. (See below for more.) <b>Easy. </b>(Unless it requires actual thought, in which case you'd have to understand the code, and that would make it a <b>Challenge</b>.)<br />
<br />
<b><span style="font-size: large;">core.match:</span></b> Another large project. The usual, and not much of it. The <span style="font-family: 'Courier New', Courier, monospace;">bean-match</span> function will require adaptation to CLR classes and the regular expression matcher will need to be examined -- JVM vs CLR regexes always requires a look. Of most concern is the deftype <span style="font-family: 'Courier New', Courier, monospace;">MapPattern </span>that mentions <span style="font-family: 'Courier New', Courier, monospace;">java.util.Map</span>. The question is always dealing with IDictionary and <span style="font-family: 'Courier New', Courier, monospace;">IDictionary<K,V></span> -- support for arbitray generics is always tricky. Probably <b>Easy</b>, with the same caveat as core.logic.<br />
<br />
<b><span style="font-size: large;">tools.nrepl:</span></b> This is likely to be tricky. There are some Java classes that will have to be ported. Of greater concern is the amount of low-level I/O on sockets. At best, a <b>Medium </b>project, likely a <b>Challenge</b>. Given that this project is being redesigned, it might be wise to wait for 2.0 and then put in the effort.<br />
<br />
<b><span style="font-size: large;">tools.cli:</span></b> The uusual, and not much of it. There is a test that uses an Integer method. <b>Trivial</b>.<br />
<br />
<b><span style="font-size: large;">data.finger-tree:</span></b> The usual. The only concern is the mention of <span style="font-family: 'Courier New', Courier, monospace;">java.util.Set</span>. There is no <span style="font-family: 'Courier New', Courier, monospace;">System.Collections.ISet,</span> only <span style="font-family: 'Courier New', Courier, monospace;">System.Collections.Generic.ISet<T></span><span style="font-family: inherit;">, so some thought will be required. </span>At worst, <b>Medium</b>; more likely <b>Easy.</b><br />
<br />
<b><span style="font-size: large;">tools.logging:</span></b> This will take some work because adapters for .Net logging tools will have be developed. One might consider log4net, ELMAH, NLog. The good news is that the code is designed to plug different adapters into its framework, so developing new adapters should be easy, requiring mostly a decent knowledge of the target logging framework. Most of the tests will have to be rewritten. <b>Medium</b>, probably fun.<br />
<br />
<b><span style="font-size: large;">core.unify:</span></b> The usual. The same concern about <span style="font-family: 'Courier New', Courier, monospace;">java.util.Map</span> mentioned for core.match. I'm guessing this is trivial here. <b>Easy</b>.<br />
<br />
<b><span style="font-size: large;">data.json:</span></b> We know exactly how much work this will take. See <a href="http://clojureclr.blogspot.com/2012/01/porting-libs-to-clojureclr-example.html">Porting libs to ClojureCLR: an example</a>.<br />
<br />
<b><span style="font-size: large;">test.generative:</span></b> Needs tools.namespace. That didn't make the popularity cut, but it should be barely <b>Medium </b>to port, mostly due to the need to think a little about the I/O interop. In test.generative, there are some library calls, to Random, Math.* methods, system time, etc., that will take a little more work than just the usual. Barely <b>Medium</b>.<br />
<br />
<b><span style="font-size: large;">core.cache: </span></b>A moment's thought about replacing <span style="font-family: 'Courier New', Courier, monospace;">java.lang.Iterable</span> in the definition of <span style="font-family: 'Courier New', Courier, monospace;">defcache</span>. Otherwise, just the usual. <b>Easy</b>.<br />
<br />
<b><span style="font-size: large;">core.memoize:</span></b> Needs core.cache. Might work as-is! <b>Trivial</b>.<br />
<br />
<b><span style="font-size: large;">algo.monads:</span></b> Might work as-is! <b>Trivial</b>. Hey, when was the last time you saw 'trivial' and 'monads' in such proximity?<br />
<br />
<b><span style="font-size: large;">data.xml:</span></b> The README notes that is is not yet ready for use. Really, this should be called java.xml because of its dependence on org.xml.sax, java.xml.parsers, etc. This will require a major rewrite. Until this is complete, I can't say how hard it will be.<br />
<br />
<b><span style="font-size: large;">test.benchmark:</span></b> Looks straightforward. <b>Easy</b>.<br />
<br />
<b><span style="font-size: large;">core.incubator:</span></b> The toughest thing is reference to java.util.Map (see above). <b>Trivial</b>.<br />
<br />
<b><span style="font-size: large;">data.csv:</span></b> The I/O will take some time, but at worst a <b>Medium</b>. A very <b>Easy Medium</b> at that.<br />
<br />
<b><span style="font-size: large;">tools.macro:</span></b> Appears to be <b>Trivial</b>.<br />
<br />
So, what are you waiting for. Plenty of easy ones to get started with and a few more challenging ones. Whatever you pick, you'll have a chance to read some good Clojure code, always a worthwhile exercise.<br />
<br />
Where are the hard ones, you ask? They certainly exist, just not among the official contrib libs. There are plenty of other Clojure projects floating around that will require significant effort.<br />
<br />
<b>Port a lib today!</b><br />
<br />
A note on <span style="font-family: 'Courier New', Courier, monospace;">java.util.Map$Entry</span>: <span style="font-family: 'Courier New', Courier, monospace;">clojure.lang.IMapEntry</span> extends <span style="font-family: 'Courier New', Courier, monospace;">java.util.Map$Entry</span> on the JVM. ClojureCLR could not do that because the equivalent to <span style="font-family: 'Courier New', Courier, monospace;">Map$Entry</span>, <span style="font-family: 'Courier New', Courier, monospace;">System.Collections.DictionaryEntry</span>, is a struct and can't be subclassed. Also, we have the problem with the generic <span style="font-family: 'Courier New', Courier, monospace;">System.Collections.Generic.KeyValuePair<TKey,TValue></span>. I shudder when I see <span style="font-family: 'Courier New', Courier, monospace;">Map$Entry</span>; this is a sign that real thinking will be required.David Millerhttp://www.blogger.com/profile/07657040519395296684noreply@blogger.com10tag:blogger.com,1999:blog-4262147391488425950.post-21596037872920905662012-01-06T00:30:00.000-06:002012-01-06T00:30:06.181-06:00Porting libs to ClojureCLR: an exampleResponses to the 2011 ClojureCLR survey gave high priority to the porting of Clojure contrib libs to ClojureCLR. One action item resulting from an <a href="http://clojureclr.blogspot.com/2011/11/survey-says-port-those-libs.html">analysis of the responses</a> was to provide examples of the porting process. As an example, I decided to port the <a href="https://github.com/clojure/data.json">data.json contrib lib</a>, authored by Stuart Sierra. In looking across all the authorized contrib libs on <a href="https://github.com/clojure">github.com/clojure</a>, this port was above trivial but below daunting in complexity. (In a later post, I will analyze all the contrib libs for complexity.)<br />
<br />
The following recipe will work for simple ports.<br />
<br />
<b>Figure out how the original code works.</b> This step might be optional on the simplest ports involving just simple interop method renaming. For this port, I had to modify one algorithm and think through extending a protocol to CLR types.<br />
<br />
<b>Create a project for the port.</b> I did not fork the original data.json project on github; the project needs its own identity and you're not going to be issuing pull requests back to the original.<br />
<br />
You are on your own for picking project names and namespace structures for these ports. I chose the name <b>cljclr.data.json</b> for both the project and the namespace. You will find my project <a href="https://github.com/dmiller/clrclj.data.json">here</a>.<br />
<br />
<blockquote class="tr_bq">
I would appreciate input on naming these projects. Here's my current thoughts. I didn't want to call this project <b>clr.data.json</b>--I plan to use <b>clr.<i>X.X</i></b> for ports of contrib libs that have names like <b>java.<i>X.X</i></b>. The namespace for <b>data.json</b> is actually <b>clojure.data.json</b>, so I decided to use <b>cljclr.data.json</b>. I thought of <b>data.json.clr</b> and other variations adding <b>clr</b> as a component, but was offended by having on extra layer of subdirectory injected. I don't actually like <b>cljclr--</b>I can't read it and I always mistype it. Help!</blockquote>
In the absence of tools such as leiningen or a working Visual Studio extension, for now you will have to come up with your project structure. I just used<br />
<br />
<ul>
<li><root></li>
<ul>
<li> src</li>
<li> test</li>
</ul>
</ul>
<br />
as the two main branches, with subdirectories corresponding to the namespaces.<br />
<br />
<b>Copy files from the source project.</b> Usually, you can preserve the basic code structure, relocating files appropriately for your namespace structure. The data.json project really has only two files of significance: <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">json.clj</span> and <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">json_test.clj</span>. I copied them into <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">src/cljclr/data/json.clj</span> and <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">test/cljclr/data/json_test.clj</span>.<br />
<br />
<b>Modify file headers.</b> I changed the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">ns</span> directive in each file to match my namespace structure. If you are interested in things like copyrights, you will have figure out how you want to acknowledge the original author according the license on the original project.<br />
<br />
<b>Scan for trouble. </b>I look for trouble. Here are some of the things I look for.<br />
<br />
<ul>
<li><b>Imports in the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">ns</span> directive.</b> Imports of clojure.lang classes are usually okay--I've been carerful to maintain class names and public method names to match Clojure as best I can. Anything starting <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">java.</span> will have to be replaced.</li>
<li><b>Interop calls.</b> Scan for <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">(.name</span>, <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">(name.</span>, and <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">(CapName/name</span>. If you are lucky, a simple capitalization will handle many of the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">(.name</span> calls.</li>
<li><b>Type hints.</b> Most type hints of classes outside <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">clojure.lang</span> will need to be changed. Carats feel like sticks.</li>
<li><b>Exceptions.</b> The only exception class that works unchanged is <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Exception</span> itself.</li>
<li><b>CapitalLetters.</b> Given that Clojure code is mostly lowercase, anything with CapitalLetters is likely to be trouble.</li>
</ul>
<div>
<b>Do simple renamings.</b> Hack out the bad imports and add new ones as you work through the code. Work through each interop call and determine equivalents; ditto for type hints and exceptions.</div>
<div>
<br /></div>
<div>
I adopt a uniform method of marking the places where I make changes. This makes it easier to update the port as the original lib changes. You will see lines like this in my code:</div>
<div>
<br /></div>
<div>
(Char/IsWhiteSpace c) (recur (.Read stream) result) ;DM: Character/isWhitespace .read </div>
<div>
<br /></div>
<div>
where the comment shows what was changed from in the original code.</div>
<div>
<br /></div>
<div>
For json.clj, I made the following simple changes. <br />
<br />
Method renamings:</div>
<div>
<br /></div>
<table border="1">
<tbody>
<tr><th>From</th><th>To</th><th>Count</th></tr>
<tr><td>(.read</td><td>(.Read</td><td><div style="text-align: center;">
30</div>
</td></tr>
<tr><td>(.append</td><td>(.Append</td><td><div style="text-align: center;">
14</div>
</td></tr>
<tr><td>(.print</td><td>(.Write</td><td><div style="text-align: center;">
11</div>
</td></tr>
<tr><td>(.unread</td><td>(.Unread</td><td><div style="text-align: center;">
3</div>
</td></tr>
<tr><td>(Character/isWhitespace</td><td>(Char/IsWhiteSpace</td><td><div style="text-align: center;">
3</div>
</td></tr>
<tr><td>(.isArray</td><td>(.IsArray</td><td><div style="text-align: center;">
2</div>
</td></tr>
<tr><td>(.charAt</td><td>(.get_Chars</td><td><div style="text-align: center;">
1</div>
</td></tr>
<tr><td>(.toString</td><td>(.ToString</td><td><div style="text-align: center;">
1</div>
</td></tr>
</tbody></table>
<div>
<br /></div>
<div>
Type renamings:<br />
<br /></div>
<table border="1">
<tbody>
<tr><th>From</th><th>To</th><th>Count</th></tr>
<tr><td>PushbackReader</td><td>PushbackTextReader</td><td><div style="text-align: center;">
9</div>
</td></tr>
<tr><td>PrintWriter</td><td>TextWriter</td><td><div style="text-align: center;">
5</div>
</td></tr>
<tr><td>PrintWriter</td><td>StreamWriter</td><td><div style="text-align: center;">
1</div>
</td></tr>
<tr><td>CharSequence</td><td>String</td><td><div style="text-align: center;">
1</div>
</td></tr>
<tr><td>EOFException</td><td>EndOfStreamException</td><td><div style="text-align: center;">
5</div>
</td></tr>
</tbody></table>
<div>
<br /></div>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">PrintWriter </span>was mostly used as a type hint, and could have <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">TextWriter </span>substituted. In one place, it was used new'd. <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">TextWriter</span> is abstract and can't be constructed, so <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">StreamWriter</span> had to be used in that place.<br />
<br />
This project is obviously quite I/O-centric. Fortunately, there is sufficient commonality between the I/O libraries on the JVM and CLR to make this part of the translation fairly routine.<br />
<br />
At this point, you are probably very close to being able to load the file. You can try loading or compiling and let the errors guide you.<br />
<br />
<b>Check for reflection warnings. </b> I find it useful to <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">(set! *warn-on-reflection* true)</span> at the start of each code file. I don't do this for performance, but it can catch bad type hints and misnamed methods in the code. The perf I care about is coding perf, not runtime.<br />
<br />
<b>Do the hard parts.</b> The remaining changes were not as easy. There were two other type renamings, not I/O-related.<br />
<blockquote class="tr_bq">
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">java.util.Map</span> => <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">System.Collections.IDictionary</span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">java.util.Collection </span>=> <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">System.Collections.ICollection</span></blockquote>
If you see Java collection types, you are going to have think about the correct alternatives. In general, we have no way to deal with CLR generic collection types -- most uses of these type names will require the type parameters to be instantiated, so you can't say you want all <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">System.Collections.GenericICollection<T></span> to be handled. However, most of the generic collection types will provide non-generic interfaces to work with. That is the solution I chose for this code:<br />
<br />
<pre class="brush: clojure">(defn- pprint-json-dispatch [x escape-unicode]
(cond (nil? x) (print "null")
(instance? System.Collections.IDictionary x)
(pprint-json-object x escape-unicode) ;DM: java.util.Map
(instance? System.Collections.ICollection x)
(pprint-json-array x escape-unicode) ;DM: java.util.Collection
(instance? clojure.lang.ISeq x)
(pprint-json-array x escape-unicode)
:else (pprint-json-generic x escape-unicode)))
</pre>
<br />
Another common trouble spot is dealing with the Java primitive wrapper classes, such as <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Integer</span>. You mostly like won't see many type hints, but you will see calls to static methods. There is only one in this code. In read-json-hex-character, I translated <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">(Integer/parseInt s 16)</span> to <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">(Int32/Parse s NumberStyles/HexNumber)</span>. (I added an import for <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">System.Globalization.NumberStyles</span>.) I don't have a list of rules for this. You're on your own.<br />
<br />
Extending protocols to Java library classes will also cause you to spend some time thinking. The primary difficulty here came in extensions to the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Write-JSON</span> protocol. Extensions to things like <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">nil</span> and <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">clojure.lang.Named</span> were unchanged. Other extensions had to be modifed.<br />
<br />
You will have a problem anytime you run into<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> java.lang.Number</span>. This is a base class for all the primtive numeric wrapper classes such as Integer. There is no equivalent in the CLR. I created extensions for each primitive numeric type.<br />
<br />
<pre class="brush: clojure">(extend System.Byte Write-JSON {:write-json write-json-plain})
(extend System.SByte Write-JSON {:write-json write-json-plain})
(extend System.Int16 Write-JSON {:write-json write-json-plain})
...
</pre>
<br />
Also, <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">java.math.BigInteger</span> and <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">java.math.BigDecimal</span> will need to be translated to <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">clojure.lang.BigInteger</span> and <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">clojure.lang.BigDecimal</span>, and <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">CharSequence</span> usualy goes to <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">String</span>.<br />
<br />
The only significant algorithmic change was in <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">write-json-string</span>. Stuart was careful to properly handle full Unicode, which means not just iterating through the string character by character but dealing with actual Unicode code points as expressed in the UTF-16 encoding used in Java strings. CLR strings use the same encoding, but the proper way to iterate through Unicode code points is different. This took the most time for me to translate due to my own ignorance. I ended up with<br />
<br />
<pre class="brush: clojure">(defn- write-json-string [^String s ^PrintWriter out escape-unicode?]
(let [sb (StringBuilder. ^Integer(count s))]
(.append sb \")
(dotimes [i (count s)]
(let [cp (Character/codePointAt s i)]
(cond
;; Handle printable JSON escapes before ASCII
(= cp 34) (.append sb "\\\"")
...
(< 31 cp 127) (.append sb (.charAt s i))
...
:else (if escape-unicode?
;; Hexadecimal-escaped
(.append sb (format "\\u%04x" cp))
(.appendCodePoint sb cp)))))
...
</pre>
<br />
becoming<br />
<br />
<pre class="brush: clojure">(defn- write-json-string [^String s ^TextWriter out escape-unicode?]
(let [sb (StringBuilder. ^Int32 (count s))
chars32 (StringInfo/ParseCombiningCharacters s)]
(.Append sb \")
(dotimes [i (count chars32)]
(let [cp (Char/ConvertToUtf32 s (aget chars32 i))]
(cond
;; Handle printable JSON escapes before ASCII
(= cp 34) (.Append sb "\\\"")
...
(< 31 cp 127) (.Append sb (.get_Chars s i))
...
:else (if escape-unicode?
;; Hexadecimal-escaped
(.Append sb (format "\\u%04x" cp))
(.Append sb (Char/ConvertFromUtf32 cp))))))
...
</pre>
<br />
<b>Translate your tests.</b> This is generally easier. The only changes I had to make were to some setup code for certain tests. Only a handful of changes were required.<br />
<br />
<b>Test. Repair. Repeat. </b> Good luck.<br />
<br />
After just a few iterations, I had all tests passing except one. In the pretty-print test, I was getting output for some floating point number that were exact integers without a .0 at the end as was required by the test. Having run into this before, I recalled that I had defined a helper function name fp-str to take care of this. <br />
<br />
<pre class="brush: clojure">(defn- write-json-float [x ^TextWriter out escape-unicode?]
(.Write out (fp-str x)))
</pre>
<br />
and then modifed the two float-type extends:<br />
<br />
<pre class="brush: clojure">(extend System.Double Write-JSON {:write-json write-json-float})
(extend System.Single Write-JSON {:write-json write-json-float})
</pre>
<br />
GREEN!!!!<br />
<br />
<b>Celebrate. </b><br />
<b>Publish.</b><br />
<br />
I leave these steps to you.<br />
<b><br /></b><br />
<b>Next steps?</b> Choose something to port and go for it.<b> </b><br />
<b><br /></b><br />
Many of the contrib libs will require significantly less work than this. There are others that will require almost complete rewrites. Outside of the core contrib libs, many of the requested ports such as leiningen and the web frameworks are going to a lot of work.<br />
<br />
<b>Resources</b><br />
<br />
* data.json: <a href="https://github.com/clojure/data.json">https://github.com/clojure/data.json</a><br />
* clrclj.data.json -- <a href="https://github.com/dmiller/clrclj.data.json">https://github.com/dmiller/clrclj.data.json</a>David Millerhttp://www.blogger.com/profile/07657040519395296684noreply@blogger.com0tag:blogger.com,1999:blog-4262147391488425950.post-5176995777315115562012-01-03T00:30:00.000-06:002012-01-03T00:30:05.284-06:00Referring to typesThe basics for referring to types for CLR interop are the same for ClojureCLR as for Clojure on the JVM. I will assume you are familiar with interop as covered in <a href="http://clojure.org/java_interop">http://clojure.org/java_interop</a> or your favorite Clojure intro.
<br />
<br />
Standard Clojure allows use of the symbols <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">int</span>, <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">double</span>, <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">float</span>, etc. in type hints to refer to the corresponding primitive types. ClojureCLR allows this and extends this to the numeric types present in the CLR but not in the JVM: <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">uint</span>, <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">ulong</span>, etc. Similarly, the shorthand array references such <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">ints</span> and <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">doubles</span> work, and are joined by <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">uints</span>, <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">ulongs</span>, etc.<br />
<br />
<b><i><u>The CLR is not C#</u></i></b>.<br />
Do not let the presence of <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">int</span> and company for type hinting put you in a C# frame of mind. When specifying generic types, you cannot use C# notation:<br />
<br />
<pre class="brush: csharp">System.Collections.Generic.IList<int>
</pre>
<br />
Instead, you must use the actual CLR type name:
<br />
<br />
<pre class="brush: csharp">System.Collections.Generic.IList`1[System.Int32]
</pre>
<br />
Remember that <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">float</span>becomes <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">System.Single</span>; I've had to dope-slap myself on that one a few times.<br />
<br />
Clojure uses symbols to refer to types. This works on the JVM because package-qualified class names are lexically compatible with symbols. Not so here. The backquote and square brackets in the type name shown above cannot be part of a symbol name. If you type that string of characters into the REPL, you will get
<br />
<br />
<pre class="brush: clojure">user=> System.Collections.Generic.IList`1[System.Int32]
CompilerException System.InvalidOperationException:
Unable to resolve symbol: System.Collections.Generic.IList in this context
at ...
1
[System.Int32]
</pre>
<br />
The input string is parsed as separate entities:<br />
<br />
<pre class="brush: clojure">System.Collections.Generic.IList
`1
[System.Int32]
</pre>
<br />
Not what was intended.<br />
<br />
In addition to backquotes and square brackets, a fully-qualified type name can contain an assembly identifier--that involves spaces and commas. In fact, CLR typenames can contain arbitrary characters. Backslashes can escape characters that do have special meaning in the typename syntax (comma, plus, ampersand, asterisk, left and right square bracket, left and right angle bracket, backslash).<br />
<br />
To allow symbols to contain arbitrary characters, ClojureCLR extends the reader syntax using "vertical bar quoting".
Vertical bars are used in pairs to surround the name or a part of the name of a symbol.
Any characters between the vertical bars are taken to be part of the symbol name. For example,
<br />
<br />
<pre class="brush: clojure">|A(B)|
A|(|B|)|
A|(B)|
</pre>
<br />
all mean the symbol whose name consists of the four characters A, (, B, and ). I consider only the first one to be readable; quoting the entire name is to be preferred. To quote the IList example above, you would write<br />
<br />
<pre class="brush: clojure">|System.Collections.Generic.IList`1[System.Int32]|</pre>
<br />
To include a vertical bar in a symbol name that is |-quoted, use a doubled vertical bar.<br />
<br />
<pre class="brush: clojure">|This has a vertical bar in the name ... || ...<>@#$@#$#$|
</pre>
<br />
With this mechanism can we make a symbol for a fully-qualified typename, such as:<br />
<br />
<pre class="brush: clojure">(|com.myco.mytype+nested, MyAssembly, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b14a123334343434|/DoSomething x y)
</pre>
<br />
or<br />
<br />
<pre class="brush: clojure">(reify
|AnInterface`2[System.Int32,System.String]|
(m1 [x] ...)
I2
(m2 [x] ...))
</pre>
<br />
<br />
There are a number of things you should note about |-quoting and about generic type references.<br />
<div>
<br /></div>
<div>
First, what |-quoting does is to prevent characters from stopping the token scan. Checks on symbol validity that follow token scanning are still in effect. These include not starting with a digit, containing a non-intial colon, and a few others. When scanning <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">A(B)</span>, the left parenthesis stops scanning the token that begins with <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">A</span>. When scanning <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">|A(B)|</span>, the left and right parentheses do not stop the scan. However, scanning <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">|ab:|</span> is the same as scanning <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">ab:</span>, a colon being a perfectly fine token constituent. However, the colon at the end is a no-no, and so the token is rejected and the reader throws an exception.</div>
<div>
<br />
(I could have taken more radical approach and allowed <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">|ab:|</span>. One then gets into all kinds of edge cases that I didn't want to solve. I feel that a more radical quoting approach requires consultation and agreement with the Clojure powers-that-be.)<br />
<br />
<br />
Second, be careful with namespaces for symbols. Any <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">/</span> appearing |-quoted does not count as a namespace/name separator. If you have special characters in either the namespace name or the symbol name, you must |-quote either one separately. Thus,<br />
<br />
<pre class="brush: clojure">(namespace 'ab|cd/ef|gh) ;=> nil
(name 'ab|cd/ef|gh) ;=> "abcd/efgh"
(namespace 'ab/cd|ef/gh|ij) ;=> "ab"
(name 'ab/cd|ef/gh|ij) ;=> "cdef/ghij"
</pre>
<br />
Rather than<br />
<br />
<pre class="brush: clojure">ab/cd|ef/gh|ij
</pre>
<br />
it would be more readable to write<br />
<br />
<pre class="brush: clojure">ab/|cdef/ghij|</pre>
<br />
Third, you will usually need to fully namespace-qualify generic types and their parameters. For example,<br />
<br />
<pre class="brush: clojure">|System.Collections.Generic.IList`1[System.Int32]|</pre>
<br />
works as a type reference while
<br />
<br />
<pre class="brush: clojure">|System.Collections.Generic.IList`1[Int32]|</pre>
<br />
does not.
<br />
<br />
Also, aliasing via <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">import</span> is not of much help. After eval'ing<br />
<br />
<pre class="brush: clojure">(import '|System.Collections.Generic.IList`1|)
</pre>
<br />
the symbol <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">|IList`1|</span> will refer in the current namespace to the generic type <span class="Apple-style-span" style="font-family: monospace; white-space: pre;">|System.Collections.Generic.IList`1|</span>, but that is of no help in referring to instantiated <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">IList</span> types. You cannot then refer to<br />
<br />
<pre class="brush: clojure">|IList`1[System.Int32]|
</pre>
<br />
Perhaps someday we will introduce a more compositional approach to generic types and symbols that will accommodate this.<br />
<div>
<br /></div>
Fourth, if you are familiar with |-quoting in Common Lisp, the ClojureCLR mechanism is not as inclusive. In CL you could include a literal vertical bar in a symbol name with backslash-escaping: <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">abc\|123</span> has name <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">“abc|123”</span>. CL has \-escaping for characters in symbol tokens; ClojureCLR does not.<br />
<br />
<br />
Finally, note that when printing with <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">*print-dup*</span> true, symbols with 'bad' characters will be |-quoted.</div>David Millerhttp://www.blogger.com/profile/07657040519395296684noreply@blogger.com2tag:blogger.com,1999:blog-4262147391488425950.post-1095235584835390892011-12-29T00:30:00.000-06:002011-12-29T00:30:02.690-06:00Calling generic methodsTo take advantage of some of the recent API goodness coming from Microsoft, interoperating with generic methods is a must. Here's an example from
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">System.Linq.Reactive.Observable</span>:
<br />
<br />
<pre class="brush: csharp">public static IObservable<TResult> Generate<TState, TResult>(
TState initialState, Func<TState, bool> condition,
Func<TState, TState> iterate,
Func<TState, TResult> resultSelector,
Func<TState, TimeSpan> timeSelector )
</pre>
<br />
and from the land of Linq, in
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">System.Linq.Enumerable</span>:
<br />
<br />
<pre class="brush: csharp">public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector,
Func<TKey, IEnumerable<TElement>, TResult> resultSelector,
IEqualityComparer<TKey> comparer )
</pre>
<br />
Much of the goodness of Linq, Reactive Framework and others comes from the ability to chain together generic method calls with minimum specification of type arguments for those calls. If you are in a statically-typed language such as C#, there are plenty of types floating around to do inferencing on. Of course, with <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">dynamic</span>, C# is not quite the paragon of static typing it once was. The mechanisms C# uses for dynamic call sites surface in the Dynamic Language Runtime and so are available to the wider world. Following the path blazed by IronPython, we have recently enhanced ClojureCLR's ability to interoperate with generic methods.
<br />
<br />
Start a REPL and start typing:
<br />
<br />
<pre class="brush: clojure">(import 'System.Linq.Enumerable)
(def r1 (Enumerable/Where [1 2 3 4 5] even?))
(seq r1) ;=> (2 4)
</pre>
<br />
"But of course", you say. Not so fast; under the covers there is merry mischief.
<br />
<br />
The generic method <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Where</span> is overloaded with the following signatures.
<br />
<br />
<pre class="brush: csharp">public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate)
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, int, bool> predicate)
</pre>
<br />
In the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Where</span> call above, the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">[1 2 3 4 5]</span> is a <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">clojure.lang.PersistentVector</span>. This class implements <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">IEnumerable<Object></span> and so matches the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">IEnumerable<TSource></span> in the first argument position.
<br />
<br />
The value of <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">even?</span> is a <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">clojure.lang.IFn</span>, more specifically a <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">clojure.lang.AFn</span>. In ClojureCLR, <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">clojure.lang.AFn</span> implements interfaces allowing it take take part in the DLR's generic method type inferencing protocol. One interface answers queries about the arities supported by the function. The function <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">even?</span> reports that it supports one argument and does not support two arguments. Therefore, it supports casting to <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Func<TSource, bool></span> but not to <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Func<TSource, int, bool></span>, allowing discrimination between the two overloads. (<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Func<TSource, bool></span> is a delegate class representing a method taking one argument of type <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">TSource </span>and returning a value of type <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Boolean</span>.)
<br />
<br />
From this information, we can pick the overload of <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Where</span> to use. The value returned by the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Where</span> call is of type <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">System.Linq.Enumerable+WhereEnumerableIterator<Object></span>. This type implements <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">IEnumerable</span> and <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">seq</span> can do the expected thing to it.
<br />
<br />
If we had a function f that supports one and two arguments, say
<br />
<br />
<pre class="brush: clojure">(defn f
([x] x)
([x y] [x y]))
</pre>
<br />
the type inferencing illustrated in the previous example would not work.
<br />
<br />
<pre class="brush: clojure">(Enumerable/Where [1 2 3 4 5] f) ;=> FAIL!
</pre>
The error messages is quite clear:
<br />
<br />
<pre>ArgumentTypeException Multiple targets could match:
Where(IEnumerable`1, Func`2),
Where(IEnumerable`1, Func`3)
</pre>
<br />
There are two ways around this. The simplest is to use an anonymous function of one argument that calls <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">f</span>:
<br />
<br />
<pre class="brush: clojure">(Enumerable/Where [1 2 3 4 5] #(f %1))
</pre>
<br />
The second way is to declare the types explicitly. Macros <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">sys-func</span> and <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">sys-action</span> are available to create a function with delegate type matching <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">System.Func<,...></span> and <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">System.Action<,...></span>, respectively.
<br />
<br />
<pre class="brush: clojure">(Enumerable/Where [1 2 3 4 5] (sys-func [Object Boolean] [x] (f x))))
</pre>
<br />
The first way clearly is preferable. However, when type inferencing does not suffice, <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">sys-func</span> and <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">sys-action</span> can be used. (If delegates of types other then <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Func<,...></span> and <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Action<,...></span> are required, <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">gen-delegate</span> is available.)
<br />
<br />
Not just Clojure data structures can participate as sources:
<br />
<br />
<pre class="brush: clojure">(def r2 (Enumerable/Range 1 10))
(seq r2) ;=> (1 2 3 4 5 6 7 8 9 10)
(seq (Enumerable/Where r2 even?)) ;=> (2 4 6 8 10)
</pre>
<br />
In fact, any of the following calls will work:
<br />
<br />
<pre class="brush: clojure">(Enumerable/Where r2 (sys-func [Int32 Boolean] [x] (even? x)))
(Enumerable/Where r2 (sys-func [Object Boolean] [x] (even? x)))
(Enumerable/Where (seq r2) even?)
</pre>
<br />
There are situations where you need to supply type arguments explicitly to a generic method. For example, the following fails:
<br />
<br />
<pre class="brush: clojure">(def r3 (Enumerable/Repeat 2 5) ;=> FAILS!
</pre>
<br />
The error message states:<br />
<br />
<pre>InvalidOperationException Late bound operations cannot be performed
on types or methods for which ContainsGenericParameters is true.
</pre>
<br />
We can cause the type arguments on the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Repeat<T></span> method to be filled in using the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">type-args</span> macro:
<br />
<br />
<pre class="brush: clojure">(def r3 (Enumerable/Repeat (type-args Int32) 2 5))
(seq r2) ;=> (2 2 2 2 2)
</pre>
<br />
If you'd like to do Linq-style method concatenation, don't forget the threading macro:
<br />
<br />
<pre class="brush: clojure">(seq (-> (Enumerable/Range 1 10)
(Enumerable/Where even?)
(Enumerable/Select #(* %1 %1)))) ;=> (4 16 36 64 100)
</pre>
<br />
Of course, if you'd like to have the Linq syntax that is available in C#, you are free to write a macro.David Millerhttp://www.blogger.com/profile/07657040519395296684noreply@blogger.com0tag:blogger.com,1999:blog-4262147391488425950.post-76589920183478590812011-12-27T03:00:00.000-06:002011-12-27T03:00:05.196-06:00Working with enums<div>
<br /></div>
Working with enum types is straightforward. We have provided a few core methods to simplify certain operations.<br />
<br />
<span class="Apple-style-span" style="font-size: large;">Accessing/creating enum values</span><br />
<br />
An enum type is a value type derived from <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">System.Enum</span>. The named constants in an enum type are implemented as static fields on the type. For example, <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">System.IO.FileMode</span>, defined in C# as<br />
<br />
<pre class="brush: csharp">public enum FileMode
{
Append = 6,
Create = 2,
CreateNew = 1,
Open = 3,
OpenOrCreate = 4,
Truncate = 5
}
</pre>
<br />
has an MSIL implementation more-or-less equivalent to
<br />
<br />
<pre class="brush:csharp">[Serializable]
public sealed class FileMode : System.Enum
{
public static System.IO.FileMode CreateNew = 1;
public static System.IO.FileMode Create = 2;
public static System.IO.FileMode Open = 3;
public static System.IO.FileMode OpenOrCreate 4;
public static System.IO.FileMode Truncate = 5;
public static System.IO.FileMode Append = 6;
}
</pre>
<br />
Thus, we can use our regular static-field access interop syntax to retrieve these values:
<br />
<br />
<pre class="brush: clojure">(import 'System.IO.FileMode) ;=> System.IO.FileMode
FileMode/CreateNew ;=> CreateNew
</pre>
<br />
These are not integral-type values. They retain the enumeration type.<br />
<br />
<pre class="brush: clojure">(class FileMode/CreateNew) ;=> System.IO.FileMode
</pre>
<br />
You can convert them to an integer value if you desire:
<br />
<br />
<pre class="brush: clojure">(int FileMode/CreateNew) ;=> 1
</pre>
<br />
If you want to convert from an integer value to an enumeration value, try:<br />
<br />
<pre class="brush:clojure">(Enum/ToObject FileMode 4) ;=> OpenOrCreate
</pre>
<br />
If you want convert from the name of an integer to an enumeration value, the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">enum-val</span> method will work with strings or anything that <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">name</span> works on:<br />
<br />
<pre class="brush:clojure">(enum-val FileMode "CreateNew") ;=> CreateNew
(enum-val FileMode :CreateNew) ;=> CreateNew
</pre>
<br />
<br />
<span class="Apple-style-span" style="font-size: large;">Working with bit fields</span><br />
<br />
Enumeration types that have the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Flags</span> attribute are often used to represent bit fields. For convenience, we provide methods <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">bit-or</span> and <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">bit-and</span> to to combine and mask bit field values. For example, <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">System.IO.FileShare</span> has the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">Flags</span> attribute. It is defined as follows:
<br />
<br />
<pre class="brush: csharp">[Serializable, ComVisible(true), Flags]
public enum FileShare
{
Delete = 4,
Inheritable = 0x10,
None = 0,
Read = 1,
ReadWrite = 3,
Write = 2
}
</pre>
<br />
Use <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">enum-or</span> to combine values.
<br />
<br />
<pre class="brush:clojure">(import 'System.IO.FileShare)
(enum-or FileShare/Read FileShare/Write) ;=> ReadWrite
</pre>
<br />
Use <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">enum-and</span> to mask values.
<br />
<br />
<pre class="brush:clojure">(def r (enum-or FileShare/ReadWrite FileShare/Inheritable))
(= (enum-and r FileShare/Write) FileShare/Write) ;=> true
(= (enum-and r FileShare/Write) FileShare/None) ;=> false
(= (enum-and r FileShare/Delete) FileShare/None) ;=> true
</pre>
<br />
<br />
You can also use the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">HasFlag</span> method to test if a bit is set:
<br />
<br />
<pre class="brush:clojure">(.HasFlag r FileShare/Write) ;=> true
(.HasFlag r FileShare/Delete) ;=> false
</pre>
<br />
<br />David Millerhttp://www.blogger.com/profile/07657040519395296684noreply@blogger.com0tag:blogger.com,1999:blog-4262147391488425950.post-20973311070359587702011-12-26T00:00:00.000-06:002011-12-26T05:39:32.863-06:00Using ngen to improve ClojureCLR startup timeStartup speed ranked fairly low in importance in the 2011 ClojureCLR survey. Still, it can be annoying and is an impediment to certain uses of ClojureCLR.<br />
<br />
I've used several profiling tools to examine the startup period. The only conclusion I've been able to draw: JIT-compilation is the culprit. The percentage of startup time devoted to JITting is in excess of 90%. One solution to this: pre-JIT.<br />
<br />
If you run ngen.exe on the primary DLLs involved in ClojureCLR startup, you will experience significant startup time improvement. I ran<br />
<br />
<blockquote class="tr_bq">
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">time ./Clojure.Main.exe -e "(println :a)"</span></blockquote>
<br />
on a 4.0 Debug build, on a 4.0 Release build, and on a 4.0 Release build with ngen. For comparison, I also ran<br />
<blockquote class="tr_bq">
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"> time java -jar clojure.jar -e "(println :a)"</span></blockquote>
(I used my git-bash shell via msysgit, so time was available via mingw.)<br />
<br />
Results:<br />
<br />
<table border="1" style="text-align: center;">
<tbody>
<tr><th></th><th>Debug</th><th>Release</th><th>Release / ngen</th><th>JVM</th></tr>
<tr><th>real</th><td><div style="text-align: center;">
0m5.118s</div>
</td><td><div style="text-align: center;">
0m8.130s</div>
</td><td><div style="text-align: center;">
0m0.231s</div>
</td><td><div style="text-align: center;">
0m1.053s</div>
</td></tr>
<tr><th>user</th><td><div style="text-align: center;">
0m0.000s</div>
</td><td><div style="text-align: center;">
0m0.015s</div>
</td><td><div style="text-align: center;">
0m0.000s</div>
</td><td><div style="text-align: center;">
0m0.000s</div>
</td></tr>
<tr><th>sys</th><td><div style="text-align: center;">
0m0.000s</div>
</td><td><div style="text-align: center;">
0m0.000s</div>
</td><td><div style="text-align: center;">
0m0.015s</div>
</td><td><div style="text-align: center;">
0m0.000s</div>
</td></tr>
</tbody></table>
<div style="text-align: center;">
<br /></div>
The slower startup time of Debug vs non-ngen'd Release is no doubt due to the more extensive JIT optimizations taking place in the latter. Approximately four times as fast as the JVM version is good enough for me.<br />
<br />
I did the following ngens. All these DLLs are loaded on an intial startup through one eval and printing. <br />
<br />
<blockquote class="tr_bq">
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">ngen install Clojure.dll<br />ngen install clojure.clr.io.clj.dll<br />ngen install clojure.core.clj.dll<br />ngen install clojure.core.protocols.clj.dll<br />ngen install clojure.core_clr.clj.dll<br />ngen install clojure.core_deftype.clj.dll<br />ngen install clojure.core_print.clj.dll<br />ngen install clojure.core_proxy.clj.dll<br />ngen install clojure.genclass.clj.dll<br />ngen install clojure.gvec.clj.dll<br />ngen install clojure.main.clj.dll<br />ngen install clojure.pprint.cl_format.clj.dll<br />ngen install clojure.pprint.clj.dll<br />ngen install clojure.pprint.column_writer.clj.dll<br />ngen install clojure.pprint.dispatch.clj.dll<br />ngen install clojure.pprint.pprint_base.clj.dll<br />ngen install clojure.pprint.pretty_writer.clj.dll<br />ngen install clojure.pprint.print_table.clj.dll<br />ngen install clojure.pprint.utilities.clj.dll<br />ngen install clojure.repl.clj.dll<br />ngen install clojure.walk.clj.dll</span></blockquote>
<br />
<div>
<div>
You will get errors, mostly of the form</div>
<blockquote class="tr_bq">
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">1>Common Language Runtime detected an invalid program. </span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">while compiling method </span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">cl</span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">ojure/walk$macroexpand_all$fn__12034__12039..ctor</span></blockquote>
</div>
<br />
It works nevertheless. Someday I'll have to figure out exactly what sin I'm committing in my constructor code.<br />
<br />
I cannot competently hypothesize why ClojureCLR kills the JITter like this, in comparison to the JVM, or in comparison to other similar sized programs. Delayed JITting may be one reason. Also, the generated ClojureCLR code contains twice as many classes as the JVM code does, due to the tactic I use to workaround the inability of the DLR to generate instance methods. <br />
<br />
<br />David Millerhttp://www.blogger.com/profile/07657040519395296684noreply@blogger.com9tag:blogger.com,1999:blog-4262147391488425950.post-7350040938722051132011-12-24T18:00:00.000-06:002011-12-26T00:23:58.827-06:00ClojureCLR has a new homeThe <a href="http://clojureclr.blogspot.com/2011/11/survey-says-call-to-action.html">survey action items</a> had as item #1 the following:<br />
<blockquote class="tr_bq">
<b style="background-color: white; color: #444444; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px;"><span class="Apple-style-span" style="font-weight: normal;"><b>Action item:</b></span></b> <span class="Apple-style-span" style="background-color: white; color: #444444; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px;">Ask Rich Hickey and Clojure/core to clarify their position and/or plans re ClojureCLR.</span></blockquote>
You can refer to the <a href="http://clojureclr.blogspot.com/2011/11/survey-says-viability-is-number-one.html">post on viability</a> to to get a better sense of what responders were looking for.<br />
<br />
As a result of a discussions with <i>core</i>, ClojureCLR has moved to a better neighborhood. The repo has moved under the clojure group at github:<br />
<blockquote class="tr_bq">
<a href="https://github.com/clojure/clojure-clr">https://github.com/clojure/clojure-clr</a></blockquote>
joining the mainline Clojure project, ClojureScript and the contrib libs. <br />
<br />
ClojureCLR is now an official project under dev.clojure.org:<br />
<blockquote class="tr_bq">
<a href="http://dev.clojure.org/jira/browse/CLJCLR">http://dev.clojure.org/jira/browse/CLJCLR</a></blockquote>
Issues will be managed through this site. We will continue to maintain <a href="http://clojure.org/contributing">RHCAH: Rich Hickey Contributor Agreement Hygiene</a>. Please have a CA on file with Rich before submitting patches.<br />
<br />
I've used the move as an opportunity to rewrite and reorganize <a href="https://github.com/clojure/clojure-clr/wiki">the wiki pages</a>. I'll be posting entries here on some of the newest material, such as the improved support for generic method interop. <br />
<br />
This (much appreciated) token of <i>core</i>'s regard is likely to be the extent of official support for ClojureCLR for the time being. <i>Core</i> does not have sufficient resources for more aggressive stewardship of the project. <br />
<br />
The answer to the action item: ClojureCLR is a community-supported project. If you are interested in the long-term success of Clojure on the CLR, roll up your sleeves. <br />
<span style="color: #444444; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: x-small;"><span style="line-height: 18px;"><br /></span></span><br />
<br />
<br />
<blockquote class="tr_bq">
</blockquote>
<br />
<br />David Millerhttp://www.blogger.com/profile/07657040519395296684noreply@blogger.com0tag:blogger.com,1999:blog-4262147391488425950.post-53139302726395478602011-11-03T12:26:00.003-05:002011-11-03T12:26:32.952-05:00Survey says: be eco-friendlyI included a number of questions on the survey that related to the environment. For code development, that is. I had in mind two development scenarios:<br />
<br />
<br />
<ol>
<li>"Pure" clojure development: these are projects that are Clojure-centric. This could be a simple port of Clojure project to the CLR, or any Clojure project where Visual Studio support is not critical, i.e., not involving co-development of C# code or the use of big frameworks such as ASP.NET. Such projects could easily be developed using the same tools as JVM Clojure developers. I used Leiningen and Emacs as examples for project management and source editing.</li>
<li>Clojure projects where Visual Studio capabilities might be crucial, such as ASP.NET or WPF projects, or just heavy development of C# and Clojure code together.</li>
</ol>
<br />
Leiningen/Emacs support dominated Visual Studio integration, NuGet, etc.<br />
<br />
In the frustrations/deterrents section:<br />
<br />
#8 -- Availability of Clojure-CLR targeted editors/dev environments<br />
#10 -- Lack of integration with Visual Studio<br />
<br />
In the desirability section:<br />
<br />
#3 -- Leiningen support for 'pure' ClojureCLR projects<br />
#6 -- Emacs support for 'pure' ClojureCLR projects<br />
#7 -- Visual Studio integration<br />
#8 -- NuGet distribution<br />
<br />
Even Mono got higher ranking or more mention than VS. However, some mentioned that lack of VS integration has been a show-stopper.<br />
<br />
<blockquote class="tr_bq">
<b>Action item: </b>Develop a version of Leiningen supporting ClojureCLR projects (nlein?) </blockquote>
<blockquote class="tr_bq">
<b>Action item: </b>Develop a NuGet distribution for ClojureCLR, and perhaps ported contrib libs</blockquote>
<blockquote class="tr_bq">
<b>Action item: </b>Develop Emacs support for ClojureCLR</blockquote>
<blockquote class="tr_bq">
<b>Action item: </b>Improve VS integration (vsClojure?)</blockquote>
<br />
I'm fairly comfortable taking a look at creating an 'nlein' and working NuGet distributions (though others should feel free to step in). However, I have no interest in IDE development, whether hacking Emacs or developing VS plug-ins. Others are going to have to lead those efforts.<br />
<br />
Mono compatibility probably has been the most frequent question on the Clojure ML and on IRC. It seems to matter to an important subset of potential users. I've not wanted to deal with yet another development environment. I hope someone will step up to this one before I have to.<br />
<blockquote class="tr_bq">
<b>Action item: </b>Investigate Mono compatibility</blockquote>
<br />David Millerhttp://www.blogger.com/profile/07657040519395296684noreply@blogger.com0tag:blogger.com,1999:blog-4262147391488425950.post-62403180021331755232011-11-03T12:26:00.002-05:002011-11-03T12:26:27.652-05:00Survey says: interoperateOne thread running through the survey had to do with interoperability and the specifics of working with Microsoft frameworks.<br />
<br />
"Availability of ClojureCLR-specific documentation" was fourth on the list of frustrations. "Interop support" was sixth. Under desirability, "Sample framework interop code" was #2 and "Wrappers for MS libraries/frameworks" was # 5.<br />
<br />
Related comments include:<br />
<ul>
<li>In general the lack of examples of typical uses, something which is pretty well covered in the JVM based Clo[j]ure, things like jetty/ring, jdbc, and GUI (which tends to be a lot more important in the windows world).</li>
<li>Support for .net generics is extremely important! Lack of [this and another] features were the show stoppers for me. </li>
<li>Writing my libs in Clojure.CLR and using them in ASP.NET apps.</li>
<li>anything that makes interop between ClojureCLR and existing CLR languages easier/seamless has my vote.</li>
<li>interop with C#</li>
</ul>
The survey asked respondents to indicate MS frameworks of interest. Those receiving more than one vote:<br />
<br />
<table>
<tbody>
<tr><td>Linq </td><td>26</td><td> 59%</td></tr>
<tr><td>ASP.NET / MVC</td><td>20</td><td> 45%</td></tr>
<tr><td>Reactive Framework</td><td>15</td><td> 34%</td></tr>
<tr><td>WPF</td><td>13</td><td> 30%</td></tr>
<tr><td>Windows Runtime (Win8) </td><td>10</td><td> 23%</td></tr>
<tr><td>WinForms</td><td> 9</td><td> 20%</td></tr>
<tr><td>XNA (incl. XBox)</td><td> 9</td><td> 20%</td></tr>
<tr><td>Silverlight </td><td> 7</td><td> 16%</td></tr>
<tr><td>WCF </td><td> 7</td><td> 16%</td></tr>
<tr><td>Azure </td><td> 7</td><td> 16%</td></tr>
<tr><td>Entity Framework</td><td> 5</td><td> 11%</td></tr>
<tr><td>Robotics Studio</td><td> 5</td><td> 11%</td></tr>
<tr><td>Sharepoint </td><td> 3</td><td> 7%</td></tr>
<tr><td></td><td></td><td></td></tr>
</tbody></table>
<br />
<div>
Linq's #1 status surprised me. I think of Linq as providing a functional approach to accessing sequential data, and Clojure is ... that. However, my use of Linq to date is minimal--implementing ClojureCLR does not stretch that muscle. Perhaps people want to write Linq extensions in Clojure for use in C#? Perhaps some could comment on this.</div>
<div>
<br /></div>
<blockquote class="tr_bq">
<b>Question for you: </b> What form of Linq interop is desired? </blockquote>
<div>
<br /></div>
<div>
The next several entries--ASP.NET/MVC, Rx, WPF--did not surprise me. Reading it just now, I realized that I left out the TPL (Task Parallel Library). I wonder where that would have ranked.</div>
<div>
<br /></div>
<div>
I tossed in Windows Runtime (WinRT from Win8) for fun. Its high rank was a surprise. </div>
<blockquote class="tr_bq">
<b>Question for you: </b>How are you planning to use ClojureCLR with WinRT?</blockquote>
Steps suggested by the data:<br />
<blockquote class="tr_bq">
<b>Action item:</b> Provide better documentation and examples for interop at the class/method level, particularly for things not in the Java world, such as true generic classes and methods, by-ref parameters, etc.</blockquote>
<blockquote class="tr_bq">
<b>Action item: </b>Provide tutorial examples of interop with key MS frameworks: Linq, ASP.NET/MVC, Reactive Framework, WPF, TPL.</blockquote>
The situation regarding wrappers for MS libraries and frameworks is less clear to me. You can't 'wrap' ASP.NET. Calling out to ClojureCLR code from ASP.NET seems more likely. Interop from C# back to ClojureCLR is the real problem here (probably). I can imagine wrappers for smaller things such as Rx, TPL, etc.<br />
<blockquote class="tr_bq">
<b>Action item:</b> Provide tutorial examples of C# calling back into ClojureCLR.</blockquote>
<blockquote class="tr_bq">
<b>Action item: </b>Identify smaller libraries that would benefit from wrappers and implement same. </blockquote>
<br />David Millerhttp://www.blogger.com/profile/07657040519395296684noreply@blogger.com2tag:blogger.com,1999:blog-4262147391488425950.post-70890048869319186952011-11-03T12:26:00.001-05:002011-11-03T12:26:18.632-05:00Survey says: port those libs<br />
<br />
<b>Clojure/contrib lib ports</b><br />
<br />
I suspected this would be high on the list, but hitting #3 was a surprise. This was one community task I thought people might get drawn to first. For the most part, it's not that hard to do, and there are significant examples: all the files such as clojure/core.clj, gvec.clj, and xml.clj in the main ClojureCLR distribution are ported libs. However, as one comment stated:<br />
<blockquote class="tr_bq">
I haven't even really seen anything in terms of guidance / best practices to allow this work to be carried forward by others in a consistent manner.</blockquote>
Okay, here it is:<br />
<blockquote class="tr_bq">
Replace interop calls to Java methods with interop calls to CLR methods.</blockquote>
That covers most of it. I've managed to keep the port of clojure/core.clj to inline changes across almost 6000 lines of code. However, more accessible examples might be useful.<br />
<blockquote class="tr_bq">
<b>Action item:</b> Provide ports of key libs to 'prime the pump'.</blockquote>
<blockquote class="tr_bq">
<b>Action item:</b> Illustrate the porting process and provide more detailed guidelines in a future post.</blockquote>
<div>
The ongoing reorganization of the contrib libs will be big help in moving this forward. It makes the mass of clojure/contrib more modular and gives clues to what are viable libraries.</div>
<div>
<br /></div>
<div>
The biggest problem is not the effort to port but how to manage the code when done. Ideally, the libs would contain JVM and CLR versions in one code base. There are ways to write *.clj code that would lessen the burden of porting. However, I don't see contrib lib authors taking on that burden. And the mind-set is not there from the top: Rich has been very clear on two points: there will be no conditionalized read mechanism; and that Clojure code involving interop is never intended to be portable.</div>
<div>
<br /></div>
<div>
So, at the moment, it appears that parallel projects, with 90% duplicate code, is the only option. Duplication carries the burden of maintaining consistency. </div>
<div>
<blockquote class="tr_bq">
<b>Action item:</b> Find a way to manage maintenance of ported libs.</blockquote>
</div>
<div>
Which contrib libs should be done first?</div>David Millerhttp://www.blogger.com/profile/07657040519395296684noreply@blogger.com0tag:blogger.com,1999:blog-4262147391488425950.post-70429499893666209252011-11-03T12:26:00.000-05:002011-11-03T12:26:03.259-05:00Survey says: we need community<br />
<br />
<div>
I think one respondent captured the problem quite well:</div>
<blockquote class="tr_bq">
I would need to see signs of momentum: users downloading it and asking questions, reporting bugs, asking for features and chipping in, writing the odd .NET wrapper here and there, complaining about and contributing tooling, and talking/blogging about how they hope to use it, strengths and weaknesses, why it's viable, etc.</blockquote>
Yeah. Me, too.<br />
<br />
Community building takes effort. In the beginning, I hoped that if I just took care of questions coming up on the mailing list, the rest would develop with a few hardy individuals starting to contribute. I didn't (and still don't) have time to hang on IRC. I was usually behind bringing ClojureCLR up-to-date with Clojure and felt that the best thing was for ClojureCLR to be as close to feature-complete as I could make it. Hence, I neglected the community building.<br />
<br />
I asked two questions on the survey about specific community activities:<br />
<ul>
<li>Separate ClojureCLR forum/mailing list </li>
<li>Blog or other forum for articles and commentary </li>
</ul>
<div>
Twenty of 53 respondents checked the ML question; 29 of 53 indicated a blog or similar is desired.</div>
<blockquote class="tr_bq">
<b>Action item:</b> Now that there is blog (here!), use it to inform and educate the community.</blockquote>
The comments on the survey give some ideas on what would be useful: best practices, examples of interop, progress reports, roadmaps, etc. <br />
<br />
<blockquote class="tr_bq">
Please use the comments to give input on what you'd like to see.</blockquote>
<br />
Several people had suggested prior to the survey that people primarily interested in CLR might be put off by the high volume of irrelevant traffic on the Clojure ML. So I put in the question on forming a separate ML for ClojureCLR. I hesitate to create a mailing list at this time. Nothing says "not viable" like a mailing list that has no activity. Is this something that should wait until there is more of a community need?<br />
<blockquote class="tr_bq">
I'd love to hear what others think will be effective in building the ClojureCLR community.</blockquote>David Millerhttp://www.blogger.com/profile/07657040519395296684noreply@blogger.com0tag:blogger.com,1999:blog-4262147391488425950.post-72592538488004198472011-11-03T12:25:00.001-05:002011-11-03T12:25:54.684-05:00Survey says: viability is number one<br />
<div>
I'm not surprised viability is the #1 concern. This concen boils down to:</div>
<div>
<ol>
<li>ClojureCLR has no official status.</li>
<li>ClojureCLR has no community.</li>
</ol>
<div>
ClojureCLR is obviously pretty much a one-person operation. The project's relationship to the overall Clojure effort is not clear. There is one mention on the home page of <a href="http://clojure.org/">clojure.org</a>. If you search for 'CLR' on <a href="http://dev.clojure.org/">dev.clojure.org</a>, you will get three hits: one for an article stub for installing on CLR/VS (I didn't know that existed until just now); one mention as a possible backend for CinC; and a mention on the JIRA workflow page. Since the JIRA workflow sends all requests through Clojure/core members that bring us back to the 'no official status': Clojure/core does not appear to acknowledge the existence of ClojureCLR. </div>
<div>
<br /></div>
<div>
For some, the lack of official status is enough by itself to preclude any use of ClojureCLR. The comments for "what do you need to see to improve confidence [in viability]" include:</div>
<ul>
<li>Visible support and contributions from Clojure brass would go a long way to showing viability as well.</li>
<li>I need Rich Hickey and clojure/core to give the utmost "seal of approval" that ClojureCLR is 100% feature complete for a given version of Clojure proper. To a degree (i.e. for my boss), ClojureCLR needs to be released BY clojure/core and will not be considered until it is.</li>
<li>A dedicated core community that is focused exclusively on the CLR (probably precludes any existing Clojure/dev or Clojure/core people?).</li>
<li>CLR should be taking as seriously as JS or JVM targets by Rich and his entourage.</li>
<li>real endorsement from people at Clojure head</li>
</ul>
<div>
Out-of-band, I've received additional comments that the absence of ClojureCLR from dev.clojure.org and the fact that the ClojureCLR repo did not move from <a href="http://github.com/richhickey">github.com/richhickey</a> to <a href="http://github.com/clojure">github.com/clojure</a> along with Clojure and the contribs (and now also ClojureScript) are at least highly suspect.</div>
</div>
<div>
<br /></div>
<div>
There's not much I can do about this concern, except to:</div>
<blockquote class="tr_bq">
<b>Action item:</b> Ask Rich Hickey and Clojure/core to clarify their position and/or plans re ClojureCLR.</blockquote>
<div>
The answer to this question could affect the other actions items, but I won't second-guess that.</div>
<div>
<br /></div>
<div>
As for (2), community, that deserves its own post.</div>
<div>
<br /></div>David Millerhttp://www.blogger.com/profile/07657040519395296684noreply@blogger.com0tag:blogger.com,1999:blog-4262147391488425950.post-85891024573883079352011-11-03T12:25:00.000-05:002011-11-03T12:28:32.884-05:00Survey says: a call to actionI created the <a href="http://clojureclr.blogspot.com/2011/10/2011-clojureclr-survey-is-open.html">2011 ClojureCLR Survey </a>to get some guidance on moving ClojureCLR forward. The<a href="http://clojureclr.blogspot.com/2011/11/results-of-2011-clojureclr-survey.html"> survey results</a> give pretty clear indication of what needs to be worked on to move ClojureCLR forward.<br />
<div>
<br /></div>
<div>
The writeup is a bit long. So that the whole thing is not just "tl;dr" for the masses, I'll split it into multiple posts.</div>
<div>
<br /></div>
<div>
Spoiler alert: Here are all the action items suggested in the various posts.</div>
<div>
<br /></div>
<div>
<b><a href="http://clojureclr.blogspot.com/2011/11/survey-says-viability-is-number-one.html">Viability</a></b></div>
<blockquote class="tr_bq">
<b><span class="Apple-style-span" style="font-weight: normal;"><b>Action item:</b></span> </b>Ask Rich Hickey and Clojure/core to clarify their position and/or plans re ClojureCLR.</blockquote>
<div>
<br /></div>
<div>
<b><a href="http://clojureclr.blogspot.com/2011/11/survey-says-we-need-community.html">Community</a></b></div>
<blockquote class="tr_bq">
<b>Action item:</b> Now that there is blog (here!), use it to inform and educate the community.</blockquote>
<br />
<b><a href="http://clojureclr.blogspot.com/2011/11/survey-says-port-those-libs.html">Clojure/contrib lib ports </a></b><br />
<div>
<blockquote class="tr_bq">
<b>Action item:</b> Provide ports of key libs to 'prime the pump'.</blockquote>
<blockquote class="tr_bq">
<b>Action item:</b> Illustrate the porting process and provide more detailed guidelines.</blockquote>
</div>
<div>
<div>
<blockquote class="tr_bq">
<b>Action item:</b> Find a way to manage maintenance of ported libs.</blockquote>
</div>
<div>
<br /></div>
<div>
<b><a href="http://clojureclr.blogspot.com/2011/11/survey-says-interoperate.html">Interoperability</a></b></div>
<div>
<b></b><br />
<blockquote class="tr_bq" style="font-weight: normal;">
<b><b>Action item:</b> Provide better documentation and examples for interop at the class/method level, particularly for things not in the Java world, such as true generic classes and methods, by-ref parameters, etc.</b></blockquote>
<b>
<blockquote class="tr_bq" style="font-weight: normal;">
<b>Action item: </b>Provide tutorial examples of interop with key MS frameworks: Linq, ASP.NET/MVC, Reactive Framework, WPF, TPL.</blockquote>
<blockquote class="tr_bq" style="font-weight: normal;">
<b>Action item:</b> Provide tutorial examples of C# calling back into ClojureCLR. </blockquote>
</b><br />
<blockquote class="tr_bq">
<b>Action item: </b>Identify smaller libraries that would benefit from wrappers and implement same. </blockquote>
<br />
<b><a href="http://clojureclr.blogspot.com/2011/11/survey-says-be-eco-friendly.html">Ecosystem </a></b></div>
<div>
<blockquote class="tr_bq">
<b>Action item: </b>Develop a version of Leiningen supporting ClojureCLR projects (nlein?) </blockquote>
<blockquote class="tr_bq">
<b>Action item: </b>Develop a NuGet distribution for ClojureCLR, and perhaps ported contrib libs</blockquote>
<blockquote class="tr_bq">
<b>Action item: </b>Develop Emacs support for ClojureCLR</blockquote>
<blockquote class="tr_bq">
<b>Action item: </b>Improve VS integration (vsClojure?)</blockquote>
<blockquote class="tr_bq">
<b>Action item: </b>Investigate Mono compatibility </blockquote>
</div>
<div>
<br /></div>
<div>
Does this look like a reasonable agenda for the immediate future of ClojureCLR development. The lines are open and agents are standing by to take your call.</div>
<div>
<br /></div>
<div>
<br /></div>
<br />
<br /></div>David Millerhttp://www.blogger.com/profile/07657040519395296684noreply@blogger.com1tag:blogger.com,1999:blog-4262147391488425950.post-59346068142597269402011-11-01T15:08:00.001-05:002011-11-03T09:53:14.604-05:00Results of the 2011 ClojureCLR SurveyThe <a href="http://clojureclr.blogspot.com/2011/10/2011-clojureclr-survey-is-open.html">2011 ClojureCLR Survey</a> concluded last night. Inspired by Chas Emerick's State of Clojure Surveys (<a href="http://cemerick.com/2010/06/07/results-from-the-state-of-clojure-summer-2010-survey/">2010</a>, <a href="http://cemerick.com/2011/07/11/results-of-the-2011-state-of-clojure-survey/">2011</a>), the survey was an attempt to get feedback from those interested in ClojureCLR regarding usage, problems, needs and desires, in the hope of setting the direction for ClojureCLR development.<br />
<br />
The survey responses are summarized below. I will provide my analysis in a later posting.<br />
<br />
The survey was announced by three posts to the <a href="http://groups.google.com/group/clojure">Clojure mailing list</a> and two tweets from my Twitter account. Since I had never tweeted before (I may be anti-social), I made sure a few select people were following so that there would be minimum of retweeting.<br />
<br />
There were 53 responses to the survey. This number is 8% of the 670 responses to the 2011 State of Clojure survey. For comparison, the ClojureCLR repo has 29% the number of watchers of the Clojure repo. There is no way to know how representative this sample in the universe of Clojure folk.<br />
<br />
Make of this what you will: Given ten days to respond, 36% of the responses came on the last day of the survey. :)<br />
<br />
The first two questions on the survey were an attempt to judge the respondent's past and present engagement with ClojureCLR.<br />
<br />
<br />
<span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"><b>What is your level of experience with ClojureCLR?</b></span><br />
<br />
<img src="https://chart.googleapis.com/chart?cht=bhs&chs=345x180&chbh=24%2C6&chco=2121e4%7C0000e0%7C4242e8%7C6363ec%7C8585f0&chxt=x%2Cy&chxl=0%3A%7C0%7C5%7C10%7C15%7C20%7C25%7C30%7C1%3A%7CRaising%20a%20family%7CEntertaining%20thou...%7CHanging%20out%7CDated%20a%20few%20times%7CNever%20met&chxs=0%2C000000%2C12%2C0%2Clt%7C1%2C000000%2C12%2C1%2Clt&chds=0%2C30&chd=t%3A27%2C21%2C2%2C2%2C1" /><br />
<br />
<span class="Apple-style-span" style="background-color: white; font-family: arial, sans-serif; font-size: 12px;"></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">27 (51%) -- Never met <br />21 (40%) -- Dated a few times <br /> 2 ( 4%) -- Hanging out <br /> 2 ( 4%) -- Entertaining thoughts about a future together<br /> 1 ( 2%) -- Raising a family</span>The majority of respondents have never used ClojureCLR. Just 9% have used it more than a few times.<br />
<br />
<b><span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"><br />How would you characterize your use of ClojureCLR today?</span></b><span class="Apple-style-span" style="background-color: white; font-family: arial, sans-serif; font-size: 12px; font-weight: bold;"> </span><img src="https://chart.googleapis.com/chart?cht=bhs&chs=345x180&chbh=24%2C6&chco=ff9900%7Cffa621%7Cffb442%7Cffc163%7Cffce85&chxt=x%2Cy&chxl=0%3A%7C0%7C5%7C10%7C15%7C20%7C25%7C30%7C1%3A%7CI%20use%20it%20at%20work.%7CI%20use%20it%20for%20seri...%7CI'm%20just%20tinkering.%7CI%20tried%20it%2C%20gave%20...%7CReally%2C%20I've%20neve...&chxs=0%2C000000%2C12%2C0%2Clt%7C1%2C000000%2C12%2C1%2Clt&chds=0%2C30&chd=t%3A27%2C16%2C8%2C2%2C0" /><br />
<br />
<span class="Apple-style-span" style="background-color: white; font-family: arial, sans-serif; font-size: 12px;"></span><br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">27 (51%) -- Really, I've never touched it. <br />16 (30%) -- I tried it, gave it up.<br /> 8 (15%) -- I'm just tinkering.<br /> 2 ( 4%) -- I use it for serious "hobby" projects.<br /> 0 ( 0%) -- I use it at work. </span><br />
<br />
"Never met" was almost perfectly correlated with "Really, I've never touched it", as it should be. "Dated a few times" was unfortunately mostly paired with "I tried it, gave it up". (Some of the other pairings suggest I should have been less cute with the labels.)<br />
<br />
<table border="1">
<tbody>
<tr>
<th></th>
<th>Never<br />
touched</th>
<th>Tried it<br />
gave it up</th>
<th>Tinkering</th>
<th>Serious<br />
"hobby"</th>
<th>Work</th>
</tr>
<tr><th>Never met</th><td><div style="text-align: center;">
25</div>
</td><td><div style="text-align: center;">
1</div>
</td><td><div style="text-align: center;">
1</div>
</td><td style="text-align: center;"></td><td style="text-align: center;"></td></tr>
<tr><th>Dated a few times</th><td><div style="text-align: center;">
1</div>
</td><td><div style="text-align: center;">
15</div>
</td><td><div style="text-align: center;">
5</div>
</td><td style="text-align: center;"></td><td style="text-align: center;"></td></tr>
<tr><th>Hanging out</th><td style="text-align: center;"></td><td style="text-align: center;"></td><td><div style="text-align: center;">
1</div>
</td><td><div style="text-align: center;">
1</div>
</td><td style="text-align: center;"></td></tr>
<tr><th>Thoughts of a<br />
future together</th><td style="text-align: center;"></td><td style="text-align: center;"></td><td><div style="text-align: center;">
1</div>
</td><td><div style="text-align: center;">
1</div>
</td><td style="text-align: center;"></td></tr>
<tr><th>Raising a family</th><td><div style="text-align: center;">
1</div>
</td><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td><td style="text-align: center;"></td></tr>
</tbody></table>
<br />
<div>
At any rate, it is clear that the level of involvement is very low overall.</div>
<div>
<br /></div>
<br />
<b><span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;">Which of the following apply to your Microsoft development experience?</span></b><br />
<span class="Apple-style-span" style="background-color: white; font-family: arial, sans-serif; font-size: 12px; font-weight: bold;"><img src="https://chart.googleapis.com/chart?cht=bhs&chs=345x240&chbh=24%2C6&chco=e15f5f%7Cd41818%7Cd00000%7Cdd4747%7Cd92f2f%7Cea8e8e%7Ce67676&chxt=x%2Cy&chxl=0%3A%7C0%7C5%7C10%7C15%7C20%7C25%7C30%7C1%3A%7CMy%20workplace%20woul...%7CMy%20workplace%20perm...%7CMy%20workplace%20allo...%7CMy%20workplace%20does...%7CI%20have%20tried%20othe...%7CI%20presently%20devel...%7CI%20presently%20devel...&chxs=0%2C000000%2C12%2C0%2Clt%7C1%2C000000%2C12%2C1%2Clt&chds=0%2C30&chd=t%3A14%2C27%2C26%2C15%2C16%2C8%2C8" /></span><br />
<div>
<span class="Apple-style-span" style="background-color: white; font-family: arial, sans-serif; font-size: 12px; font-weight: bold;"><br /></span></div>
<br />
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">14 (27%) -- I presently develop on the .Net platform for non-work projects. <br />27 (52%) -- I presently develop on the .Net platform at work.<br />26 (50%) -- I have tried other non-Microsoft languages targeting the .Net platform.<br />15 (29%) -- My workplace does not use the .Net platform.<br />16 (31%) -- My workplace allows non-Microsoft languages targeting the .Net platform.<br /> 8 (15%) -- My workplace permits ClojureCLR for development.<br /> 8 (15%) -- My workplace would never permit ClojureCLR for development. </span><br />
<br />
<br />
<b><span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;">What has been most frustrating for you in your use of ClojureCLR or kept you from using it (more or at all)? (Over and above general Clojure issues.)</span></b><br />
<div>
<br />
This question asked the respondent to rank each of a set of categories on a 1-5 scale of importance.</div>
<div>
<br /></div>
<table border="1">
<tbody>
<tr><th></th><th>Not imp.<br />
1</th><th><br />
2</th><th><br />
3</th><th><br />
4</th><th>Very imp.<br />
5</th></tr>
<tr><th>Availability of ClojureCLR-specifc documentation</th><td><div style="text-align: center;">
5</div>
</td><td><div style="text-align: center;">
8</div>
</td><td><div style="text-align: center;">
11</div>
</td><td><div style="text-align: center;">
8</div>
</td><td><div style="text-align: center;">
13</div>
</td></tr>
<tr><th>ClojureCLR's install process</th><td><div style="text-align: center;">
8</div>
</td><td><div style="text-align: center;">
4</div>
</td><td><div style="text-align: center;">
12</div>
</td><td><div style="text-align: center;">
7</div>
</td><td><div style="text-align: center;">
12</div>
</td></tr>
<tr><th>Difficulty deploying completed applications</th><td><div style="text-align: center;">
11</div>
</td><td><div style="text-align: center;">
8</div>
</td><td><div style="text-align: center;">
12</div>
</td><td><div style="text-align: center;">
5</div>
</td><td><div style="text-align: center;">
4</div>
</td></tr>
<tr><th>Clojure/contrib libs not ported</th><td><div style="text-align: center;">
5</div>
</td><td><div style="text-align: center;">
4</div>
</td><td><div style="text-align: center;">
11</div>
</td><td><div style="text-align: center;">
11</div>
</td><td><div style="text-align: center;">
11</div>
</td></tr>
<tr><th>Lack of integration with Visual Studio</th><td><div style="text-align: center;">
14</div>
</td><td><div style="text-align: center;">
6</div>
</td><td><div style="text-align: center;">
9</div>
</td><td><div style="text-align: center;">
7</div>
</td><td><div style="text-align: center;">
7</div>
</td></tr>
<tr><th>Availability of ClojureCLR-targeted editors/dev environments</th><td><div style="text-align: center;">
10</div>
</td><td><div style="text-align: center;">
8</div>
</td><td><div style="text-align: center;">
9</div>
</td><td><div style="text-align: center;">
6</div>
</td><td><div style="text-align: center;">
10</div>
</td></tr>
<tr><th>Startup speed</th><td><div style="text-align: center;">
13</div>
</td><td><div style="text-align: center;">
8</div>
</td><td><div style="text-align: center;">
7</div>
</td><td><div style="text-align: center;">
4</div>
</td><td><div style="text-align: center;">
6</div>
</td></tr>
<tr><th>Runtime performance</th><td><div style="text-align: center;">
9</div>
</td><td><div style="text-align: center;">
6</div>
</td><td><div style="text-align: center;">
10</div>
</td><td><div style="text-align: center;">
9</div>
</td><td><div style="text-align: center;">
5</div>
</td></tr>
<tr><th>Interop support</th><td><div style="text-align: center;">
5</div>
</td><td><div style="text-align: center;">
8</div>
</td><td><div style="text-align: center;">
8</div>
</td><td><div style="text-align: center;">
9</div>
</td><td><div style="text-align: center;">
11</div>
</td></tr>
<tr><th>Concern about lack of community</th><td><div style="text-align: center;">
3</div>
</td><td><div style="text-align: center;">
3</div>
</td><td><div style="text-align: center;">
14</div>
</td><td><div style="text-align: center;">
11</div>
</td><td><div style="text-align: center;">
13</div>
</td></tr>
<tr><th>Concern about quality</th><td><div style="text-align: center;">
10</div>
</td><td><div style="text-align: center;">
7</div>
</td><td><div style="text-align: center;">
6</div>
</td><td><div style="text-align: center;">
6</div>
</td><td><div style="text-align: center;">
14</div>
</td></tr>
<tr><th>Concern about long-term viability</th><td><div style="text-align: center;">
6</div>
</td><td><div style="text-align: center;">
3</div>
</td><td><div style="text-align: center;">
5</div>
</td><td><div style="text-align: center;">
13</div>
</td><td><div style="text-align: center;">
16</div>
</td></tr>
<tr><th>Mono</th><td><div style="text-align: center;">
13</div>
</td><td><div style="text-align: center;">
5</div>
</td><td><div style="text-align: center;">
6</div>
</td><td><div style="text-align: center;">
6</div>
</td><td><div style="text-align: center;">
11</div>
</td></tr>
</tbody></table>
<br />
<div>
Focusing on the total number of responses of 4+5 or 3+4+5 is one way to get a ranking of relative importance.</div>
<div>
<br /></div>
<table border="1">
<tbody>
<tr><th></th><th>3+4+5</th><th>Rank</th><th></th><th>4+5</th><th>Rank</th></tr>
<tr><th>Concern about lack of community</th><td><div style="text-align: center;">
38</div>
</td><td><div style="text-align: center;">
1</div>
</td><td><div style="text-align: center;">
<br /></div>
</td><td><div style="text-align: center;">
24</div>
</td><td><div style="text-align: center;">
2</div>
</td></tr>
<tr><th>Concern about long-term viability</th><td><div style="text-align: center;">
34</div>
</td><td><div style="text-align: center;">
2</div>
</td><td><div style="text-align: center;">
<br /></div>
</td><td><div style="text-align: center;">
29</div>
</td><td><div style="text-align: center;">
1</div>
</td></tr>
<tr><th>Clojure/contrib libs not ported</th><td><div style="text-align: center;">
33</div>
</td><td><div style="text-align: center;">
3</div>
</td><td><div style="text-align: center;">
<br /></div>
</td><td><div style="text-align: center;">
22</div>
</td><td><div style="text-align: center;">
3</div>
</td></tr>
<tr><th>Availability of ClojureCLR-specifc documentation</th><td><div style="text-align: center;">
32</div>
</td><td><div style="text-align: center;">
4</div>
</td><td><div style="text-align: center;">
<br /></div>
</td><td><div style="text-align: center;">
21</div>
</td><td><div style="text-align: center;">
4</div>
</td></tr>
<tr><th>ClojureCLR's install process</th><td><div style="text-align: center;">
31</div>
</td> <td><div style="text-align: center;">
5</div>
</td><td><div style="text-align: center;">
<br /></div>
</td><td><div style="text-align: center;">
19</div>
</td><td><div style="text-align: center;">
7</div>
</td></tr>
<tr><th>Interop support</th><td><div style="text-align: center;">
28</div>
</td><td><div style="text-align: center;">
6</div>
</td><td><div style="text-align: center;">
<br /></div>
</td><td><div style="text-align: center;">
20</div>
</td><td><div style="text-align: center;">
5 (T)</div>
</td></tr>
<tr><th>Concern about quality</th><td><div style="text-align: center;">
26</div>
</td><td><div style="text-align: center;">
7</div>
</td><td><div style="text-align: center;">
<br /></div>
</td><td><div style="text-align: center;">
20</div>
</td><td><div style="text-align: center;">
5 (T)</div>
</td></tr>
<tr><th>Availability of ClojureCLR-targeted editors/dev environments</th><td><div style="text-align: center;">
25</div>
</td><td><div style="text-align: center;">
8</div>
</td><td><div style="text-align: center;">
<br /></div>
</td><td><div style="text-align: center;">
16</div>
</td><td><div style="text-align: center;">
9</div>
</td></tr>
<tr><th>Runtime performance</th><td><div style="text-align: center;">
24</div>
</td><td><div style="text-align: center;">
9</div>
</td><td><div style="text-align: center;">
<br /></div>
</td><td><div style="text-align: center;">
14</div>
</td><td><div style="text-align: center;">
10 (T)</div>
</td></tr>
<tr><th>Mono</th><td><div style="text-align: center;">
23</div>
</td><td><div style="text-align: center;">
10 (T)</div>
</td><td><div style="text-align: center;">
<br /></div>
</td><td><div style="text-align: center;">
17</div>
</td><td><div style="text-align: center;">
8</div>
</td></tr>
<tr><th>Lack of integration with Visual Studio</th><td><div style="text-align: center;">
23</div>
</td><td><div style="text-align: center;">
10 (T)</div>
</td><td><div style="text-align: center;">
<br /></div>
</td><td><div style="text-align: center;">
14</div>
</td><td><div style="text-align: center;">
10 (T)</div>
</td></tr>
<tr><th>Difficulty deploying completed applications</th> <td><div style="text-align: center;">
21</div>
</td><td><div style="text-align: center;">
12</div>
</td><td><div style="text-align: center;">
<br /></div>
</td><td><div style="text-align: center;">
9</div>
</td><td><div style="text-align: center;">
13</div>
</td></tr>
<tr><th>Startup speed</th><td><div style="text-align: center;">
17</div>
</td><td><div style="text-align: center;">
13</div>
</td><td><div style="text-align: center;">
<br /></div>
</td><td><div style="text-align: center;">
10</div>
</td><td><div style="text-align: center;">
12</div>
</td></tr>
</tbody></table>
<br />
<div>
The top four in each ranking contain the same items. It is possible that people who tried ClojureCLR early and were disappointed in the install process and interop support would be happier with these in the most recent version; this deserves investigation. Because I suspected that the questions about community and viability would be high on the list, later questions probed these topics more. See below.</div>
<div>
<br /></div>
<div>
This question allowed additional comments. Among the deterents noted:</div>
<ul>
<li>In general the lack of examples of typical uses, something which is pretty well covered in the JVM based Clo[j]ure, things like jetty/ring, jdbc, and GUI (which tends to be a lot more important in the windows world).</li>
<li>Emacs support as good as standard clojure's is extremely important! Support for .net generics is extremely important! Lack of these two features were the show stoppers for me. </li>
<li>Lack of ported libraries is also pretty important. </li>
<li>I haven't even really seen anything in terms of guidance / best practices to allow this work to be carried forward by others in a consistent manner.</li>
<li>Also, it would be great if there were more readily available progress reports, roadmaps, etc from David et al. Until this survey became available, ClojureCLR hasn't had a blog, so that's a good start.</li>
<li>VsClojure is unreliable. Trying to build the self generated main() works maybe one or two times, then keeps failing when the bootstrap compiler aborts. I guess this might be covered by the vs integration question but it turns off developers immediately. </li>
<li>Microsoft can kill off support at any time. Linux is a 2nd class citizen. .NET/CLR is not a viable target for anything.</li>
<li>The completeness of the ClojureCLR implementation compared to the Clojure implementation. I.e. do they do the same thing? Is there a Clojure Spec suite of tests or something like that that both implementations pass?</li>
<li>Lack of personal need for CLR.</li>
<li>Generally the install seems bulky compared to clojure for the jvm.</li>
<li>I hadn't heard of it. I'm quite interested in Clojure, but was not aware of a CLR port. So greatest impediment is lack of knowledge/lack of PR.</li>
<li> Mono is my insurance policy, so I want at a minimum as much .NET code as I write (to a maximum of ""all .NET code I write and use"") to run on Mono as well on MS's CLR. [...] I'd love to have ClojureCLR work seamlessly on Mono.</li>
</ul>
<div>
<b><span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;">Rate the following for desirability.</span></b><br />
Respondents were asked to rate a variety of features for desirability on a scale of 1 to 5. The listing below shows them ranked by 4+5 and by 3+4+5. (The two rankings agree across the board.)</div>
<div>
<br /></div>
<table border="1" style="text-align: center;">
<tbody>
<tr><th><br /></th><th>Not imp.<br />
1</th><th><br />
<br />
2</th><th><br />
<br />
3</th><th><br />
<br />
4</th><th><br />
Imp.<br />
5</th><th>4+5</th><th>Rank</th><th>3+4+5</th><th>Rank</th></tr>
<tr><th>Ports of key clojure/contrib libraries</th><td><div style="text-align: center;">
2</div>
</td><td><div style="text-align: center;">
6</div>
</td><td><div style="text-align: center;">
9</div>
</td><td><div style="text-align: center;">
15</div>
</td><td><div style="text-align: center;">
15</div>
</td><td><div style="text-align: center;">
30</div>
</td><td><div style="text-align: center;">
1</div>
</td><td><div style="text-align: center;">
39</div>
</td><td><div style="text-align: center;">
1</div>
</td></tr>
<tr><th>Sample framework interop code</th><td><div style="text-align: center;">
5</div>
</td><td><div style="text-align: center;">
5</div>
</td><td><div style="text-align: center;">
10</div>
</td><td><div style="text-align: center;">
15</div>
</td><td><div style="text-align: center;">
12</div>
</td><td><div style="text-align: center;">
27</div>
</td><td><div style="text-align: center;">
2</div>
</td><td><div style="text-align: center;">
37</div>
</td><td><div style="text-align: center;">
2</div>
</td></tr>
<tr><th>Leiningen support for 'pure' ClojureCLR projects</th><td><div style="text-align: center;">
5</div>
</td><td><div style="text-align: center;">
6</div>
</td><td><div style="text-align: center;">
9</div>
</td><td><div style="text-align: center;">
14</div>
</td><td><div style="text-align: center;">
12</div>
</td><td><div style="text-align: center;">
26</div>
</td><td><div style="text-align: center;">
3</div>
</td><td><div style="text-align: center;">
35</div>
</td><td><div style="text-align: center;">
3 (T)</div>
</td></tr>
<tr><th>DLR hosting (integration w/ C#, IRuby, etc.)</th><td><div style="text-align: center;">
6</div>
</td><td><div style="text-align: center;">
3</div>
</td><td><div style="text-align: center;">
13</div>
</td><td><div style="text-align: center;">
13</div>
</td><td><div style="text-align: center;">
9</div>
</td><td><div style="text-align: center;">
22</div>
</td><td><div style="text-align: center;">
4</div>
</td><td><div style="text-align: center;">
35</div>
</td><td><div style="text-align: center;">
3 (T)</div>
</td></tr>
<tr><th>Wrappers for MS libraries/frameworks</th><td><div style="text-align: center;">
9</div>
</td><td><div style="text-align: center;">
6</div>
</td><td><div style="text-align: center;">
9</div>
</td><td><div style="text-align: center;">
15</div>
</td><td><div style="text-align: center;">
6</div>
</td><td><div style="text-align: center;">
21</div>
</td><td><div style="text-align: center;">
5</div>
</td><td><div style="text-align: center;">
30</div>
</td><td><div style="text-align: center;">
5</div>
</td></tr>
<tr><th>Emacs support for 'pure' ClojureCLR projects</th><td><div style="text-align: center;">
15</div>
</td><td><div style="text-align: center;">
3</div>
</td><td><div style="text-align: center;">
10</div>
</td><td><div style="text-align: center;">
8</div>
</td><td><div style="text-align: center;">
11</div>
</td><td><div style="text-align: center;">
19</div>
</td><td><div style="text-align: center;">
6</div>
</td><td><div style="text-align: center;">
29</div>
</td><td><div style="text-align: center;">
6</div>
</td></tr>
<tr><th>Visual Studio integration</th><td><div style="text-align: center;">
12</div>
</td><td><div style="text-align: center;">
11</div>
</td><td><div style="text-align: center;">
9</div>
</td><td><div style="text-align: center;">
5</div>
</td><td><div style="text-align: center;">
11</div>
</td><td><div style="text-align: center;">
16</div>
</td><td><div style="text-align: center;">
7</div>
</td><td><div style="text-align: center;">
25</div>
</td><td><div style="text-align: center;">
7</div>
</td></tr>
<tr><th>NuGet distribution</th><td><div style="text-align: center;">
17</div>
</td><td><div style="text-align: center;">
6</div>
</td><td><div style="text-align: center;">
12</div>
</td><td><div style="text-align: center;">
6</div>
</td><td><div style="text-align: center;">
2</div>
</td><td><div style="text-align: center;">
8</div>
</td><td><div style="text-align: center;">
8</div>
</td><td><div style="text-align: center;">
20</div>
</td><td><div style="text-align: center;">
8</div>
</td></tr>
</tbody></table>
<br />
<div>
<br /></div>
<div>
This question also allowed for additional comments. Comments included:</div>
<ul>
<li>We need Clojure to be a first-class citizen on par with C#/F# before we can make the switch. This is more important for us than Visual Studio integration or the porting of libraries. A "gimped" Clojure on par with ClojureScript that was hosted on the CLR directly rather than on the DLR would be enough for us to make the switch from C#.</li>
<li>one word: mono</li>
<li>Writing my libs in Clojure.CLR and using them in ASP.NET apps.</li>
<li>Visual Studio is not that important to me personally. But none of my coworks would get theire hands dirty with vim/vimclojure</li>
<li>We need a visual studio plugin for visual studio express. It would make it easier for people to experiment with clojure clr.</li>
<li>startup duration !!</li>
<li>What I really want is not so much Leiningen support for ClojureCLR, but to see a pure Clojure Leiningen replacement (where ""pure Clojure"" means at least ""runs on both Clojure(JVM) and ClojureCLR). </li>
<li>With regards to VS integration, vsClojure seems OK and useful in the limited amount I have used it thus far. [...] I'd probably be all for even better VS integration. I just don't *need* it. </li>
<li>With regards to DLR hosting, anything that makes interop between ClojureCLR and existing CLR languages easier/seamless has my vote. In my particular case, this would probably be F# and C#, in that order. IronRuby and IronPython might be useful and fun if that integration with ClojureCLR was really powerful and interesting, [...]."</li>
<li>Mono/Monodevelop support</li>
</ul>
<div>
<br /></div>
<b><span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;">With which Microsoft frameworks would you like to use ClojureCLR?</span></b><br />
<div>
<img src="https://chart.googleapis.com/chart?cht=bhs&chs=345x480&chbh=24%2C6&chco=7a7aef%7C0000e0%7C2121e4%7C0b0be1%7C6363ec%7C4242e8%7C9b9bf3%7C6f6fed%7C2c2ce5%7C5858eb%7C3737e7%7C1616e3%7C4d4de9%7C8585f0%7C9090f1&chxt=x%2Cy&chxl=0%3A%7C0%7C5%7C10%7C15%7C20%7C25%7C30%7C1%3A%7COther%7CXNA%20(incl.%20XBox)%7CWinForms%7CWindows%20Runtime%20(...%7CWF%7CWPF%7CWCF%7CSilverlight%7CSharepoint%7CRobotics%20Studio%7CReactive%20Framework%7CLinq%7CEntity%20Framework%7CAzure%7CASP.NET%20%2F%20MVC&chxs=0%2C000000%2C12%2C0%2Clt%7C1%2C000000%2C12%2C1%2Clt&chds=0%2C30&chd=t%3A20%2C7%2C5%2C26%2C15%2C5%2C3%2C7%2C7%2C13%2C0%2C10%2C9%2C9%2C4" /><br />
<br />
"Other" included:<br />
<br />
<br />
<ul>
<li>MS Office</li>
<li>installation, etc.</li>
<li>Microsoft Solver Foundation</li>
<li>Kinect</li>
</ul>
<br />
<br /></div>
<div>
<br /></div>
<div>
<span class="Apple-style-span" style="background-color: white;"></span><br />
<b><span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;">If viability (long-term prospects, maturity, etc.) are a concern (for yourself or to present a case at work), what do you need to see to improve confidence?</span></b><span class="Apple-style-span" style="background-color: white;">
</span><br />
<div>
<ul><span class="Apple-style-span" style="background-color: white;">
<li>A dedicated core community that is focused exclusively on the CLR (probably precludes any existing Clojure/dev or Clojure/core people?).</li>
<li>I would need to see signs of momentum: users downloading it and asking questions, reporting bugs, asking for features and chipping in, writing the odd .NET wrapper here and there, complaining about and contributing tooling, and talking/blogging about how they hope to use it, strengths and weaknesses, why it's viable, etc. Visible support and contributions from Clojure brass would go a long way to showing viability as well.</li>
<li>Very solid VS integration and interop with C#</li>
<li>community, books with .net specific samples to avoid setting up a jvm environment</li>
<li>Better visual studio support.</li>
<li>I need Rich Hickey and clojure/core to give the utmost "seal of approval" that ClojureCLR is 100% feature complete for a given version of Clojure proper. To a degree (i.e. for my boss), ClojureCLR needs to be released BY clojure/core and will not be considered until it is.</li>
<li>More info about the state of the project and more info about its integration in the mono ecosystem.</li>
<li>Larger community with wider array of active projects</li>
<li>A solid Mono story. Some ports of major web libraries like compojure, noir, etc.</li>
</span></ul>
<div>
<span class="Apple-style-span" style="background-color: white;"><br /></span></div>
</div>
<b><span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;">If the lack of community is an issue: What would be useful to you?</span></b></div>
<div>
<span class="Apple-style-span" style="font-family: arial, sans-serif;"><span class="Apple-style-span" style="font-size: 12px;"><b><br /></b></span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">20 (63%) -- Separate ClojureCLR forum/mailing list <br />29 (91%) -- Blog or other forum for articles and commentary <br /> 3 ( 9%) -- Other </span> <br />
<br />
For 'Other' was listed the following:<br />
<br />
<ul>
<li>real endorsement from people at Clojure head</li>
<li>First-class Clojure entity.</li>
<li>Active Twitter presence</li>
</ul>
<br />
<br />
Additional comments included:</div>
<div>
</div>
<ul>
<li>Im new to clojure and I love it! I work in a .net environment and I think clojure clr is the way I will get clojure into our environment. Keep clojure clr coming!</li>
<li>I think that it is good running Clojure in many platform (JVM, .NET Platform, JavaScript) and I am interested in ClojureCLR. I think that there are many Clojure programmers who use non-Windows OS. Because they cannot use Visual Studio and shoud use Mono to use ClojureCLR, so they tend to choose JVM.</li>
<li>I would love to use CLR to bypass the strange quirks I ocassionally running in using java (yes the language) on the windows platform</li>
<li>I think it's wonderful that Clojure has a port to the CLR. From a community standpoint, it seems that the "kinds of people" who would use a Clojure either (1) aren't in Windows-heavy environments or (2) would try something like F# with its VS integration and name recognition before ClojureCLR. Almost more than other Clojures, Clojure on the CLR needs a "killer app," or at least a killer wrapper/framework around existing .NET libraries to create a greater impression of activity and reliability.</li>
<li>First, if CLR is really a Clojure target, Clojure as a language should be more abstracted from JVM implementation, to allow a seemless implementation on the CLR (thus less less to worry about contrib libs porting)</li>
<li>Second, CLR should be taking as seriously as JS or JVM targets by Rich and his entourage.</li>
<li>I would love to use CLR to bypass the strange quirks I ocassionally running in using java (yes the language) on the window splatform. Just as a way to make installers and so on without having to go through java->new javalibs etc.</li>
<li>server side would be clojure JVM anyways, i'm mostly interested in client side for clojure CLR.</li>
</ul>
Thanks to all who took the time to respond.<br />
<br />
I'll draw some conclusions and ask for input on future directions in a future posting (soon).<br />
<br />
<br />
<div>
<span class="Apple-style-span" style="background-color: white; font-family: arial, sans-serif; font-size: 12px;">
</span></div>David Millerhttp://www.blogger.com/profile/07657040519395296684noreply@blogger.com1tag:blogger.com,1999:blog-4262147391488425950.post-51300337225467052942011-10-22T23:18:00.000-05:002011-11-03T09:52:59.107-05:00The 2011 ClojureCLR survey is openInspired by Chas Emerick's State of Clojure survey, I've created a similar survey to assess the state of the ClojureCLR community and to gather ideas for moving ClojureCLR forward.<br />
<br />
The survey is at: <span class="Apple-style-span" style="color: #1f497d;"> </span><br />
<span class="Apple-style-span" style="color: #1f497d;"><br />
</span><br />
<span class="apple-style-span"><span style="background-attachment: initial; background-clip: initial; background-color: white; background-image: initial; background-origin: initial; color: black; font-family: Arial, sans-serif; font-size: 10pt;"><span style="color: #0000cc;"><a href="https://docs.google.com/spreadsheet/viewform?formkey=dDE3YnlYbXBxc3ljVU80bjNnTVZaMlE6MQ" target="_blank">https://docs.google.com/spreadsheet/viewform?formkey=dDE3YnlYbXBxc3ljVU80bjNnTVZaMlE6MQ</a></span></span></span><br />
<br />
The survey will remain open through October 31, 2011. <br />
<br />
<br />
The first code commit to the <a href="https://github.com/richhickey/clojure-clr">ClojureCLR github site</a> occurred on February 1, 2009. Today, ClojureCLR is a 99% feature-complete implementation of Clojure. It closely tracks developments in the JVM implementation. It is current with the 1.3.0 release (and has been current and mostly feature-complete since at least 1.1, in January, 2010).<br />
<div>
<br /></div>
<div>
Apparently, there is some interest in ClojureCLR. The binary distribution of the 1.2.0 version has been downloaded 772 times. The repo has 267 watchers, 29% of the number of watchers on the main Clojure repo.</div>
<div>
<br /></div>
<div>
Despite those measures, it is hard to get a sense of use, community or momentum for ClojureCLR. The few queries on IRC often go unanswered; the mailing list sees no mention; there are no bug reports; and there is almost no sign of people asking for features or pitching in to create something simple like wrapper code or ports of the contrib libs.</div>
<div>
<br /></div>
<div>
What will help create that community? What will increase confidence in the viability of this port of Clojure? I hope this survey will give some guidance for moving ClojureCLR forward.</div>
<div>
<br /></div>
<div>
<br /></div>David Millerhttp://www.blogger.com/profile/07657040519395296684noreply@blogger.com0