Jonathan Pryor's web log Jonathan Pryor's web log http://www.jprl.com/Blog/index.html Jonathan Pryor jonpryor@vt.edu Tue, 27 May 2008 23:24:00 GMT http://backend.userland.com/rss lb# Threading: Lock Nesting <p><i>a.k.a. Why the Java 1.0 collections were rewritten...</i></p> <p>Threading is an overly complicated subject, covered in great detail at other locations and in many books. However, there is one subject that either I haven't seen discussed too often, or somehow have managed to miss while reading the plethora of threading sources, something I'll call <i>lock nesting depth</i>:</p> <blockquote> <dl> <dt>lock nesting depth</dt> <dd> The number of locks that must be acquired and held simultaneously in order to perform a given operation. </dd> </dl> </blockquote> <p>In general, the lock nesting depth should be kept as small as possible; anything else results in extra, possibly unnecessary/extraneous locks, which serve only to slow down performance for no added benefit.</p> <p>First, an aside: why does threading code require locks? To maintain data invariants for data shared between threads, preventing the data from being corrupted. Note that this is not necessarily the same as producing "correct" data, as there may be internal locks to prevent internal data corruption but the resulting output may not be "correct" (in as much as it isn't the output that we want).</p> <p>The prototypical example of "non-corrupting but not correct" output is when multiple threads write to the (shared) terminal:</p> <blockquote><pre class="code-csharp"> using System; using System.Threading; class Test { public static void Main () { Thread[] threads = new Thread[]{ new Thread ( () =&gt; { WriteMessage ("Thread 1"); } ), new Thread ( () =&gt; { WriteMessage ("Thread 2"); } ), }; foreach (var t in threads) t.Start (); foreach (var t in threads) t.Join (); } static void WriteMessage (string who) { Console.Write ("Hello from "); Console.Write (who); Console.Write ("!\n"); } }</pre></blockquote> <p>Output for the above program can vary from the sensible (and desirable):</p> <blockquote><pre> $ mono ls.exe Hello from Thread 2! Hello from Thread 1! $ mono ls.exe Hello from Thread 1! Hello from Thread 2!</pre></blockquote> <p>To the downright "corrupt":</p> <blockquote><pre> Hello from Hello from Hello from Hello from Thread 2! Thread 1!</pre></blockquote> <p>(This can happen when Thread 1 is interrupted by Thread 2 before it can write out its entire message.)</p> <p>Notice what's going on here: as far as the system is concerned, what we're doing is safe -- no data is corrupted, my terminal/shell/operating system/planet isn't going to go bonkers, everything is well defined. It's just that in this circumstance "well defined" doesn't match what I, as the developer/end user, desired to see: one of the first two sets of output.</p> <p>The solution, as always, is to either add a a lock within <tt>WriteMessage</tt> to ensure that the output is serialized as desired:</p> <blockquote><pre class="code-csharp"> static object o = new object (); static void WriteMessage (string who) { lock (o) { Console.Write ("Hello from "); Console.Write (who); Console.Write ("!\n"); } }</pre></blockquote> <p>Or to instead ensure that the message can't be split up, working within the predefined semantics of the terminal:</p> <blockquote><pre class="code-csharp"> static void WriteMessage (string who) { string s = "Hello from " + who + "!\n"; Console.Write (s); }</pre></blockquote> <p>(Which can oddly generate duplicate messages on Mono; not sure what's up with that... <a href="http://lists.ximian.com/pipermail/mono-list/2008-April/038401.html" >More here.</a>)</p> <p>For the <tt>WriteMessage</tt> that uses locks, the lock nesting depth is 2, and this can't be readily improved (because <tt>Console.Write</tt> is static, and thus must be thread safe as any thread could execute it at any time).</p> <p>Returning to this entry's subtitle, why were the Java 1.0 collections rewritten? Because they were all internally thread safe. This had it's uses, should you be sharing a <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/Hashtable.html" >Hashtable</a> or <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/Vector.html" >Vector</a> between threads, but even then it was of limited usefulness, as it only protected the <i>internal</i> state <i>for a single method call</i>, not any state that may require more than one function call. Consider this illustrative code which counts the number of times a given token is encountered:</p> <blockquote><pre class="code-csharp"> Hashtable data = new Hashtable (); for (String token : tokens) { if (data.containsKey (token)) { Integer n = (Integer) data.get (token); data.put (token, new Integer (n.intValue() + 1)); } else { data.put (token, new Integer (1)); } }</pre></blockquote> <p>Yes, Hashtable is thread safe and thus won't have <i>its</i> data corrupted, but it can still corrupt <i>your</i> data should multiple threads execute this code against a shared <tt>data</tt> instance, as there is a race with the <tt>data.containsKey()</tt> call, where multiple threads may evaluate the same token "simultaneously" (read: before the following <tt>data.put</tt> call), and thus each thread would try to call <tt>data.put (token, new Integer (1))</tt>. The result: a missed token.</p> <p>The solution is obvious: <i>another</i> lock, controlled by the developer, <i>must</i> be used to ensure valid data:</p> <blockquote><pre class="code-csharp"> Object lock = new Object (); Hashtable data = new Hashtable (); for (String token : tokens) { synchronized (lock) { if (data.containsKey (token)) { Integer n = (Integer) data.get (token); data.put (token, new Integer (n.intValue() + 1)); } else { data.put (token, new Integer (1)); } } }</pre></blockquote> <p>Consequently, for <i>all</i> "non-trivial" code (where "non-trivial" means "requires more than one method to be called on the collection object in an atomic fashion") will <i>require</i> a lock nesting depth of two. Furthermore, the lock nesting depth would always be at least one, and since many functions were not invoked between multiple threads, or the collection instance local to that particular method, the synchronization within the collection was pure overhead, providing no benefit.</p> <p>Which is why in Java 1.2, all of the new collection classes such as <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/ArrayList.html" >ArrayList</a> and <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/HashMap.html" >HashMap</a> are explicitly unsynchronized, as are all of the .NET 1.0 and 2.0 collection types unless you use a synchronized wrapper such as <a href="http://www.go-mono.com/docs/index.aspx?link=M%3aSystem.Collections.ArrayList.Synchronized(System.Collections.ArrayList)" >System.Collections.ArrayList.Synchronized</a> (which, again, is frequently of dubious value if you ever need to invoke more than one method against the collection atomically).</p> <p>Finally, the <a href="http://msdn.microsoft.com/en-us/library/f857xew0(VS.71).aspx" >Threading Design Guidelines</a> of the <a href="http://msdn.microsoft.com/en-us/library/czefa0ke(VS.71).aspx" >.NET Framework Design Guidelines for Class Library Developers</a> (<a href="http://www.amazon.com/Framework-Design-Guidelines-Conventions-Development/dp/0321246756/ref=pd_bbs_sr_1?ie=UTF8&amp;s=books&amp;qid=1211941515&amp;sr=8-1" >book</a>) suggests that all static members be thread safe, but instance member <i>by default</i> should not be thread safe:</p> <blockquote> <p>Instance state does not need to be thread safe. By default, class libraries should not be thread safe. Adding locks to create thread-safe code decreases performance, increases lock contention, and creates the possibility for deadlock bugs to occur. In common application models, only one thread at a time executes user code, which minimizes the need for thread safety. For this reason, the .NET Framework class libraries are not thread safe by default.</p> </blockquote> <p>Obviously, there are exceptions -- for example, if a static method returns a shared instance of some class, then all of those instance members must be thread safe as they can be accessed via the static method (<a href="http://msdn.microsoft.com/en-us/library/system.reflection.assembly.aspx" >System.Reflection.Assembly</a> must be thread safe, as an instance of <tt>Assembly</tt> is returned by the static method <a href="http://msdn.microsoft.com/en-us/library/system.reflection.assembly.getexecutingassembly.aspx" >Assembly.GetExecutingAssembly</a>). <i>By default</i>, though, instance members should <i>not</i> be thread safe.</p> http://www.jprl.com/Blog/archive/development/2008/May-27.html Jonathan Pryor (jonpryor@vt.edu) http://www.jprl.com/Blog/archive/development/2008/May-27.html Wed, 28 May 2008 03:24:00 GMT HackWeek Summary <p>In case you missed it, last week was "Hackweek" at Novell.</p> <p>My week was less "hacking" and more "spit-and-polish." In particular:</p> <ul> <li>Wrote <a href="http://anonsvn.mono-project.com/source/trunk/monodoc/class/Mono.Posix/en/Mono.Unix/UnixSignal.xml" >Mono.Unix.UnixSignal</a> documentation. This only took ~1/2 a day.</li> <li>Released <a href="http://www.jprl.com/Blog/archive/development/2008/../ndesk.options/2008/Feb-14.html" >NDesk.Options 0.2.0</a>, which in turn involved the <a href="http://www.jprl.com/Blog/archive/development/2008/../mono/2006/Sep-20.html">vicious cycle</a> of write documentation (and samples), realize I'm missing something or don't like the name, change the library, update the documentation, repeat... <p>Consequently, something I <i>thought</i> would only take another half a day wound up taking 3 days, with some changes happening at the last moment (the <tt>System.Action`2</tt> removal, thus removing the need to have two different builds depending on whether .NET 2.0 or .NET 3.0 is targeted).</p> </li> <li>Improve <a href="http://www.mono-project.com/Generating_Documentation" >monodocs2html</a> so that the output sucks...well, less. I won't say that it's actually good now, but it is an improvement. For comparison purposes, <a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html" >NDesk.Options.OptionSet</a> documentation output from: <ul> <li><a href="http://www.jprl.com/Blog/archive/development/2008/OptionSet.orig.htm">monodocs2html 1.2.6</a></li> <li><a href="http://www.jprl.com/Blog/archive/development/2008/OptionSet.svn.htm">monodocs2html svn</a></li> </ul> <p>In particular, note that in the 1.2.6 output that there are three examples as part of the Remarks documentation, but it's rather difficult to tell when one example ends and the next begins (due to the lack of an Example header). The svn version fixes this, adds JavaScript bling so that all sections can be collapsed and expanded, and adds a mini "index" to the top-left so that it's easier to get to the relevant sections (such as skipping the three lengthy examples that precede the Members listing).</p> </li> </ul> <p>I had wanted to do other things as well, such as migrate the monodoc-related programs to use NDesk.Options instead of Mono.GetOptions for option parsing, but such efforts will have to wait until later...</p> http://www.jprl.com/Blog/archive/development/2008/Feb-19.html Jonathan Pryor (jonpryor@vt.edu) http://www.jprl.com/Blog/archive/development/2008/Feb-19.html Tue, 19 Feb 2008 15:51:00 GMT Announcing NDesk.Options 0.2.0 <p>I am pleased to announce the release of <a href="http://www.ndesk.org/Options">NDesk.Options</a> 0.2.0. NDesk.Options is a C# program option parser library, inspired by Perl's <a href="http://perldoc.perl.org/Getopt/Long.html">Getopt::Long</a> option parser.</p> <p>To download, visit the NDesk.Options web page:</p> <blockquote> <a href="http://www.ndesk.org/Options">http://www.ndesk.org/Options</a> </blockquote> <h3>Usage</h3> <p>See <a href="http://www.ndesk.org/Options">http://www.ndesk.org/Options</a> and the <a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html" >OptionSet</a> documentation for examples.</p> <h3>What's New?</h3> <p>There have been numerous changes since the previous <a href="http://www.jprl.com/Blog/archive/development/ndesk.options/2008/../../ndesk.options/2008/Jan-27.html">0.1.0 release</a>:</p> <ul> <li>Mono 1.9 is now required to build. (An svn release was previously required anyway, so this isn't a surprising requirement.)</li> <li> <p>Simplify the API by removing all <tt>OptionSet.Add()</tt> methods which provided an <a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionContext.html" >OptionContext</a> to the callback function; this includes: </p> <ul> <li><tt>OptionSet.Add(string, Action&lt;string, OptionContext&gt;)</tt></li> <li><tt>OptionSet.Add(string, string, Action&lt;string, OptionContext&gt;)</tt></li> <li><tt>OptionSet.Add&lt;T&gt;(string, Action&lt;T, OptionContext&gt;)</tt></li> <li><tt>OptionSet.Add&lt;T&gt;(string, string, Action&lt;T, OptionContext&gt;)</tt></li> </ul> <p>If you really need access to an <tt>OptionContext</tt>, you can <a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html#M:NDesk.Options.OptionSet.Add(NDesk.Options.Option)" >Add</a> your own <a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/Option.html" >Option</a> and override <a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/Option.html#M:NDesk.Options.Option.OnParseComplete(NDesk.Options.OptionContext)" >Option.OnParseComplete(OptionContext)</a>.</p> </li> <li><p>By <a href="http://www.tirania.org/blog">Miguel</a>'s request, change the semantics for <tt>Option</tt>s with <a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionValueType.html#F:NDesk.Options.OptionValueType.Optional" >optional</a> values (arguments that have a type value of `<tt>:</tt>'). Previously, <tt>Option</tt>s accepting an optional value were virtually identical to <tt>Option</tt>s accepting a required value; the only place they would differ is at the end of the command line, where if a value was missing for a <tt>Option</tt> with an optional value no error would occur, while an <tt>Option</tt> with a required value would generate an error.</p> <p>Now, we introduce the notion of <i>greediness</i>: required values are greedy, and will eat any number of following arguments in order to fulfill their requirements. Optional values are <i>not</i> greedy, and will <i>only</i> extract a value from the <i>current</i> argument.</p> <p>By way of example:</p> <blockquote><pre class="code-csharp"> string color = null; var p = new OptionSet () { { "-color:", v => color = v }, }; p.Parse (new string[]{"--color=auto"}); // 1 p.Parse (new string[]{"--color", "auto"}); // 2</pre></blockquote> <p>In NDesk.Options 0.1.0, (1) and (2) would be identical and <tt>color</tt> would be given the value <tt>auto</tt>. In 0.2.0, they are <i>not</i> identical: (1) would assign the value <tt>auto</tt> to <tt>color</tt>, while (2) would assign <tt>null</tt> to <tt>color</tt>. This permits consistency with GNU <b>ls</b>(1)'s <tt>ls --color</tt> behavior.</p> <p>If a required option were to be specified (by using <tt>=</tt> instead of <tt>:</tt>), then (1) and (2) would again have identical results.</p> </li> <li>NDesk.Options 0.1.0 restricted option bundling to boolean <tt>Option</tt>s. This restriction has been relaxed so that (1) <tt>Option</tt>s accepting both optional and required values may be bundled with boolean <tt>Option</tt>s, and (2) the optional or required value may be bundled as well. As before, only single character <tt>Option</tt>s may be bundled. <p>The logic is as follows: given an argument such as <tt>-cvfname</tt>:</p> <ol> <li><tt>cvfname</tt> must <i>not</i> match a registered <tt>Option</tt>. If it does match a registered option, then that is the <tt>Option</tt> that will (eventually) be invoked.</li> <li><tt>c</tt> must be a registered option. If it isn't, then <tt>-cvfname</tt> is returned from <a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html#M:NDesk.Options.OptionSet.Parse(System.Collections.Generic.IEnumerable%3CSystem.String%3E)" >OptionSet.Parse(IEnumerable&lt;string&gt;)</a>.</li> <li>Each character is looked up; if it's a boolean <tt>Option</tt>, then the associated action is invoked with a non-<tt>null</tt> value.</li> <li>If instead the character is an <tt>Option</tt> accepting one or more optional or required values, then the rest of the argument (not including the <tt>Option</tt> character) is used as the value. This also follows the greediness of optional vs. required values: optional values will only use the current argument, while required values may use the following argument(s) if e.g. the <tt>Option</tt>'s character is the last character in the sequence.</li> <li>If a non-<tt>Option</tt> character is encountered that is <i>not</i> (a) the first character in the sequence, or (b) used as the value for a previous <tt>Option</tt>, then an <a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionException.html" >OptionException</a> is thrown.</li> </ol> <p>This does The Right Thing for <b>tar</b>(1)-like option handling, with <tt>tar -cvfname ...</tt> <i>c</i>reating (with <i>v</i>erbose output) the <i>f</i>ile with the name <i>name</i>.</p> </li> <li><tt>Option</tt>s may now accept (or require) more than one value. The <a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/Option.html#C:NDesk.Options.Option(System.String,System.String,System.Int32)" >Option (string, string, int)</a> constructor allows specifying how many values are accepted/required (depending on whether the <tt>Option</tt> has optional or required values). <p>The <tt>Option</tt> values are available through the <a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionContext.html#P:NDesk.Options.OptionContext.OptionValues" >OptionContext.OptionValues</a> collection.</p> </li> <li>Direct support for <tt>Option</tt>s accepting/required two values within <a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html" >OptionSet</a>: <ul> <li><a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html#M:NDesk.Options.OptionSet.Add(System.String,NDesk.Options.OptionAction{System.String,System.String})" >OptionSet.Add(string, OptionAction&lt;string, string&gt;)</a></li> <li><a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html#M:NDesk.Options.OptionSet.Add(System.String,System.String,NDesk.Options.OptionAction{System.String,System.String})" >OptionSet.Add(string, string, OptionAction&lt;string, string&gt;)</a></li> <li><a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html#M:NDesk.Options.OptionSet.Add%60%602(System.String,NDesk.Options.OptionAction{%60%600,%60%601})" >OptionSet.Add&lt;TKey, TValue&gt; (string, OptionAction&lt;TKey, TValue&gt;)</a></li> <li><a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html#M:NDesk.Options.OptionSet.Add%60%602(System.String,System.String,NDesk.Options.OptionAction{%60%600,%60%601})" >OptionSet.Add&lt;TKey, TValue&gt; (string, string, OptionAction&lt;TKey, TValue&gt;)</a></li> </ul> <p>This now permits reasonable handling of <b>cc</b>(1)-style parameters:</p> <blockquote><pre class="code-csharp"> var macros = new Dictionary&lt;string, string&gt; (); var p = new OptionSet () { { "D:", (k, v) => { if (k != null) macros.Add (k, v); } }, }; p.Parse (new string[]{"-DNAME1", "-DNAME2=VALUE2"}); // Adds the keys "NAME1" (with null value) // and "NAME2" (with value "VALUE2") to `macros'.</pre></blockquote> <p>Note that an optional value is used; if <tt>D=</tt> were specified, two values would be required, so <tt>-DNAME1 -DNAME2=VALUE2</tt> would insert <i>one</i> macro -- <tt>NAME1</tt> -- with the value <tt>-DNAME2=VALUE2</tt>. </p> </li> <li>When an <tt>Option</tt> permits more than one value, it may provide a list of <i>value separator strings</i>, strings that may be used to separate the multiple values. If no separators are listed, <tt>=</tt> and <tt>:</tt> are used as the default (thus permitting the previous <tt>-DNAME2=VALUE2</tt> example to work; <tt>-DNAME2:VALUE2</tt> would have had the same result). <p>The value separator strings follow the <tt>:</tt> or <tt>=</tt> in the <tt>Option</tt> prototype. They consist of:</p> <ul> <li>The string <i>within</i> <tt>{</tt> and <tt>}</tt>.</li> <li>Any other invidividual character.</li> </ul> <p>Thus, the prototype <tt>M:+-*/</tt> would use <tt>+</tt>, <tt>-</tt>, <tt>*</tt>, or <tt>/</tt> to split values, so <tt>-M5+2</tt>, <tt>-M5-2</tt>, <tt>-M5*2</tt>, and <tt>-M5/2</tt> all provide two values (<tt>5</tt> and <tt>2</tt>) to the <tt>M</tt> option.</p> <p>The prototype <tt>N={-->}{=>}</tt> would parse both <tt>-NA-->B</tt> and <tt>-NA=>B</tt> so that <tt>A</tt> and <tt>B</tt> are provided as the two values to the <tt>N</tt> option.</p> <p>As a special construct, the separator <tt>{}</tt> requires that each value be a separate argument. (This makes no sense for <tt>Option</tt>s with optional values.)</p> </li> <li>Naming consistency improvements: an <i>argument</i> is an unparsed string, an <i>option</i> is a parsed argument that corresponds to a registered <tt>Option</tt>, and a <i>prototype</i> is a description of an <tt>Option</tt>, describing all aliases, the value type, and value separators. This has resulted in method argument name changes.</li> <li>Removal of .NET 3.5 support. Instead of using <tt>System.Action`2</tt> from System.Core.dll (or providing an internal equivalent), I've just defined a <a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionAction%602.html" >OptionAction&lt;TKey, TValue&gt;</a> type. This simplifies assembly versioning.</li> </ul> http://www.jprl.com/Blog/archive/development/ndesk.options/2008/Feb-14.html Jonathan Pryor (jonpryor@vt.edu) http://www.jprl.com/Blog/archive/development/ndesk.options/2008/Feb-14.html Thu, 14 Feb 2008 21:42:00 GMT Unix Signal Handling In C# <p>In the beginning, Unix introduced <a href="http://linux.die.net/man/2/signal">signal(2)</a>, which permits a process to respond to external "stimuli", such as a keyboard interrupt (<tt>SIGINT</tt>), floating-point error (<tt>SIGFPE</tt>), dereferencing the <tt>NULL</tt> pointer (<tt>SIGSEGV</tt>), and other asynchronous events. And lo, it was...well, acceptable, really, but there wasn't anything better, so it at least <i>worked</i>. (Microsoft, when faced with the same problem of allowing processes to perform some custom action upon an external stimuli, invented <a href="http://www.microsoft.com/msj/0197/exception/exception.aspx" >Structured Exception Handling</a>.)</p> <p>Then, in a wrapping binge, I exposed it for use in C# with <a href="http://www.go-mono.com/docs/index.aspx?tlink=0@ecma%3a149%23Stdlib%2fM%2f53" >Stdlib.signal()</a>, so that C# code could register signal handlers to be invoked when a signal occurred.</p> <p>The problem? By their very nature, signals are asynchronous, so even in a single-threaded program, you had to be <i>very</i> careful about what you did, as your "normal" thread was certainly in the middle of doing something. For example, calling <a href="http://linux.die.net/man/3/malloc">malloc(3)</a> was almost certainly a bad idea, because if the process was in the middle of a <tt>malloc</tt> call already, you'd have a reentrant malloc call which could corrupt the heap.</p> <p>This reentrant property impacts <i>all</i> functions in the process, including system calls. Consequently, a list of functions that were "safe" for invocation from signal handlers was standardized, and is listed in the above <tt>signal</tt> man page; it includes functions such as <tt>read(2)</tt> and <tt>write(2)</tt>, but not functions like e.g. <tt>pwrite(2)</tt>.</p> <p>Consequently, these limitations and a few other factors led to the general recommendation that signal handlers should be as simple as possible, such as writing to global variable which the main program occasionally polls.</p> <p>What's this have to do with <tt>Stdlib.signal()</tt>, and why was it a mistake to expose it? The problem is the <a href="http://www.mono-project.com/dllimport">P/Invoke mechanism</a>, which allows marshaling C# delegates as a function pointer that can be invoked from native code. When the function pointer is invoked, the C# delegate is eventually executed.</p> <p>However, before the C# delegate can be executed, <a href="http://lists.ximian.com/pipermail/mono-devel-list/2008-January/026501.html" >a number of of steps needs to be done first</a>:</p> <blockquote> <ol> <li>The first thing it does is to ensure the application domain for the thread where the signal handler executes actually matches the appdomain the delegate comes from, if it isn't it may need to set it and do several things that we can't guarantee are signal context safe...</li> <li>If the delegate is of an instance method we also need to retrieve the object reference, which may require taking locks...</li> </ol> </blockquote> <p>In the same email, <a href="http://www.advogato.org/person/lupus/">lupus</a> suggests an alternate signal handling API that would be safe to use from managed code. Later, <a href="http://lists.ximian.com/pipermail/mono-devel-list/2008-January/026673.html" >I provided a possible implementation</a>. It amounts to treating the <tt>UnixSignal</tt> instance as a glorified global variable, so that it can be polled to see if the signal has been generated:</p> <blockquote><pre class="code-csharp"> UnixSignal signal = new UnixSignal (Signum.SIGINT); while (!signal.IsSet) { /* normal processing */ }</pre></blockquote> <p>There is also an API to permit blocking the current thread until the signal has been emitted (which also accepts a timeout):</p> <blockquote><pre class="code-csharp"> UnixSignal signal = new UnixSignal (Signum.SIGINT); // Wait for SIGINT to be generated within 5 seconds if (signal.WaitOne (5000, false)) { // SIGINT generated }</pre></blockquote> <p>Groups of signals may also be waited on:</p> <blockquote><pre class="code-csharp"> UnixSignal[] signals = new UnixSignal[]{ new UnixSignal (Signum.SIGINT), new UnixSignal (Signum.SIGTERM), }; // block until a SIGINT or SIGTERM signal is generated. int which = UnixSignal.WaitAny (signals, -1); Console.WriteLine ("Got a {0} signal!", signals [which].Signum);</pre></blockquote> <p>This isn't as powerful as the current <tt>Stdlib.signal()</tt> mechanism, but it is safe to use, doesn't lead to potentially ill-defined or unwanted behavior, and is the best that we can readily provide for use by managed code.</p> <p><tt>Mono.Unix.UnixSignal</tt> is now in <a href="http://anonsvn.mono-project.com/source/trunk/">svn-HEAD</a> and the <a href="http://anonsvn.mono-project.com/source/branches/mono-1-9/">mono-1-9</a> branch, and should be part of the next Mono release.</p> http://www.jprl.com/Blog/archive/development/mono/2008/Feb-08.html Jonathan Pryor (jonpryor@vt.edu) http://www.jprl.com/Blog/archive/development/mono/2008/Feb-08.html Fri, 08 Feb 2008 20:32:00 GMT Announcing NDesk.Options 0.1.0 <p>I am pleased to announce the release of <a href="http://www.ndesk.org/Options">NDesk.Options</a> 0.1.0. NDesk.Options is a C# program option parser library, inspired by Perl's <a href="http://perldoc.perl.org/Getopt/Long.html">Getopt::Long</a> option parser.</p> <p>To download, visit the NDesk.Options web page:</p> <blockquote> <a href="http://www.ndesk.org/Options">http://www.ndesk.org/Options</a> </blockquote> <h3>Usage</h3> <p>See <a href="http://www.ndesk.org/Options">http://www.ndesk.org/Options</a> and the <a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html" >OptionSet</a> documentation for examples.</p> <h3>What's New?</h3> <p>There have been numerous changes since the previous <a href="http://www.jprl.com/Blog/archive/development/ndesk.options/2008/../../mono/2008/Jan-07.html">prototype release</a>:</p> <ul> <li><a href="http://www.ndesk.org/doc/ndesk-options">Full member documentation.</a></li> <li>All errors are reported via <a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionException.html" >OptionException</a>.</li> <li><tt>Options</tt> has been renamed to <a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html" >OptionSet</a>.</li> <li> <a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html#M:NDesk.Options.OptionSet.Parse(System.Collections.Generic.IEnumerable{System.String})" >OptionSet.Parse(IEnumerable&lt;string&gt;)</a> now returns a <tt>List&lt;string&gt;</tt> instead of an <tt>IEnumerable&lt;string&gt;</tt>.</li> <li>When a registered option follows an option requiring a value, the registered option is used as the option value instead of triggering an error. Thus: <blockquote><pre class="code-csharp"> var p = new OptionSet () { { "-n=", v => { /* ignore */ } }, { "-v", v => { /* ignore */ } }, }; p.Parse (new string[]{"-n", "-v"});</pre></blockquote> <p>would previously have triggered an exception, but now uses <tt>-v</tt> as the value of the <tt>-n</tt> option. This is consistent with Getopt::Long.</p></li> <li><a href="http://www.go-mono.com/docs/index.aspx?tlink=13@ecma%3a1626%23TypeConverter%2f" >TypeConverter</a> exceptions are now wrapped within an <tt>OptionException</tt>, and the <tt>Message</tt> property contains a useful error message.</li> <li><a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html#C:NDesk.Options.OptionSet(System.Converter{System.String,System.String})" >OptionException message localization support.</a></li> <li>Add a <a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionContext.html" >OptionContext</a> class that provides contextual information about the current option.</li> <li>Add a set of <a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html#M:NDesk.Options.OptionSet.Add(System.String,System.String,System.Action{System.String,NDesk.Options.OptionContext})" >OptionSet.Add()</a> methods that have callbacks that accept an <tt>OptionContext</tt> parameter.</li> <li>Add a set of virtual methods to <a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/Option.html" >Option</a> and <a href="http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html" >OptionSet</a> to permit use by subclasses. The <tt>OptionSet</tt> class-level documentation has an example.</li> </ul> http://www.jprl.com/Blog/archive/development/ndesk.options/2008/Jan-27.html Jonathan Pryor (jonpryor@vt.edu) http://www.jprl.com/Blog/archive/development/ndesk.options/2008/Jan-27.html Mon, 28 Jan 2008 03:24:00 GMT Mono and Mixed Mode Assembly Support <p>An occasional question on <a href="irc://irc.gnome.org:6667/%23mono">#mono@irc.gnome.org</a> and <a href="irc://irc.freenode.net:6667/%23%23csharp">##csharp@irc.freenode.net</a> is whether <a href="http://www.mono-project.com">Mono</a> will support mixed-mode assemblies, as generated by Microsoft's Managed Extensions for C++ compiler (Visual Studio 2001, 2003), and C++/CLI (Visual Studio 2005, 2008).</p> <p>The answer is <i>no</i>, and mixed mode assemblies will likely never be supported.</p> <p>Why?</p> <p>First, what's a <i>mixed mode assembly</i>? A mixed mode assembly is an assembly that contains <i>both</i> managed (CIL) and unmanaged (machine language) code. Consequently, they are <i>not</i> portable to other CPU instruction sets, just like normal C and C++ programs and libraries.</p> <p>Next, why use them? The primary purpose for mixed mode assemblies is as "glue", to e.g. use a C++ library class as a base class of a managed class. This allows the managed class to extend unmanaged methods, allowing the managed code to be polymorphic with respect to existing unmanaged functions. This is extremely useful in many contexts. However, as something like this involves extending a C++ class, it requires that the compiler know all about the C++ compiler ABI (name mangling, virtual function table generation and placement, exception behavior), and thus effectively requires native code. If the base class is within a separate <tt>.dll</tt>, this will also require that the mixed mode assembly list the native <tt>.dll</tt> as a dependency, so that the native library is also loaded when the assembly is loaded.</p> <p>The <i>other</i> thing that mixed mode assemblies support is the ability to export new <tt>C</tt> functions so that other programs can <tt>LoadLibrary()</tt> the assembly and <tt>GetProcAddress</tt> the exported <tt>C</tt> function.</p> <p>Both of these capabilities <i>require</i> that the shared library loader for the platform support Portable Executable (PE) files, as assemblies are PE files. If the shared library loader supports PE files, then the loader can ensure that when the assembly is loaded, all listed dependent libraries are also loaded (case 1), or that native apps will be able to load the assembly as if it were a native DLL and resolve DLL entry points against it.</p> <p>This requirement is met on Windows, which uses the PE file format for EXE and DLL files. This requirement is not met on Linux, which uses ELF, nor is it currently met on Mac OS X, which uses Mach-O.</p> <p>So why can't mixed mode assemblies be easily supported in Mono? Because <tt>ld.so</tt> doesn't like PE.</p> <p>The only workarounds for this would be to either extend assemblies so that ELF files can contain both managed and unmanaged code, or to extend the shared library loader to support the loading of PE files. Using ELF as an assembly format may be useful, but would restrict portability of such ELF-assemblies to only Mono/Linux; .NET could never make use of them, nor could Mono on Mac OS X. Similarly, extending the shared library loader to support PE could be done, but can it support loading <i>both</i> PE and ELF (or Mach-O) binaries into a single process? What happens if a PE file loaded into an "ELF" process requires <tt>KERNEL32.DLL</tt>? Extending the shared library loader isn't a panacea either.</p> <p>This limitation makes mixed mode assemblies of dubious value. It is likely solvable, but there are for more important things for Mono to focus on.</p> http://www.jprl.com/Blog/archive/development/mono/2008/Jan-27.html Jonathan Pryor (jonpryor@vt.edu) http://www.jprl.com/Blog/archive/development/mono/2008/Jan-27.html Mon, 28 Jan 2008 01:37:00 GMT So you want to parse a command line... <p>If you develop command-line apps, parsing the command-line is a necessary evil (unless you write software so simple that it doesn't require any options to control its behavior). Consequently, I've written and used several parsing libraries, including <a href="http://www.go-mono.com/docs/index.aspx?link=N%3aMono.GetOptions" >Mono.GetOptions</a>, Perl's <a href="http://perldoc.perl.org/Getopt/Long.html" >Getopt::Long</a> library, and some <a href="http://anonsvn.mono-project.com/source/trunk/type-reflector/ProgramOptions.cs" >custom</a> <a href="http://anonsvn.mono-project.com/source/trunk/lb/config.cs">written</a> <a href="http://www.jprl.com/Blog/../cgi-bin/gitweb.cgi?p=mono-fuse.git;a=blob;h=79e3ee0099c846d864111295064d2a8a891a99b0;hb=0b1e5d9aefab7f552f0aaa57e9c80095e8e3120b;f=src/Mono.Fuse/Mono.Fuse/FileSystem.cs">libraries</a> or <a href="http://www.jprl.com/Blog/../cgi-bin/gitweb.cgi?p=omgwtf.git;a=blob;h=c8f1c39f63d1e7a20b6c52c43461464652b9b989;hb=7a43f9dcf583e65dc06fad1c57f975a648cff8d7;f=Main.cpp" >helpers</a>.</p> <p>So what's wrong with them? The problem with <tt>Mono.GetOptions</tt> is that it has <a href="http://www.codinghorror.com/blog/archives/001025.html">high code overhead</a>: in order to parse a command line, you need a new type (which inherits from <a href="http://www.go-mono.com/docs/index.aspx?link=T%3aMono.GetOptions.Options" >Mono.GetOptions.Options</a>) and annotate each field or property within the type with an <a href="http://www.go-mono.com/docs/index.aspx?link=T%3AMono.GetOptions.OptionAttribute" >Option</a> attribute, and let <tt>Mono.GetOptions</tt> map each command-line argument to a field/property within the <tt>Options</tt> subclass. See <a href="http://anonsvn.mono-project.com/source/trunk/monodoc/tools/monodocer.cs" >monodocer</a> for an example; search for <tt>Opts</tt> to find the subclass.</p> <p>The <tt>type-reflector</tt> parser is similarly code heavy, if only in a different way. The <tt>Mono.Fuse</tt>, <tt>lb</tt>, and <tt>omgwtf</tt> parsers are one-offs, either specific to a particular environment (e.g. integration with the <tt>FUSE</tt> native library) or not written with any eye toward reuse.</p> <p>Which leaves Perl's <tt>Getopt::Long</tt> library, which I've used for a number of projects, and quite like. It's short, concise, requires no object overhead, and allows seeing at a glance all of the options supported by a program:</p> <blockquote><pre id="opt-Perl-example" class="code-perl"> use Getopt::Long; my $data = "file.dat"; my $help = undef; my $verbose = 0; GetOptions ( "file=s" =&gt; \$data, "v|verbose" =&gt; sub { ++$verbose; }, "h|?|help" =&gt; $help );</pre></blockquote> <p>The above may be somewhat cryptic at first, but it's short, concise, and lets you know at a glance that it takes three sets of arguments, one of which takes a required string parameter (the <tt>file</tt> option).</p> <p>So, says I, what would it take to provide similar support in C#? With C# 3.0 collection initializers and lambda delegates, I can get something that feels rather similar to the above <tt>GetOpt::Long</tt> code:</p> <blockquote><pre class="code-csharp"> string data = null; bool help = false; int verbose = 0; var p = new Options () { { "file=", (v) =&gt; data = v }, { "v|verbose", (v) =&gt; { ++verbose } }, { "h|?|help", (v) =&gt; help = v != null }, }; p.Parse (argv).ToArray ();</pre></blockquote> <p><a href="http://www.jprl.com/Blog/archive/development/mono/2008/Options.v1.cs">Options.cs</a> has the goods, plus unit tests and additional examples (via the tests).</p> <p><tt>Options</tt> is both more and less flexible than <tt>Getopt::Long</tt>. It doesn't support providing references to variables, instead using a delegate to do all variable assignment. In this sense, <tt>Options</tt> is akin to <tt>Getopt::Long</tt> while requiring that all options use a <tt>sub</tt> callback (as the <a href="#opt-Perl-example"><tt>v|verbose</tt> option</a> does above).</p> <p><tt>Options</tt> is more flexible in that it isn't restricted to just strings, integers, and floating point numbers. If there is a <a href="http://msdn2.microsoft.com/en-us/library/system.componentmodel.typeconverter.aspx" >TypeConverter</a> registered for your type (to perform string-&gt;object conversions), then any type can be used as an option value. To do so, merely declare that type within the callback:</p> <blockquote><pre class="code-csharp"> int count = 0; var p = new Options () { { "c|count=", (int v) =&gt; count = v }, };</pre></blockquote> <p>As additional crack, you can provide an (optional) description of the option so that <tt>Options</tt> can generate help text for you:</p> <blockquote><pre class="code-csharp"> var p = new Options () { { "really-long-option", "description", (v) =&gt; {} }, { "h|?|help", "print out this message and exit", (v) =&gt; {} }, }; p.WriteOptionDescriptions (Console.Out);</pre></blockquote> <p>would generate the text:</p> <blockquote><pre> --really-long-option description -h, -?, --help print out this message and exit</pre></blockquote> <p><tt>Options</tt> currently supports:</p> <ul> <li>Parameters of the form: <tt>-flag</tt>, <tt>--flag</tt>, <tt>/flag</tt>, <tt>-flag=value</tt>, <tt>--flag=value</tt>, <tt>/flag=value</tt>, <tt>-flag:value</tt>, <tt>--flag:value</tt>, <tt>/flag:value</tt>, <tt>-flag value</tt>, <tt>--flag value</tt>, <tt>/flag value</tt>.</li> <li>"boolean" parameters of the form: <tt>-flag</tt>, <tt>--flag</tt>, and <tt>/flag</tt>. Boolean parameters can have a `<tt>+</tt>' or `<tt>-</tt>' appended to explicitly enable or disable the flag (in the same fashion as <tt>mcs -debug+</tt>). For boolean callbacks, the provided value is non-<tt>null</tt> for enabled, and <tt>null</tt> for disabled.</li> <li>"value" parameters with a required value (append `<tt>=</tt>' to the option name) or an optional value (append `<tt>:</tt>' to the option name). The option value can either be in the current option (<tt>--opt=value</tt>) or in the following parameter (<tt>--opt value</tt>). The actual value is provided as the parameter to the callback delegate, unless it's (1) optional and (2) missing, in which case <tt>null</tt> is passed.</li> <li>"bundled" parameters which <i>must</i> start with a single `<tt>-</tt>' and consists of only single characters. In this manner, <tt>-abc</tt> would be a shorthand for <tt>-a -b -c</tt>.</li> <li>Option processing is disabled when <tt>--</tt> is encountered.</li> </ul> <p>All un-handled parameters are returned from the <tt>Options.Parse</tt> method, which is implemented as an iterator (hence the calls to <tt>.ToArray()</tt> in the above C# examples, to force processing).</p> http://www.jprl.com/Blog/archive/development/mono/2008/Jan-07.html Jonathan Pryor (jonpryor@vt.edu) http://www.jprl.com/Blog/archive/development/mono/2008/Jan-07.html Tue, 08 Jan 2008 02:59:00 GMT Announcing Brian Jonathan Pryor <p>It took longer than we would have liked, and he still arrived earlier than he wanted, but Brian Jonathan Pryor was born this morning at 2:39 AM:</p> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_2040.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_2040-web.jpg" title="Brian and Amber" alt="Brian and Amber" /></a></p></blockquote> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_2049.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_2049-web.jpg" title="Jonathan and Brian" alt="Jonathan and Brian" /></a></p></blockquote> <p>Vital Statistics:</p> <blockquote> <dl> <dt>Weight</dt><dd>7 lbs, 9 oz</dd> <dt>Length</dt><dd>20 inches</dd> </dl> </blockquote> <p>Delivery did <i>not</i> go according to plan. Amber's OBGYN was going on vacation today at noon, so we had originally planned to induce labor on Wednesday. That fell through...because the hospitals were full. They managed to find a room for us on Thursday, so we induced last night. By Friday morning, things had gone "sour" -- Brian's heart rate was lower than the doctors were comfortable with, so Amber underwent an emergency C-section.</p> <p>Aside from events unfolding in an unexpected fashion, Amber and Brian are doing fine.</p> http://www.jprl.com/Blog/archive/life/2007/Dec-21.html Jonathan Pryor (jonpryor@vt.edu) http://www.jprl.com/Blog/archive/life/2007/Dec-21.html Fri, 21 Dec 2007 22:37:00 GMT Random Musings About Spain/Barcelona <p>Some random thoughts that occurred to me while in Barcelona:</p> <ul> <li>The "No Smoking" sign looks more like a "Do Not Enter" sign: <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1726.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1726-web.jpg" title="No Smoking" alt="No Smoking" /></a></p></blockquote> </li> <li>I found it difficult to figure out how to flush some of the toilettes. I realize that there are several different flusher styles, but I wasn't aware there were so many I hadn't come across.</li> <li>Unisex bathrooms! They didn't seem that widespread, and I wonder how soon before I see more in the States: <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1734.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1734-web.jpg" title="Unisex Bathroom Sign" alt="Unisex Bathroom Sign" /></a></p></blockquote> </li> <li>The intersections of roads in Barcelona are "weird." Instead of being a straight right-angle, the corner is "cut," with parking spaces provided in the "cut" area. <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1739.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1739-web.jpg" title="Street Corner Parking" alt="Street Corner Parking" /></a></p></blockquote> </li> <li>I found it incredibly difficult to find the names of roads at intersections. This is probably because I'm not used to looking on the sides of buildings (!), or signs that aren't visible from the corner itself; I frequently couldn't find a road sign at all.</li> <li>The McDonald's calorie information sheets <i>also</i> include alergen information (e.g. <i>does it include wheat?</i>, etc.).</li> <li>Drink prices are...interesting. Either most States in the USA charge a lot for beer (which is true), or Coca Cola is <i>really</i> expensive in Europe; regardless, at many restaurantes 0.2L of Coke had the same price as 0.3L of beer -- 2.35 &euro;. Free water? Forget about it... It's bottled water, and it frequently has the same price.</li> <li>For comparison, I'm used to <i>unlimited</i> fountain drinks for $1.50-$1.95 (free refills!), and free tap water.</li> <li>Light switches are more kid-friendly; they're about three feet from the floor, which is easily within reach of Sarah, as opposed to the ~4.5 feet of the light switches in my home.</li> <li>Why don't the large maps at bus stations, metro stations, etc. have a "You Are Here" sticker? Some do, but most don't, which makes things more difficult if you're completely lost to begin with...</li> </ul> http://www.jprl.com/Blog/archive/life/2007/Sep-24-4.html Jonathan Pryor (jonpryor@vt.edu) http://www.jprl.com/Blog/archive/life/2007/Sep-24-4.html Tue, 25 Sep 2007 01:00:00 GMT OOoCon 2007 Trip: Saturday - Monday <p>Saturday was the "tourist" day; get up early, meet with Shaun, Louis, John, and several others, hike around town:</p> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1743.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1743-web.jpg" title="Outdoor Market." alt="Outdoor Market." /></a></p></blockquote> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1747.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1747-web.jpg" title="Cathedral." alt="Cathedral." /></a></p></blockquote> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1762.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1762-web.jpg" title="Sea Port." alt="Sea Port." /></a></p></blockquote> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1775.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1775-web.jpg" title="Yes, I really did go and I'm not making this up!" alt="Yes, I really did go and I'm not making this up!" /></a></p></blockquote> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1796.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1796-web.jpg" title="Overlooking the port from the Castle." alt="Overlooking the port from the Castle." /></a></p></blockquote> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1813.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1813-web.jpg" title="John and Shaun" alt="John and Shaun" /></a></p></blockquote> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1833.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1833-web.jpg" title="A cathedral under construction for over 130 years..." alt="A cathedral under construction for over 130 years..." /></a></p></blockquote> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1848.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1848-web.jpg" title="Christ looks like a nude cubist piece of art up close." alt="Christ looks like a nude cubist piece of art up close." /></a></p></blockquote> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1855.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1855-web.jpg" title="Beach!" alt="Beach!" /></a></p></blockquote> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1867.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1867-web.jpg" title="More Beach!" alt="More Beach!" /></a></p></blockquote> <p>Sunday I did some actual work (I had a patch written Wednesday, but the wireless access at the University was sufficiently flakey that <tt>cvs diff</tt> never completed), hit the beach again, and started writing these blog entries.</p> <p>Monday was the (long!) flight home, limited work (when will planes get real internet access?), and more blog entries.</p> <p>Mental note: Try to <i>never</i> go through JFK International Airport in New York when returning from an international flight. I had to go through security after going through customs to get on a domestic flight. :-(</p> http://www.jprl.com/Blog/archive/life/2007/Sep-24-3.html Jonathan Pryor (jonpryor@vt.edu) http://www.jprl.com/Blog/archive/life/2007/Sep-24-3.html Tue, 25 Sep 2007 00:00:00 GMT OOoCon 2007 Trip: Wednesday - Friday <p><a href="http://marketing.openoffice.org/ooocon2007/programme/wednesday.html" >Wednesday</a> officially started the conference, with a <a href="http://marketing.openoffice.org/ooocon2007/programme/wednesday_186.pdf" >talk by Louis Suárez-Potts</a>.</p> <p>Then were some excellent presentations on the <a href="http://marketing.openoffice.org/ooocon2007/programme/wednesday_769.pdf" >Aqua port</a> of <a href="http://porting.openoffice.org/mac/">OpenOffice.org</a>, a meetup at the hotel Tuesday night with the Aqua port folks, and Tapas for dinner. Tapas are like appetizers; many restaurants I go to have a "choose 3 appetizers for one price" deal. Tapas are like a la carte appetizer-sized dishes, allowing for a wide variety of foods to be sampled.</p> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1732.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1732-web.jpg" title="Dinner" alt="Dinner" /></a></p></blockquote> <p><a href="http://marketing.openoffice.org/ooocon2007/programme/thursday.html" >Thursday</a> brought chatting with Niklas Nebel, one of Sun's Calc programmers, the <a href="http://marketing.openoffice.org/ooocon2007/programme/thursday_116.pdf" >Chart2 overview</a>, and <a href="http://marketing.openoffice.org/ooocon2007/programme/thursday_100.pdf">OpenGL transitions</a>. The OpenGL presentation mentioned a desire to create a UI that "mere mortals" can use to create new transitions. I wish them luck in this -- it's very difficult to create a UI that non-experts can use that won't enflame the experts (insert Gnome vs. KDE flame war here as a perfect example).</p> <p><a href="http://marketing.openoffice.org/ooocon2007/programme/friday.html" >Friday</a> had a wonderful set of presentations on source code managers, which I <a href="http://www.jprl.com/Blog/archive/life/2007/../development/openoffice.org/Sep-23.html">discussed earlier</a>. For dinner I was supposted to meet up with <a href="http://www.gnome.org/~michael/">Michael Meeks</a>, and sadly got lost instead. Apparently we were on the same road (Catalunya), but since said road is <i>very</i> long I'm not surprised that Shaun and I couldn't find him and his entourage with 30 minutes of walking...</p> http://www.jprl.com/Blog/archive/life/2007/Sep-24-2.html Jonathan Pryor (jonpryor@vt.edu) http://www.jprl.com/Blog/archive/life/2007/Sep-24-2.html Mon, 24 Sep 2007 23:00:00 GMT OOoCon 2007 Trip: Monday - Tuesday <p>The <a href="http://marketing.openoffice.org/ooocon2007/index.html" >OpenOffice.org 2007 Conference</a> officially started on Wednesday, but since I was going for the whole conference I needed to arrive on Tuesday and leave on Saturday. To arrive on Tuesday, I had to leave on Monday, and to get the best flight bargain I'd have to leave on Sunday. Not too bad -- I'd have a day to look around Barcelona.</p> <p>So I dutifully show up ~2 hours early for my flight 3:38 PM flight, and find...that there is no reservation for me. Fun! Apparently something somewhere got screwed up (I still haven't heard what), so the flight arrangements I had made in August were canceled...in August. Oops.</p> <p>Quick phone calls to the travel agency ("what's going on?!") and to my manager got things sorted out in time for the original flight, but with a change in plans; in order to get the cheapest flight, I now would be leaving Barcelona on Monday September 24. This was less than ideal -- it meant that Amber would be alone with Sarah for a day longer than originally planned -- but off I went for my first-ever trip to Spain.</p> <p>After that beginning, the flights were uneventful. (Long and boring, but uneventful. Silly 8-10 hour flights! At least I was able to finish some research into a bug...)</p> <p>When I landed in Barcelona on Tuesday at 11:15 AM, I met up with <a href="http://kohei.us/">Kohei</a>, who was kind enough to wait for me even though he arrived two hours prior. Thanks! We continued to wait around for <a href="http://florianreuter.blogspot.com/">Florian</a> to no avail, because we mis-understood his 12:15 <i>departure</i> time for an <i>arrival</i> time. By 1:30 PM we figured he wouldn't be showing up, so we tried to make our way to the Hotel.</p> <p>That trip was also unexpectedly long, as we had difficulty reading the bus map (can I have a "You Are Here" sticker, please?), and the bus map at the bus stop was truncated, so that we couldn't see the full path of the bus. Long story short, we got off at the wrong place because we didn't realize that the bus would loop around to drop us off at the right place (ugh!), but we quickly hit upon the metro to continue our journy.</p> <p>Long story short: when someone (<a href="http://www.figuiere.net/hub/">hub</a>) is kind enough to provide Metro instructions over IRC, you should probably follow them. :-)</p> <p>Alas, I also failed to do enough pre-planning, as once we got off the metro at the correct stop (according to hub's instructions), we still needed to find the hotel. As the bus stop was ~6 blocks (and a couple turns) away from the metro stop...this was less than ideal. Apparently we looked dazed-and-confused enough that someone walked up and helped us find our location. Much walking followed.</p> <p>So by 4:00 PM we hit the hotel, get settled in, speak with <a href="http://artax.karlin.mff.cuni.cz/~kendy/blog/">kendy</a> about fixing my bug, attend a phone conference for our Novell department, and do the ~40 minute walk from our hotel to the <a href="http://www.ub.edu">Universitat de Barcelona</a> for "dinner" and registration at 7:00 PM (free shirt!). Much talking was had by all.</p> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1714.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1714-web.jpg" title="OpenOffice.org 2007!" alt="OpenOffice.org 2007!" /></a></p></blockquote> http://www.jprl.com/Blog/archive/life/2007/Sep-24-1.html Jonathan Pryor (jonpryor@vt.edu) http://www.jprl.com/Blog/archive/life/2007/Sep-24-1.html Mon, 24 Sep 2007 22:00:00 GMT In Defense Of <tt>git</tt> <p>On <a href="http://marketing.openoffice.org/ooocon2007/programme/friday.html">Friday</a> at the <a href="http://marketing.openoffice.org/ooocon2007/">OpenOffice.org Conference</a>, we had two sessions discussing the future of Source Code Managers in <a href="http://www.openoffice.org">OpenOffice.org</a>: <a href="http://marketing.openoffice.org/ooocon2007/programme/friday_77.pdf" >Child workspaces and the OOo SCM system</a> by Jens-Heiner Rechtien and <a href="http://marketing.openoffice.org/ooocon2007/programme/friday_117.pdf" >git: the Source Code Manager for OOo?</a> by <a href="http://artax.karlin.mff.cuni.cz/~kendy/blog">Jan Holesovsky</a> (kendy).</p> <p>In the Q&amp;A section after the git presentation, there was a lot of heated debate in which it seemed that Jan and Jens were talking "past" each other. As a <a href="http://git.or.cz/">git</a> backer, I thought I'd try to bring some clarity to things.</p> <p>It seemed that Jens has one fundamental problem with <tt>git</tt>, which itself is fundamental to its operation: commits are <i>not</i> transferred to the remote module; instead, you need an explicit <tt>git-push</tt> command to send all local changes to the remote repository. Jens claimed three implications of this (that I remember):</p> <ol> <li><tt>git</tt> did not permit line-by-line authorship information, as with <tt>cvs annotate</tt> or <tt>svn blame</tt>.</li> <li>Developers would not see changes made by other developers as soon as they happen.</li> <li>QA and Release Engineering wouldn't be alerted as soon as developers made <i>any</i> change on any child workspace.</li> </ol> <p>The line-by-line authorship information <i>is</i> possible in <tt>git</tt> with the <tt>git blame</tt> or <tt>git annotate</tt> commands (they are synonyms for each other). I suspect I misinterpreted this part of the debate, as all parties should have known that <tt>git</tt> supported this.</p> <p>Which leaves the other two issues, which (again) are fundamental to <tt>git</tt>: a commit does <i>not</i> send any data to the repository. Thus we get to the title of this blog entry: this is a Good Thing&trade;.</p> <p>Local commits are world changing in a very small way: they're insanely fast, much faster than Subversion. (For example, committing a one-line change to a text file under a Subversion remote directory took me 4.775s; a similar change under <tt>git</tt> is 0.246s -- 19x faster -- and this is a <i>small</i> Subversion module, ~1.5MB, hosted on the ximian.com Subversion repo, which never seems as loaded as the openoffice.org servers.)</p> <p>What can you do when your commits are <i>at least</i> 19x faster? You commit more often. You commit when you <i>save your file</i> (or soon thereafter). You commit when you code is 99.995% <i>guaranteed</i> to be <i>WRONG</i>.</p> <p>Why do this? Because human memory is limited. Most studies show that the average person can remember 7&plusmn;2 items at a time before they start forgetting things. This matters because a single bug may require changes to multiple different files, and even within a single file your memory will be filled with such issues as <i>what's the scope of this variable?</i>, <i>what's the type of this variable?</i>, <i>what's this method </i>do<i>?</i>, <i>what bug am I trying to fix again?</i>, etc. Human short-term memory is very limited.</p> <p>So what's the poor developer to do? Most bugs can be partitioned in some way, e.g. into multiple methods or blocks of code, and each such block/sub-problem is solved sequentially -- you pick one sub-problem, solve it, test it (individually if possible), and continue to the next sub-problem. During this process and when you're finished you'll review the patch (<i>is it formatted nicely?</i>, <i>could this code be cleaned up to be more maintainable?</i>), then <i>finally</i> commit your single patch to the repository. It <i>has</i> to be done this way because if you commit at any earlier point in time, someone else will get your intermediate (untested) changes, and you'll break THEIR code flow. This is obviously bad.</p> <p>During this solve+test cycle, I frequently find that I'll make a set of changes to a file, save it, make other changes, undo them, etc. I <i>never</i> close my file, because (and here's the key point) <tt>cvs diff</tt> shows me too many changes. It'll show me the changes I made yesterday as well as the changes I made 5 minutes ago, and I <i>need</i> to keep those changes separate -- the ones from yesterday (probably) work, the ones from 5 minutes ago (probably) don't, and the only way I can possibly remember which is the set from 5 minutes ago is to hit Undo in my editor and find out. :-)</p> <p>So <tt>git</tt>'s local commits are truly world-changing for me: I can commit something <i>as soon as</i> I have it working for a (<i>small</i>) test case, at which point I can move on to related code and fix <i>that</i> sub-problem, even (especially) if it's a change in the same file. I need an easy way to keep track of which are the solved problems (the stuff I fixed yesterday) and the current problem. I need this primarily because the current problem filled my 7&plusmn;2 memory slots, and I'm unable to <i>easily remember</i> what I did yesterday. (I'm only human! And "easily remember" means "takes less than 0.1s to recall." If you need to <i>think</i> you've already lost.)</p> <p>This is why I think the other two issues -- developers don't see other changes instantly, and neither does QA -- are a non-issue. It's a <i>feature</i>.</p> <p>So let's bring in a well-used analogy to programming: <i>writing a book</i>. You write a paragraph, spell check it, save your document, go onto another paragraph/chapter, repeat for a bit, then review what was written. At any part of this process, you'll be ready to Undo your changes because you changed your mind. Changes may need to occur across the entire manuscript.</p> <p>Remote commits are equivalent to sending each saved manuscript to the author's editor. If someone is going to review/use/depend upon your change, you're going to Damn Well make sure that it Works/is correct before you send that change.</p> <p>Which brings us to the workflow dichotomy between centralized source code managers (<tt>cvs</tt>, <tt>svn</tt>) and distributed managers (<tt>git</tt> et. al). Centralized source managers <i>by design</i> require more developer effort, because the developer needs to manually track all of the individual changes of a larger work/patch before sending it upstream (as described above).</p> <p>Decentralized source managers instead <i>help</i> the developer with the tedious effort of tracking individual changes, because the developer can commit without those changes being seen/used by anyone else. The commit instead gets sent when the developer is done with the feature.</p> <p><i>This</i> is why I prefer <tt>git</tt> to Subversion. <tt>git</tt> allows me to easily work with my 7&plusmn;2 short-term memory limitations, by allowing me to commit "probably working but not fully tested" code so that I don't need to review those changes at the next <tt>cvs diff</tt> for the current problem I'm working on.</p> http://www.jprl.com/Blog/archive/development/openoffice.org/2007/Sep-23.html Jonathan Pryor (jonpryor@vt.edu) http://www.jprl.com/Blog/archive/development/openoffice.org/2007/Sep-23.html Sun, 23 Sep 2007 04:06:00 GMT Yet Another Random Update... <p>By parental request, more images of Sarah...</p> <p>Around April, we started setting up a swing set for Sarah:</p> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1186.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1186-web.jpg" title="Sarah studying a branch." alt="Sarah studying a branch." /></a></p></blockquote> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1187.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1187-web.jpg" title="Jon preparing to put in a stud." alt="Jon preparing to put in a stud." /></a></p></blockquote> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1189.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1189-web.jpg" title="Sarah wants to help." alt="Sarah wants to help." /></a></p></blockquote> <p>Of course, play areas need to be filled with mulch:</p> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1199.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1199-web.jpg" title="Mulch." alt="Mulch." /></a></p></blockquote> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1201.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1201-web.jpg" title="Mulch in Play Area." alt="Mulch in Play Area." /></a></p></blockquote> <p>Unfortunately our back yard isn't level, so some digging was necessary to ensure that the play set was level:</p> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1227.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1227-web.jpg" title="Ditch for Swingset." alt="Ditch for Swingset." /></a></p></blockquote> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1228.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1228-web.jpg" title="Swingset." alt="Swingset." /></a></p></blockquote> <p>Which was completed just in time for my parents to visit, necessating...a trip to Busch Gardens:</p> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1229.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1229-web.jpg" title="Sarah in Airplane." alt="Sarah in Airplane." /></a></p></blockquote> <p>A trip to Maymont Park:</p> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1367.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1367-web.jpg" title="Sarah, Jon, Chris." alt="Sarah, Jon, Chris." /></a></p></blockquote> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1411.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1411-web.jpg" title="Amber, Sarah, Jon." alt="Amber, Sarah, Jon." /></a></p></blockquote> <p>Sarah likes to help with chores:</p> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1422.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1422-web.jpg" title="Sarah and Vacuum." alt="Sarah and Vacuum." /></a></p></blockquote> <p>Sarah still needs her naps...</p> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1448.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1448-web.jpg" title="Sarah napping in car." alt="Sarah napping in car." /></a></p></blockquote> <p>...Especially when we went to Chicago for July 4th to visit family, and an impromptu baby shower:</p> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1504.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1504-web.jpg" title="Sarah, Doll, Chaka." alt="Sarah, Doll, Chaka." /></a></p></blockquote> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1531.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1531-web.jpg" title="Sarah and lots of toys." alt="Sarah and lots of toys." /></a></p></blockquote> <p>And an unfortunate side trip to the hospital:</p> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1538.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1538-web.jpg" title="Sarah on Jon" alt="Sarah on Jon" /></a></p></blockquote> <p>The unfortunate trip was due to a fall on an escalator, causing Sarah to loser her pinky nail. (Ouch!) I freaked out more than Sarah, initially. We found out ~1.5 weeks after returning home that this was a <i>good</i> thing, as there were many incidents of <i>food poisening</i> at some food stands my parents hit (and we would have hit if not for the hospital).</p> <p>A Zoo Trip:</p> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1550.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1550-web.jpg" title="Amber &amp; Sarah." alt="Amber &amp; Sarah." /></a></p></blockquote> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1557.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1557-web.jpg" title="Sarah in Kangaroo." alt="Sarah in Kangaroo." /></a></p></blockquote> <p>4th of July, Sarah meets my cousins:</p> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1649.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1649-web.jpg" title="Kelcie, Kyle, Sarah." alt="Kelcie, Kyle, Sarah." /></a></p></blockquote> <p>More recently, we can relax:</p> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1693.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1693-web.jpg" title="Jon &amp; Sarah." alt="Jon &amp; Sarah." /></a></p></blockquote> <p>Also, after many years of poor health, our oldest cat Bodhi died. To keep Arthur company, we got a new cat last Saturday, Gwen:</p> <blockquote><p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1702.jpg"><img src="http://www.jprl.com/Blog/archive/life/2007/100_1702-web.jpg" title="Gwen" alt="Gwen" /></a></p></blockquote> http://www.jprl.com/Blog/archive/life/2007/Sep-03.html Jonathan Pryor (jonpryor@vt.edu) http://www.jprl.com/Blog/archive/life/2007/Sep-03.html Mon, 03 Sep 2007 23:04:00 GMT Comparing Java and C# Generics <p><i>Or, What's Wrong With Java Generics?</i></p> <h3 id="jcs-intro">What Are Generics</h3> <p>Java 5.0 and C# 2.0 have both added Generics, which permit a multitude of things:</p> <ol> <li>Improved compiler-assisted checking of types.</li> <li>Removal of casts from source code (due to (1)).</li> <li>In C#, performance advantages (discussed later).</li> </ol> <p>This allows you to replace the error-prone Java code:</p> <blockquote><pre class="code-csharp"> List list = new ArrayList (); list.add ("foo"); list.add (new Integer (42)); // added by "mistake" for (Iterator i = list.iterator (); i.hasNext (); ) { String s = (String) i.next (); // ClassCastException for Integer -&gt; String // work on `s' System.out.println (s); }</pre></blockquote> <p>with the compiler-checked code:</p> <blockquote><pre class="code-csharp"> // constructed generic type List&lt;String&gt; list = new ArrayList&lt;String&gt; (); list.add ("foo"); list.add (42); // error: cannot find symbol: method add(int) for (String s : list) System.out.println (s);</pre></blockquote> <p>The C# equivalent code is nigh identical:</p> <blockquote><pre class="code-csharp"> IList&lt;string&gt; list = new List&lt;string&gt; (); list.Add ("foo"); list.Add (42); // error CS1503: Cannot convert from `int' to `string' foreach (string s in list) Console.WriteLine (s);</pre></blockquote> <h3 id="jcs-terminology">Terminology</h3> <p>A <i>Generic Type</i> is a type (<b>class</b>es and <b>interface</b>s in Java and C#, as well as <b>delegate</b>s and <b>struct</b>s in C#) that accepts <i>Generic Type Parameters</i>. A <i>Constructed Generic Type</i> is a Generic Type with <i>Generic Type Arguments</i>, which are Types to actually use in place of the Generic Type Parameters within the context of the Generic Type.</p> <p>For simple generic types, Java and C# have identical syntax for declaring and using Generic Types:</p> <blockquote><pre class="code-csharp"> class GenericClass&lt;TypeParameter1, TypeParameter2&gt; { public static void Demo () { GenericClass&lt;String, Object&gt; c = new GenericClass&lt;String, Object&gt; (); } }</pre></blockquote> <p>In the above, <tt>GenericClass</tt> is a Generic Type, <tt>TypeParameter1</tt> and <tt>TypeParameter2</tt> are Generic Type Parameters for <tt>GenericClass</tt>, and <tt>GenericClass&lt;String, Object&gt;</tt> is a Constructed Generic Type with <tt>String</tt> as a Generic Type Argument for the <tt>TypeParameter1</tt> Generic Type Parameter, and <tt>Object</tt> as the Generic Type Argument for the <tt>TypeParameter2</tt> Generic Type Parameter.</p> <p>It is an error in C# to create a Generic Type without providing any Type Arguments. Java permits creating Generic Types without providing any Type Arguments; these are called <i>raw types</i>:</p> <blockquote><pre class="code-csharp"> Map rawMap = new HashMap &lt;String, String&gt; ();</pre></blockquote> <p>Java also permits you to leave out Generic Type Arguments from the right-hand-side. Both raw types and skipping Generic Type Arguments elicit a compiler warning:</p> <blockquote><pre class="code-csharp"> Map&lt;String, String&gt; correct = new HashMap&lt;String, String&gt; (); // no warning, lhs matches rhs Map&lt;String, String&gt; incorrect = new HashMap (); // lhs doesn't match rhs; generates the warning: // Note: gen.java uses unchecked or unsafe operations. // Note: Recompile with -Xlint:unchecked for details.</pre></blockquote> <p>Compiling the above Java code with -Xlint:unchecked produces:</p> <blockquote><pre> gen.java:9: warning: [unchecked] unchecked conversion found : java.util.HashMap required: java.util.Map&lt;java.lang.String,java.lang.String&gt; Map&lt;String, String&gt; incorrect = new HashMap ();</pre></blockquote> <p>Note that all "suspicious" code produces warnings, <i>not</i> errors, under Java. Only provably wrong code generate compiler errors (such as adding an <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Integer.html">Integer</a> to a <tt><a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/List.html" >List</a>&lt;String&gt;</tt>).</p> <p>(Also note that "suspicious" code <i>includes</i> Java &lt;= 1.4-style use of collections, i.e. <i>all collections code that predates Java 5.0</i>. This means that you get <i>lots</i> of warnings when migrating Java &lt;= 1.4 code to Java 5.0 and specifying <tt>-Xlint:unchecked</tt>.)</p> <p>Aside from the new use of `<tt>&lt;</tt>', `<tt>&gt;</tt>', and type names within constructed generic type names, the use of generic types is essentially identical to the use of non-generic types, though <a href="#jcs-java-method-constraints">Java has some extra flexibility when declaring variables</a>.</p> <p>Java has one added wrinkle as well: static methods of generic classes <i>cannot</i> reference the type parameters of their enclosing generic class. C# does not have this limitation:</p> <blockquote><pre class="code-csharp"> class GenericClass&lt;T&gt; { public static void UseGenericParameter (T t) {} // error: non-static class T cannot be // referenced from a static context } class Usage { public static void UseStaticMethod () { // Valid C#, not valid Java GenericClass&lt;int&gt;.UseGenericParameter (42); } }</pre></blockquote> <h3 id="jcs-generic-methods">Generic Methods</h3> <p>Java and C# both support generic methods, in which a (static or instance) method itself accepts generic type parameters, though they differ in where the generic type parameters are declared. Java places the generic type parameters before the method return type:</p> <blockquote><pre class="code-csharp"> class NonGenericClass { public static &lt;T&gt; T max (T a, T b) {/*...*/} }</pre></blockquote> <p>while C# places them after the method name:</p> <blockquote><pre class="code-csharp"> class NonGenericClass { static T Max&lt;T&gt; (T a, T b) {/*...*/} }</pre></blockquote> <p>Generic methods may exist on both generic- and non-generic classes <i>and</i> interfaces.</p> <h3 id="jcs-constraints">Constraints</h3> <p>What can you do with those Generic Type Parameters within the class or method body? Not much:</p> <ul> <li>Declare variables using the generic type parameter in most nested scopes (e.g. instance class member, method parameter, local variable).</li> <li>Invoke methods that exist on <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html" >java.lang.Object</a> (Java) or <a href="http://www.go-mono.com/docs/index.aspx?tlink=11@ecma%3a131%23Object%2f" >System.Object</a> (C#).</li> <li>Assign the <i>default value</i> to variables with the generic parameter type. The default value is <b>null</b> in Java, and <b>default(</b><i><tt>Generic Type Parameter</tt></i><b>)</b> in C#. (C# requires this syntax because <b>null</b> isn't a valid value for value types such as <b>int</b>.)</li> </ul> <blockquote><pre class="code-csharp"> class GenericJavaClass&lt;T&gt; { T[] arrayMember = null; T singleMember = null; public static void Demo () { T localVariable = 42; // error T localVariable2 = null; AcceptGenericTypeParameter (localVariable); } public static void AcceptGenericTypeParameter (T t) { System.out.println (t.toString ()); // ok System.out.println (t.intValue ()); // error: cannot find symbol } } class GenericCSharpClass&lt;T&gt; { T[] arrayMember = null; T singleMember = default(T); public static void Demo () { T localVariable = 42; // error T localVariable2 = default(T); AcceptGenericTypeParameter (localVariable); } public static void AcceptGenericTypeParameter (T t) { System.out.println (t.ToString ()); // ok System.out.println (t.GetTypeCode ()); // error: cannot find symbol } }</pre></blockquote> <p>So how do we call non-<tt>Object</tt> methods on objects of a generic type parameter?</p> <ol> <li>Cast the variable to a type that has the method you want (and accept the potentially resulting cast-related exceptions).</li> <li>Place a <i>constraint</i> on the generic type parameter. A constraint is a compile-time assertion that the generic type argument will fulfill certain obligations. Such obligations include the base class of the generic type argument, any implemented interfaces of the generic type argument, and (in C#) whether the generic type argument's type has a default constructor, is a value type, or a reference type.</li> </ol> <h4 id="jcs-java-type-constraints">Java Type Constraints</h4> <p>Java type and method constraints are specified using a "mini expression language" within the `<tt>&lt;</tt>' and `<tt>&gt;</tt>' declaring the generic type parameters. For each type parameter that has constraints, the syntax is:</p> <blockquote><tt>TypeParameter ListOfConstraints</tt></blockquote> <p>Where <tt>ListOfConstraints</tt> is a `<tt>&amp;</tt>'-separated list of one of the following constraints:</p> <ul> <li>Specifying a base class or implemented interface on the Generic Type Argument by using: <tt><b>extends</b> <i>BaseOrInterfaceType</i></tt></li> </ul> <p>(`<tt>&amp;</tt>' must be used instead of `<tt>,</tt>' because `<tt>,</tt>' separates each generic type parameter.)</p> <p id="jcs-java-Demo.copy">The above constraints also apply to methods, and methods can use some <a href="#jcs-java-method-constraints">additional constraints described below</a>.</p> <blockquote id=""><pre class="code-csharp"> class GenericClass&lt;T extends Number &amp; Comparable&lt;T&gt;&gt; { void print (T t) { System.out.println (t.intValue ()); // OK } } class Demo { static &lt;U, T extends U&gt; void copy (List&lt;T&gt; source, List&lt;U&gt; dest) { for (T t : source) dest.add (t); } static void main (String[] args) { new GenericClass&lt;Integer&gt;().print (42); // OK: Integer extends Number new GenericClass&lt;Double&gt;().print (3.14159); // OK: Double extends Number new GenericClass&lt;String&gt;().print ("string"); // error: &lt;T&gt;print(T) in gen cannot be applied // to (java.lang.String) ArrayList&lt;Integer&gt; ints = new ArrayList&lt;Integer&gt; (); Collections.addAll (ints, 1, 2, 3); copy (ints, new ArrayList&lt;Object&gt; ()); // OK; Integer inherits from Object copy (ints, new ArrayList&lt;String&gt; ()); // error: &lt;U,T&gt;copy(java.util.List&lt;T&gt;, // java.util.List&lt;U&gt;) in cv cannot be // applied to (java.util.ArrayList&lt;java.lang.Integer&gt;, // java.util.ArrayList&lt;java.lang.String&gt;) } }</pre></blockquote> <h4 id="jcs-csharp-constraints">C# Constraints</h4> <p>C# generic type parameter constraints are specified with the context-sensitive <b>where</b> keyword, which is placed after the class name or after the method's closing `<tt>)</tt>'. For each type parameter that has constraints, the syntax is:</p> <blockquote> <tt><b>where</b> TypeParameter : ListOfConstraints</tt> </blockquote> <p>Where <tt>ListOfConstraints</tt> is a comma-separated list of one of the following constraints:</p> <ul> <li>Specifying inheritance relationships, such as a mandatory base class or interface by listing the type name or another generic type parameter.</li> <li>Requiring that the type argument be a value type by specifying <b>struct</b>.</li> <li>Requiring that the type argument be a reference type by using <b>class</b>.</li> <li>Requiring that the type argument provide a default constructor by using <b>new()</b>.</li> </ul> <blockquote><pre class="code-csharp"> class GenericClass&lt;T&gt; : IComparable&lt;GenericClass&lt;T&gt;&gt; where T : IComparable&lt;T&gt; { private GenericClass () {} void Print (T t) { Console.WriteLine (t.CompareTo (t)); // OK; T must implement IComparable&lt;T&gt; } public int CompareTo (GenericClass&lt;T&gt; other) { return 0; } } class Demo { static void OnlyValueTypes&lt;T&gt; (T t) where T : struct { } static void OnlyReferenceTypes&lt;T&gt; (T t) where T : class { } static void Copy&lt;T, U&gt; (IEnumerable&lt;T&gt; source, ICollection&lt;U&gt; dest) where T : U, IComparable&lt;T&gt;, new() where U : new() { foreach (T t in source) dest.Add (t); } static T CreateInstance&lt;T&gt; () where T : new() { return new T(); } public static void Main (String[] args) { new GenericClass&lt;int&gt;.Print (42); // OK: Int32 implements IComparable&lt;int&gt; new GenericClass&lt;double&gt;.Print (3.14159); // OK: Double implements IComparable&lt;double&gt; new GenericClass&lt;TimeZone&gt;.Print ( TimeZone.CurrentTimeZone); // error: TimeZone doesn't implement // IComparable&lt;TimeZone&gt; OnlyValueTypes (42); // OK: int is a struct OnlyValueTypes ("42"); // error: string is a reference type OnlyReferenceTypes (42); // error: int is a struct OnlyReferenceTypes ("42"); // OK CreateInstance&lt;int&gt; (); // OK; int has default constructor CreateInstance&lt;GenericClass&lt;int&gt;&gt; (); // error CS0310: The type `GenericClass&lt;int&gt;' // must have a public parameterless constructor // in order to use it as parameter `T' in the // generic type or method // `Test.CreateInstance&lt;T&gt;()' // In theory, you could do `Copy' instead of // `Copy&lt;...&gt;' below, but it depends on the // type inferencing capabilities of your compiler. Copy&lt;int,object&gt; (new int[]{1, 2, 3}, new List&lt;object&gt; ()); // OK: implicit int -> object conversion exists. Copy&lt;int,AppDomain&gt; (new int[]{1, 2, 3}, new List&lt;AppDomain&gt; ()); // error CS0309: The type `int' must be // convertible to `System.AppDomain' in order // to use it as parameter `T' in the generic // type or method `Test.Copy&lt;T,U&gt;( // System.Collections.Generic.IEnumerable&lt;T&gt;, // System.Collections.Generic.ICollection&lt;U&gt;)' } }</pre></blockquote> <h3 id="jcs-java-method-constraints">Java Wildcards (Java Method Constraints)</h3> <p>Java has additional support for covarient- and contravariant generic types on method declarations.</p> <p>By default, you cannot assign an instance of one constructed generic type to an instance of another generic type where the generic type arguments differ:</p> <blockquote><pre class="code-csharp"> // Java, though s/ArrayList/List/ for C# List&lt;String&gt; stringList = new ArrayList&lt;String&gt; (); List&lt;Object&gt; objectList = stringList; // error</pre></blockquote> <p>The reason for this is quite obvious with a little thought: if the above were permitted, you could violate the type system:</p> <blockquote><pre class="code-csharp"> // Assume above... stringList.add ("a string"); objectList.add (new Object ()); // and now `stringList' contains a non-String object!</pre></blockquote> <p>This way leads madness and <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/ClassCastException.html" >ClassCastException</a>s. :-)</p> <p>However, sometimes you want the flexibility of having different generic type arguments:</p> <blockquote><pre class="code-csharp"> static void cat (Collection&lt;Reader&gt; sources) throws IOException { for (Reader r : sources) { int c; while ((c = r.read()) != -1) System.out.print ((char) c); } }</pre></blockquote> <p>Many types implement <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/io/Reader.html">Reader</a>, e.g. <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/io/StringReader.html" >StringReader</a> and <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/io/FileReader.html" >FileReader</a>, so we might <i>want</i> to do this:</p> <blockquote><pre class="code-csharp"> Collection&lt;StringReader&gt; sources = new Collection&lt;StringReader&gt; (); Collections.addAll (sources, new StringReader ("foo"), new StringReader ("bar")); cat (sources); // error: cat(java.util.Collection&lt;java.io.Reader&gt;) // in gen cannot be applied to // (java.util.Collection&lt;java.io.StringReader&gt;)</pre></blockquote> <p>There are two ways to make this work:</p> <ol> <li>use <tt>Collection&lt;Reader&gt;</tt> instead of <tt>Collection&lt;StringReader&gt;</tt>: <blockquote><pre class="code-csharp"> Collection&lt;Reader&gt; sources = new Collection&lt;Reader&gt; (); Collections.addAll (sources, new StringReader ("foo"), new StringReader ("bar")); cat (sources);</pre></blockquote> </li> <li>Use <i>wildcards</i>.</li> </ol> <h4 id="jcs-unbounded-wildcards">Unbounded Wildcards</h4> <p>If you don't care about the specific generic type arguments involved, you can use `<tt>?</tt>' as the type parameter. This is an <i>unbounded wildcard</i>, because the `<tt>?</tt>' can represent anything:</p> <blockquote><pre class="code-csharp"> static void printAll (Collection&lt;?&gt; c) { for (Object o : c) System.out.println (o); }</pre></blockquote> <p>The primary utility of unbounded wildcards is to migrate pre-Java 5.0 collection uses to Java 5.0 collections (thus removing the probably <i>thousands</i> of warnings <tt>-Xlint:unchecked</tt> produces) in the easiest manner.</p> <p>This obviously won't help for <tt>cat</tt> (above), but it's also possible to "bind" the wildcard, to create a <i>bounded wildcard</i>.</p> <h4 id="jcs-bounded-wildcards">Bounded Wildcards</h4> <p>You create a <i>bounded wildcard</i> by binding an upper- or lower- bound to an unbounded wildcard. Upper bounds are specified via <b>extends</b>, while lower bounds are specified via <b>super</b>. Thus, to allow a <tt>Collection</tt> parameter that accepts <tt>Reader</tt> instances or any type that derives from <tt>Reader</tt>:</p> <blockquote><pre class="code-csharp"> static void cat (Collection&lt;? extends Reader&gt; c) throws IOException { /* as before */ }</pre></blockquote> <p>This permits the more desirable use:</p> <blockquote><pre class="code-csharp"> Collection&lt;StringReader&gt; sources = new Collection&lt;StringReader&gt; (); Collections.addAll (sources, new StringReader ("foo"), new StringReader ("bar")); cat (sources);</pre></blockquote> <p>Bounded wildcards also allow you to reduce the number of generic parameters you might otherwise want/need a generic method; compare this <tt>Demo.copy</tt> to <a href="#jcs-java-Demo.copy">the previous Java <tt>Demo.copy</tt></a> implementation:</p> <blockquote><pre class="code-csharp"> class Demo { static &lt;T&gt; void copy (List&lt;? extends T&gt; source, List&lt;? super T&gt; dest) { for (T t : source) dest.add (t); } }</pre></blockquote> <h4 id="jcs-csharp-wildcards">C# Equivalents</h4> <p>C# has no direct support for bounded or unbounded wildcards, and thus doesn't permit declaring class- or method-level variables that make use of them. However, if you can make the class/method itself generic, you can create equivalent functionality.</p> <p>A Java method taking an unbounded wildcard would be mapped to a <i>generic</i> C# method with one generic type parameter for each unbound variable within the Java method:</p> <blockquote><pre class="code-csharp"> static void PrintAll&lt;T&gt; (IEnumerable&lt;T&gt; list) { foreach (T t in list) { Console.WriteLine (t); } }</pre></blockquote> <p>This permits working with any type of <a href="http://msdn2.microsoft.com/en-us/library/9eekhta0.aspx" >IEnumerable&lt;T&gt;</a>, e.g. <tt><a href="http://msdn2.microsoft.com/en-us/library/6sh2ey19.aspx" >List</a>&lt;int&gt;</tt> and <tt>List&lt;string&gt;.</tt></p> <p>A Java method taking an upper bounded wildcard can be mapped to a <i>generic</i> C# method with one generic type parameter for each bound variable, then using a derivation constraint on the type parameter:</p> <blockquote><pre class="code-csharp"> static void Cat&lt;T&gt; (IList&lt;T&gt; sources) where T : Stream { for (Stream s : sources) { int c; while ((c = r.ReadByte ()) != -1) Console.Write ((char) c); } }</pre></blockquote> <p>A Java method taking a lower bounded wildcard can be mapped to a <i>generic</i> C# method taking <i>two</i> generic type parameters for each bound variable (one is the actual type you care about, and the other is the super type), then using a derivation constraint between your type variables:</p> <blockquote><pre class="code-csharp"> static void Copy&lt;T,U&gt; (IEnumerable&lt;T&gt; source, ICollection&lt;U&gt; dest) where T : U { foreach (T t in source) dest.Add (t); }</pre></blockquote> <h3 id="jcs-implementation">Generics Implementation</h3> <p>How Java and C# implement generics has a significant impact on what generics code can do and what can be done at runtime.</p> <h4 id="jcs-java-implementation">Java Implementation</h4> <p>Java Generics were <i>originally</i> designed so that the <tt>.class</tt> file format wouldn't need to be changed. This would have meant that Generics-using code could run unchanged on JDK 1.4.0 and earlier JDK versions.</p> <p>However, the <tt>.class</tt> file format had to change <i>anyway</i> (for example, generics permits you to overload methods based solely on return type), but they didn't revisit the design of Java Generics, so Java Generics remains a <i>compile-time</i> feature based on <i>Type Erasure</i>.</p> <p>Sadly, you need to know what type erasure is in order to actually write much generics code.</p> <p>With Type Erasure, the compiler transforms your code in the following manner:</p> <ol> <li>Generic types (classes and interfaces) retain the same name, so you cannot have a generic class <tt>Foo</tt> and a non-generic <tt>Foo&lt;T&gt;</tt> in the same package -- these are the <i>same type</i>. This is the <i>raw type</i>.</li> <li>All instances of generic types become their corresponding raw type. So a <tt>List&lt;String&gt;</tt> becomes a <tt>List</tt>. (Thus all "nested" uses of generic type parameters -- in which the generic type parameter is used as a generic type argument of another generic type -- are "erased".)</li> <li>All instances of generic type parameters in both class and method scope become instances of their <i>closest matching type</i>: <ul> <li>If the generic type parameter has an <b>extends</b> constraint, then instances of the generic type parameter become instances of the specified type.</li> <li>Otherwise, <tt>java.lang.Object</tt> is used.</li> </ul> </li> <li>Generic methods also retain the same name, and thus there cannot be any overloading of methods between those using generic type parameters (after the above translations have occurred) and methods <i>not</i> using generic type parameters (see below for example).</li> <li>Runtime casts are inserted by the compiler to ensure that the runtime types are what you think they are. This means that there is runtime casting that you cannot see (the compiler inserts the casts), and thus generics confer no performance benefit over non-generics code.</li> </ol> <p>For example, the following generics class:</p> <blockquote><pre class="code-csharp"> class GenericClass&lt;T, U extends Number&gt; { T tMember; U uMember; public T getFirst (List&lt;T&gt; list) { return list.get (0); } // in bytecode, this is overloading based on return type public U getFirst (List&lt;U&gt; list) { return list.get (0); } // // This would be an error -- doesn't use generic type parameters // and has same raw argument list as above two methods: // // public Object getFirst (List list) { // return list.get (0); // } // public void printAll (List&lt;U&gt; list) { for (U u : list) { System.out.println (u); } } }</pre></blockquote> <p>Is translated by the compiler into the equivalent Java type:</p> <blockquote><pre class="code-csharp"> class GenericClass { Object tMember; Number uMember; // as `U extends Number' public Object getFirst (List list) { return list.get (0); } public Number getFirst (List list) { // note cast inserted by compiler return (Number) list.get (0); } public void printAll (List list) { for (Iterator i=list.iterator (); i.hasNext (); ) { // note cast inserted by compiler Number u = (Number) i.next (); System.out.println (u); } } }</pre></blockquote> <h4 id="jcs-cs-implementation">.NET Implementation</h4> <p>.NET adds a number of new instructions to its intermediate language to support generics. Consequently generics code cannot be directly used by languages that do not understand generics, though many generic .NET types also implement the older non-generic interfaces so that non-generic languages can still use generic types, if not directly.</p> <p>The extension of IL to support generics permits type-specific code generation. Generic types and methods can be constructed over both reference (<b>class</b>es, <b>delegate</b>s, <b>interface</b>s) and value types (<b>struct</b>s, <b>enum</b>erations).</p> <p>Under .NET, there will be only one "instantiation" (JIT-time code generation) of a class which will be used for all reference types. (This can be done because (1) all reference types have the same representation as local variables/class fields, a pointer, and (2) generics code has a different calling convention in which additional arguments are implicitly passed to methods to permit runtime type operations.) Consequently, a <tt>List&lt;string&gt;</tt> and a <tt>List&lt;object&gt;</tt> will share JIT code.</p> <p>No additional implicit casting is necessary for this code sharing, as the IL verifier will prevent violation of the type system. It is <i>not</i> Java Type Erasure.</p> <p>Value types will always get a new JIT-time instantiation, as the sizes of value types will differ. Consequently, <tt>List&lt;int&gt;</tt> and <tt>List&lt;short&gt;</tt> will <i>not</i> share JIT code.</p> <p>Currently, Mono will always generate new instantiations for generic types, for both value and reference types (i.e. JIT code is <i>never</i> shared). This may change in the future, and will have no impact on source code/IL. (It will impact runtime performance, as more memory will be used.)</p> <p>However, there are still some translations performed by the compiler, These translations have been standardized for Common Language Subset use, though these specific changes are not required:</p> <ul> <li><p>The <i>actual</i> type name for generic types is the original type name, followed by `<tt>`</tt>' and the number of generic type parameters. Thus <tt>List&lt;T&gt;</tt> has the IL name <tt>List`1</tt>. This allows multiple different generic types to share the same name as long as they have a different number of generic type parameters, e.g. you can have the types <tt>Foo</tt>, <tt>Foo&lt;T&gt;</tt>, and <tt>Foo&lt;T,U&gt;</tt> all in the same namespace.</p> <p>This impacts type lookup through reflection: <tt>Type.GetType("System.Collections.Generic.List")</tt> will fail, while <tt>Type.GetType("System.Collections.Generic.List`1")</tt> works.</p></li> <li>The <i>actual</i> method name for generic methods is unchanged, though in XML Documentation purposes it is modified to have `<tt>``</tt>' and the number of generic type parameters appended to the method name.</li> </ul> <h3 id="jcs-runtime">Runtime Environment</h3> <p>Generics implementations may have some additional runtime support.</p> <h4 id="jcs-java-runtime">Java Runtime Environment</h4> <p>Java generics are a completely compile-time construct. You cannot do anything with generic type parameters that rely in any way on runtime information. This includes:</p> <ul> <li>Creating instances of generic type parameters.</li> <li>Creating arrays of generic type parameters.</li> <li>Quering the runtime class of a generic type parameter.</li> <li>Using <b>instanceof</b> with generic type parameters.</li> </ul> <p>In short, all of the following produce compiler errors in Java:</p> <blockquote><pre class="code-csharp"> static &lt;T&gt; void genericMethod (T t) { T newInstance = new T (); // error: type creation T[] array = new T [0]; // error: array creation Class c = T.class; // error: Class querying List&lt;T&gt; list = new ArrayList&lt;T&gt; (); if (list instanceof List&lt;String&gt;) {} // error: illegal generic type for instanceof }</pre></blockquote> <h5 id="jcs-java-arrays">Array Usage</h5> <p>The above has some interesting implications on your code. For example, how would you create your own type-safe collection (i.e. how is <tt>ArrayList&lt;T&gt;</tt> implemented)?</p> <p>By <i>accepting</i> the unchecked warning -- <b>you cannot remove the warning</b>. Fortunately you'll only see the warning when you compile your class, and users of your class won't see the unchecked warnings within your code. There are two ways to do it, the horribly unsafe way and the safe way.</p> <p>The horribly unsafe way works for simple cases:</p> <blockquote><pre class="code-csharp"> static &lt;T&gt; T[] unsafeCreateArray (T type, int size) { return (T[]) new Object [size]; }</pre></blockquote> <p>This seems to work for typical generics code:</p> <blockquote><pre class="code-csharp"> static &lt;T&gt; void seemsToWork (T t) { T[] array = unsafeCreateArray (t, 10); array [0] = t; }</pre></blockquote> <p>But it fails horribly if you ever need to use a non-generic type:</p> <blockquote><pre class="code-csharp"> static void failsHorribly () { String[] array = unsafeCreateArray ((String) null, 10); // runtime error: ClassCastException }</pre></blockquote> <p>The above works if you can guarantee that the created array will <i>never</i> be cast to a non-<tt>Object</tt> array type, so it's useful in some limited contexts (e.g. implementing <tt>java.util.ArrayList</tt>), but that's the extent of it.</p> <p>If you need to create the actual runtime array type, you need to use <tt>java.lang.reflect.Array.newInstance</tt> and <tt>java.lang.Class&lt;T&gt;</tt>:</p> <blockquote><pre class="code-csharp"> static &lt;T&gt; T[] safeCreateArray (Class&lt;T&gt; c, int size) { return (T[])java.lang.reflect.Array.newInstance(c,size); } static void actuallyWorks () { String[] a1 = safeCreateArray(String.class, 10); }</pre></blockquote> <p>Note that this <i>still</i> generates a warning by the compiler, but no runtime exception will occur.</p> <h4 id="jcs-csharp-runtime">C# Runtime Environment</h4> <p>.NET provides extensive runtime support for generics code, permitting you to do everything that Java doesn't:</p> <blockquote><pre class="code-csharp"> static void GenericMethod&lt;T&gt; (T t) where T : new() { T newInstance = new T (); // OK - new() constraint. T[] array = new T [0]; // OK Type type = typeof(T); // OK List&lt;T&gt; list = new List&lt;T&gt; (); if (list is List&lt;String&gt;) {} // OK }</pre></blockquote> <p>C# also has extensive support for querying generic information at runtime via <tt>System.Reflection</tt>, such as with <tt>System.Type.GetGenericArguments()</tt>.</p> <p>What C# doesn't support is non-default constructor declaration, non-interface or base-type method declaration, and static method declaration. Since operator overloading is based on static methods, this means that you cannot generically use arithmetic unless you introduce your own interface to perform arithmetic:</p> <blockquote><pre class="code-csharp"> // This is what I'd like: class Desirable // NOT C# { public static T Add&lt;T&gt; (T a, T b) where T : .op_Addition(T,T) { return a + b; } } // And this is what we currently need to do: interface IArithmeticOperations&lt;T&gt; { T Add (T a, T b); // ... } class Undesirable { public static T Add&lt;T&gt; (IArithmeticOperations&lt;T&gt; ops, T a, T b) { return ops.Add (a, b); } }</pre></blockquote> <h3 id="jcs-summary">Summary</h3> <p>The generics capabilities in Java and .NET differ significantly. Syntax wise, Java and C# generics initially look quite similar, and share similar concepts such as constraints. The <i>semantics</i> of generics is where they differ most, with .NET permitting full runtime introspection of generic types and generic type parameters in ways that are obvious in their utility (instance creation, array creation, performance benefits for value types due to lack of boxing) and completely lacking in Java.</p> <p>In short, all that Java generics permit is greater type safety with no new capabilities, with an implementation that permits blatant violation of the type system with nothing more than warnings:</p> <blockquote><pre class="code-csharp"> List&lt;String&gt; stringList = new ArrayList&lt;String&gt; (); List rawList = stringList; // only triggers a warning List&lt;Object&gt; objectList = rawList; // only triggers a warning objectList.add (new Object ()); for (String s : stringList) System.out.println (s); // runtime error: ClassCastException due to Object. </pre></blockquote> <p>This leads to the recommendation that you remove all warnings from your code, but if you try to do anything non-trivial (apparently typesafe arrays is non-trivial), you get into scenarios where you <i>cannot</i> remove all warnings.</p> <p>Contrast this with C#/.NET, where the above code isn't possible, as there are no raw types, and converting a <tt>List&lt;string&gt;</tt> to a <tt>List&lt;object&gt;</tt> would (1) require an explicit cast (as opposed to the complete lack of casts in the above Java code), and (2) generate an <tt>InvalidCastException</tt> at runtime from the explicit cast.</p> <p>Furthermore, C#/.NET convey additional performance benefits due to the lack of required casts (as the verifier ensures everything is kosher) and support for value types (Java generics don't work with the builtin types like <tt>int</tt>), thus removing the overhead of boxing, and C# permits faster, more elegant, more understandable, and more maintainable code.</p> <h3 id="jcs-links">Links</h3> <ul> <li><a href="http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html" >http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html</a></li> <li><a href="http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf" >http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf</a></li> <li><a href="http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.pdf" >http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.pdf</a></li> <li><a href="http://tromey.com/blog/?p=297">http://tromey.com/blog/?p=297</a> </li> <li><a href="http://java.sun.com/j2se/1.5.0/docs/api/" >http://java.sun.com/j2se/1.5.0/docs/api/</a></li> <li><a href="http://java.sun.com/j2se/1.5.0/docs/guide/language/" >http://java.sun.com/j2se/1.5.0/docs/guide/language/</a></li> </ul> http://www.jprl.com/Blog/archive/development/2007/Aug-31.html Jonathan Pryor (jonpryor@vt.edu) http://www.jprl.com/Blog/archive/development/2007/Aug-31.html Fri, 31 Aug 2007 21:22:00 GMT Problems with Traditional Object Oriented Ideas <p>I've been training with <a href="http://www.gnome.org/~michael/">Michael Meeks</a>, and he gave <a href="http://www.figuiere.net/hub/blog/">Hubert</a> and I an overview of the history of OpenOffice.org.</p> <p>One of the more notable comments was the <a href="http://framework.openoffice.org/source/browse/framework/binfilter/" >binfilter</a> <a href="http://wiki.services.openoffice.org/wiki/Source_code_directories" >module</a>, which is a stripped-down copy of StarOffice 5.2 (so if you build it you wind up with an ancient version of StarOffice embedded within your current OpenOffice.org build).</p> <p>Why is a embedded StarOffice required? Because of mis-informed "traditional" Object Oriented practice. :-)</p> <p>Frequently in program design, you'll need to save state to disk and read it back again. Sometimes this needs to be done manually, and sometimes you have a framework to help you (such as <a href="http://msdn2.microsoft.com/en-us/library/7ay27kt9(vs.71).aspx">.NET Serialization</a>). Normally, you design the individual classes to read/write themselves to external storage. This has lots of nice benefits, such as better encapsulation (the class doesn't need to expose it's internals), the serialization logic is in the class itself "where it belongs," etc. It's all good.</p> <p>Except it isn't. By tying the serialization logic to your internal data structures, you <i>severely</i> reduce your ability to change your internal data structures for optimization, maintenance, etc.</p> <p>Which is why OpenOffice.org needs to embed StarOffice 5.2: the StarOffice 5.2 format serialized internal data structures, but as time went on they wanted to change the internal structure for a variety of reasons, The result: they couldn't easily read or write their older storage format without having a copy of the version of StarOffice that generated that format.</p> <p>The take away from this is that if you expect your software to change in any significant way (and why shouldn't you?), then you should aim to keep your internal data structures as far away from your serialization format as possible. This may complicate things, or it may require "duplicating" code (e.g. your <i>real</i> data structure, and then a <tt>[Serializable]</tt> version of the "same" class -- with the data members but not the non-serialization logic -- to be used when actually saving your state), but failure to do so may complicate future maintenance.</p> <p>(Which is why <a href="http://www.amazon.com/Advanced-NET-Remoting-Second-Rammer/dp/1590594177/ref=pd_bbs_sr_1/105-9545851-3808436?ie=UTF8&amp;s=books&amp;qid=1188389239&amp;sr=8-1" >Advanced .NET Remoting</a> suggests thinking about serialization formats <i>before</i> you publish your first version...)</p> http://www.jprl.com/Blog/archive/development/openoffice.org/2007/Aug-28.html Jonathan Pryor (jonpryor@vt.edu) http://www.jprl.com/Blog/archive/development/openoffice.org/2007/Aug-28.html Tue, 28 Aug 2007 12:15:00 GMT Things I Didn't Know - What Is Obesity? <p>Ran across this interesting article: <a href="http://freakonomics.blogs.nytimes.com/2007/08/22/freakonomics-quorum-what-is-the-right-way-to-think-about-the-obesity-epidemic/" >Freakonomics Quorum: What is the Right Way to Think About the Obesity ‘Epidemic’?</a>.</p> <blockquote><p> For example, under our current definitions, <b>George Bush</b> and <b>Michael Jordan</b> are overweight, while <b>Arnold Schwarzenegger</b> and <b>Mel Gibson</b> are obese. </p></blockquote> <p>In short, BMI isn't always an accurate indicator of obesity, and should be avoided.</p> http://www.jprl.com/Blog/archive/etc/2007/Aug-22.html Jonathan Pryor (jonpryor@vt.edu) http://www.jprl.com/Blog/archive/etc/2007/Aug-22.html Wed, 22 Aug 2007 17:46:00 GMT It's A Boy! <p>Amber's pregnant, and it's a boy!</p> <blockquote> <p><a href="http://www.jprl.com/Blog/archive/life/2007/100_1688.jpg" ><img src="http://www.jprl.com/Blog/archive/life/2007/100_1688-web.jpg" alt="Ultrasound" /></a></p> </blockquote> <p>Estimated due date is December 22, 2007.</p> http://www.jprl.com/Blog/archive/life/2007/Aug-15.html Jonathan Pryor (jonpryor@vt.edu) http://www.jprl.com/Blog/archive/life/2007/Aug-15.html Wed, 15 Aug 2007 15:34:00 GMT Re-Introducing <tt>monodocer</tt>