<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Trausch’s Little Home &#187; programming</title>
	<atom:link href="http://mike.trausch.us/blog/tag/programming/feed/" rel="self" type="application/rss+xml" />
	<link>http://mike.trausch.us/blog</link>
	<description>My writing on life, computers, and technology</description>
	<lastBuildDate>Wed, 09 Feb 2011 18:16:20 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>The Uniform Driver Interface—why wasn&#8217;t it adopted?</title>
		<link>http://mike.trausch.us/blog/2010/03/03/the-uniform-driver-interface%e2%80%94why-wasnt-it-adopted/</link>
		<comments>http://mike.trausch.us/blog/2010/03/03/the-uniform-driver-interface%e2%80%94why-wasnt-it-adopted/#comments</comments>
		<pubDate>Wed, 03 Mar 2010 23:31:53 +0000</pubDate>
		<dc:creator>Michael Trausch</dc:creator>
				<category><![CDATA[Rant]]></category>
		<category><![CDATA[computing]]></category>
		<category><![CDATA[freedom]]></category>
		<category><![CDATA[random thoughts]]></category>
		<category><![CDATA[free software]]></category>
		<category><![CDATA[operating systems]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://mike.trausch.us/blog/?p=592</guid>
		<description><![CDATA[Every now and again, I come back to looking at device drivers and driver-writing, and I wonder why there is not some common interface for device drivers. What would the world be like if we could write a device driver for Linux, and be able to use it on FreeBSD without modification? There was a [...]]]></description>
			<content:encoded><![CDATA[<p>Every now and again, I come back to looking at <a href="http://en.wikipedia.org/wiki/Device_driver">device drivers</a> and driver-writing, and I wonder why there is not some common interface for device drivers. What would the world be like if we could write a device driver for Linux, and be able to use it on FreeBSD without modification? There was a project called the <a href="http://www.projectudi.org/">Uniform Driver Interface</a>, which aimed to create a common specification (both <a href="http://en.wikipedia.org/wiki/API">API</a> and <a href="http://en.wikipedia.org/wiki/Application_binary_interface">ABI</a>) for drivers such that they could be used portably between operating systems. In other words, a device manufacturer could create a device (say, a <a href="http://en.wikipedia.org/wiki/SATA">SATA</a> chipset) once, and it could then be used by <a href="http://en.wikipedia.org/wiki/Linux">Linux</a>, <a href="http://en.wikipedia.org/wiki/FreeBSD">FreeBSD</a>, <a href="http://en.wikipedia.org/wiki/NetBSD">NetBSD</a>, <a href="http://en.wikipedia.org/wiki/OpenBSD">OpenBSD</a>, <a href="http://en.wikipedia.org/wiki/Haiku_(operating_system)">Haiku</a>, <a href="http://en.wikipedia.org/wiki/Microsoft_Windows">Windows</a>, <a href="http://en.wikipedia.org/wiki/Mac_OS_X">OS X</a>, or any other <a href="http://en.wikipedia.org/wiki/Operating_system">operating system</a> that chose to implement the UDI specification (or, honestly, <em>any</em> generic, OS-independent driver specification).</p>
<p>The <a href="http://en.wikipedia.org/en/Free_Software_Foundation">Free Software Foundation</a> <a href="http://www.gnu.org/philosophy/udi.html">objected to UDI</a> for various reasons. Mostly, I think, it was because they were afraid that people who are not them would choose to use drivers that were non-free. As I&#8217;ve written about before here, there are people who think that forcing people to use <a href="http://en.wikipedia.org/wiki/Free_software">free software</a> is somehow freedom—and I will not go into it in any great depth here, because I have done that in the past. Suffice it to say that forcing <em>anything</em> is not freedom; it cannot be freedom. So, the Free Software Foundation, I think, was really afraid that they would have to do more work to be able to stick to their own requirement of using 100% free software on their own computer systems. (And hey, Roy, if you&#8217;re reading—I&#8217;m not saying that the FSF is wrong, and I&#8217;m not putting myself in a position opposite of that of the FSF. I suspect you think so anyway, but hey, I just figured I would point that out.)</p>
<p>Even if the free software operating systems did not adopt the UDI specification, why didn&#8217;t proprietary operating systems? This is perhaps the most puzzling thing to me. It seems that in this event, <em>none</em> of the operating systems—free or proprietary—did what would have made sense. After all, even if <em>only</em> <a href="http://en.wikipedia.org/wiki/Apple_Inc.">Apple</a> and <a href="http://en.wikipedia.org/wiki/Microsoft_Corporation">Microsoft</a> adopted a common device driver specification, that would save a lot of time, effort, and improve user experience all the way around. Apple users would be able to use all the hardware that Microsoft users could use—and the inverse would also be true. The amount of time that device driver authors would have to spend writing and debugging driver code would go <em>way</em> down—free software driver authors would be able to write a driver <em>once</em>, for example, and all systems (including free software systems that chose to support the specification) would benefit.</p>
<p>I could see an objection of a driver specification that was binary-only. However, UDI was not—it mandated an ABI so that drivers that are built for a particular platform were binary-compatible with operating systems on the same platform, but it also mandated an API, so that drivers would be source compatible to <em>any</em> operating system that implemented the specification, on any platform. That by itself would seem to me to be positive motivation to hardware manufacturers to release the source code to drivers so that they can support operating systems that are on platforms that do not exist yet, or have not been considered (or have been considered to be nonviable or unsupported platforms).</p>
<p>So, I have to wonder why a common device driver specification was never implemented in various operating systems. It would seem to be a common sense thing, especially given that there are so many operating systems. It would make the coexistence of operating systems a lot easier, and it would promote choice. It might encourage bits of proprietary code on free software operating systems, but it would also enable people to drop the excuse that “free operating system <em>x</em> does not support device <em>y</em>”, and would as a result potentially increase the number of free software programs and operating systems in use, even if there is a minor cost in terms of certain drivers. And those drivers could always be replaced—a common driver specification would make it easier to understand the structure of drivers generally, and make it easier for lawful, clean-room reverse engineering to be done on those drivers.</p>
<p>Imagine, for example, if drivers for graphics cards, TV tuner cards, video and audio encoding/decoding cards, modems, storage chipsets, motherboard chipsets, <a href="http://en.wikipedia.org/wiki/USB">USB</a> chipsets, <a href="http://en.wikipedia.org/wiki/IEEE-1394">IEEE-1394</a> chipsets, graphics tablet devices, touch screens, debugging interfaces, network devices, and so forth were all written to a common specification, it would reduce the amount of code which needed testing. It would increase user choice in both hardware and operating systems—something which I still hold is quite likely the most valuable freedom we have. It would increase reliability, since the users of Windows, OS X, Linux, the various BSD systems, and other, not-so-mainstream operating systems would be able to run the same driver code and collectively supply debugging information and perform testing in a multitude of environments. It would increase security, because then common code that is well-known could be used on all platforms and not just the one it was written for. It would do for device drivers what <a href="http://en.wikipedia.org/wiki/POSIX">POSIX</a> has done for user-mode application software. I do not believe that I could be convinced that this would be anything other than a good thing.</p>
<p>Also, it could bring back old operating systems.  Imagine what life could be like, for example, if <a href="http://en.wikipedia.org/wiki/OS/2">OS/2</a> had a “UDI driver” written for it, and it could then take advantage of newer drivers never intended for it. Or any other very old operating system which is no longer supported and could still be useful, for any of a number of reasons…</p>
]]></content:encoded>
			<wfw:commentRss>http://mike.trausch.us/blog/2010/03/03/the-uniform-driver-interface%e2%80%94why-wasnt-it-adopted/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>On communicating with software authors</title>
		<link>http://mike.trausch.us/blog/2009/09/09/on-communicating-with-software-authors/</link>
		<comments>http://mike.trausch.us/blog/2009/09/09/on-communicating-with-software-authors/#comments</comments>
		<pubDate>Thu, 10 Sep 2009 02:09:11 +0000</pubDate>
		<dc:creator>Michael Trausch</dc:creator>
				<category><![CDATA[AllTray]]></category>
		<category><![CDATA[FLOSS]]></category>
		<category><![CDATA[Personal]]></category>
		<category><![CDATA[computing]]></category>
		<category><![CDATA[life]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[random thoughts]]></category>
		<category><![CDATA[tips & tricks]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://mike.trausch.us/blog/?p=559</guid>
		<description><![CDATA[AllTray is a rather small project&#8212;for the moment, there is a single developer working on it (myself), and there aren&#8217;t a terribly great number of users, though the users that it does have are most excellent.&#160; For a long time, the users didn&#8217;t have the ability to observe the development processes for AllTray, nor did [...]]]></description>
			<content:encoded><![CDATA[<p>AllTray is a rather small project&mdash;for the moment, there is a single developer working on it (myself), and there aren&#8217;t a terribly great number of users, though the users that it does have are most excellent.&nbsp; For a long time, the users didn&#8217;t have the ability to observe the development processes for AllTray, nor did they have a bug tracker or any point of contact to the author/maintainer other than email.&nbsp; Things have gotten better there, since AllTray development takes place in the open on Launchpad (though I&nbsp;do have to get better about publishing feature branches that last longer than a day or two so that people can see them as well while they are in progress).</p>
<p>Many projects that are all about being open and transparent provide mechanisms for their users to get in touch with the developers.&nbsp; Launchpad has become an excellent place to do these things; Launchpad&#8217;s Answers and Bugs components are <em>truly excellent</em> ways to get in touch with people that manage software there.&nbsp; The system is so good that I&#8217;d advocate that every project try to move to it.&nbsp; Launchpad <em>does</em> have its issues, though they are often quickly fixed (and can be fixed even quicker now that it is free software).&nbsp; But between Bazaar (a truly amazing and flexible distributed version control system) for code hosting and the other components of Launchpad such as the Answers, Bugs, and Translations components, Launchpad provides virtually everything that a project needs to communicate effectively with its users aside from the project&#8217;s Web site.&nbsp; And users seem to naturally be able to reach out using it.</p>
<p>In the nearly one year that I&#8217;ve been working with AllTray, I&#8217;ve talked&mdash;well, written to&mdash;several people who have asked questions and acted in their own ways to work to improve the software.&nbsp; Development on AllTray has been made much easier just because people are willing to speak up.&nbsp; Everything from the random &ldquo;thank you&rdquo; to &ldquo;hey, are you going to do this?&rdquo; or &ldquo;I&#8217;d like to see feature <em>x</em> in the new version&rdquo; or whatever.&nbsp; It&#8217;s truly great.&nbsp; I can&#8217;t say that every project has users quite like AllTray&#8217;s, because AllTray is something of a niche application, but AllTray&#8217;s users are a great model for other projects.&nbsp; There has been virtually no negativity from users and everything has been constructive.</p>
<p>To anyone who manages a project that <em>doesn&#8217;t</em> use Launchpad, I&#8217;d <strong>strongly</strong> encourage them to do so.&nbsp; Its users are great, and as far as management of the overall project goes, it&#8217;s <em>very</em> easy for project people to communicate back and manage communications in a single spot.&nbsp; It&#8217;s also great that users can ask a question and that the project can do things like go, &ldquo;oh, hey, this is really a bug,&rdquo; or vice versa with bugs&rarr;questions.&nbsp; And if you don&#8217;t use Launchpad because you don&#8217;t want to use Bazaar&nbsp;(I&nbsp;hear that users of git are pretty dedicated to it; I&nbsp;can understand that, but it&#8217;s just not for me&mdash;it&#8217;s too complex, and I&nbsp;like that Bazaar just stays out of my way), consider using LP&nbsp;for everything <em>but</em> code hosting.&nbsp; Or consider using Launchpad&#8217;s code hosting to mirror your project from git, it does this quite nicely.&nbsp; Or, find some way to do what Launchpad does wherever you do project management.&nbsp; It works really well, and it&#8217;s a big help.</p>
<p>And to AllTray&#8217;s users. A big <span style="font-size: x-large;">Thank You</span>.&nbsp; You guys and gals are great.&nbsp; Keep communicating!</p>
]]></content:encoded>
			<wfw:commentRss>http://mike.trausch.us/blog/2009/09/09/on-communicating-with-software-authors/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>The Mono war is over and we have won, thanks to Microsoft.</title>
		<link>http://mike.trausch.us/blog/2009/07/06/the-mono-war-is-over-and-we-have-won-thanks-to-microsoft/</link>
		<comments>http://mike.trausch.us/blog/2009/07/06/the-mono-war-is-over-and-we-have-won-thanks-to-microsoft/#comments</comments>
		<pubDate>Mon, 06 Jul 2009 23:18:58 +0000</pubDate>
		<dc:creator>Michael Trausch</dc:creator>
				<category><![CDATA[FLOSS]]></category>
		<category><![CDATA[computing]]></category>
		<category><![CDATA[cool stuff]]></category>
		<category><![CDATA[freedom]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[wtf‽]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[FUD]]></category>
		<category><![CDATA[microsoft]]></category>
		<category><![CDATA[mono]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[UNIX]]></category>

		<guid isPermaLink="false">http://mike.trausch.us/blog/?p=543</guid>
		<description><![CDATA[Yeah, alright.  Those are words I would never have thought I&#8217;d see in a title in a blog post, “thanks to Microsoft.”  But, it is true.  Microsoft is adding C# and the CLI to the list of technologies that it promises it will not sue for.  This is Microsoft&#8217;s “Community Promise”, which means that to [...]]]></description>
			<content:encoded><![CDATA[<p>Yeah, alright.  Those are words I would never have thought I&#8217;d see in a title in a blog post, “thanks to Microsoft.”  But, it is true.  <a href="http://port25.technet.com/archive/2009/07/06/the-ecma-c-and-cli-standards.aspx">Microsoft is adding C# and the CLI to the list of technologies that it promises it will not sue for</a>.  This is Microsoft&#8217;s “Community Promise”, which means that to all of you who claimed that patents were a problem for Mono, if you were not wrong before, you are <em>absolutely, categorically, totally, utterly</em> wrong now.</p>
<p>One of the very few times I have uttered this phrase, but it works now:  <strong>Thanks, Microsoft</strong>.</p>
]]></content:encoded>
			<wfw:commentRss>http://mike.trausch.us/blog/2009/07/06/the-mono-war-is-over-and-we-have-won-thanks-to-microsoft/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Vala: Bindings for non-GObject type C libraries</title>
		<link>http://mike.trausch.us/blog/2009/02/18/vala-bindings-for-non-gobject-type-c-libraries/</link>
		<comments>http://mike.trausch.us/blog/2009/02/18/vala-bindings-for-non-gobject-type-c-libraries/#comments</comments>
		<pubDate>Wed, 18 Feb 2009 23:08:38 +0000</pubDate>
		<dc:creator>Michael Trausch</dc:creator>
				<category><![CDATA[computing]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[vala]]></category>

		<guid isPermaLink="false">http://www.trausch.us/?p=496</guid>
		<description><![CDATA[Recently, I came upon Vala, the new programming language that has been created which is similar in nature to C#, but compiles to C (and thus to an efficient native executable). This is the kind of interesting thing that can come from research with managed code systems—and like any new technology that someone gets the [...]]]></description>
			<content:encoded><![CDATA[<p>Recently, I came upon Vala, the new programming language that has been created which is similar in nature to C#, but compiles to C (and thus to an efficient native executable).  This is the kind of interesting thing that can come from research with managed code systems—and like any new technology that someone gets the idea to create, it was (at least to me) quite unexpected.  Essentially, Vala provides reachability to programmers so that they can write good quality software in an easily readable and maintainable fashion.  The Vala compiler is not unlike something like GCC; it takes source code input and generates code output.  In this case, instead of the output being assembler, as is traditionally done with native languages, the output is C which can be fed to a C compiler like GCC, when then turns it to assembly and creates the executable.</p>
<p>Vala supports an object-oriented means of programming.  It performs &#8220;assisted&#8221; memory management, and handles a lot of things which are tedious to do in C directly for you.  This is in contrast to a runtime system like the JVM or the CLR, where the entire program requires this runtime engine and a (usually pretty large) standard library.  These things do full memory management by way of garbage collection, which is not a horrible idea, but that, plus the extra layers of software can slow things down.  (Not that they have to: an entire operating system written in Java or CLI would have zero cost of having child processes which are Java or CLI processes; instead, native executables would require emulation and a performance hit.  However, this is tangential&#8230;)</p>
<p>Getting back on track, Vala is targeted at the GObject type system.  This means that programs that are written in Vala <em>do</em> require some libraries at run-time, namely the GLib and GLib-Object libraries.  These libraries are part of the LSB spec, and are installed on most reasonable and modern systems, with possible exception for systems configured to be servers.  Effectively, though, the cost is nothing.  This brings me to the point I originally wanted to write about: using libraries in Vala.</p>
<p>In order to use a library in Vala, there must be a <tt>.vapi</tt> file for it.  This VAPI file is essentially a description of the library; it provides Vala with information it uses to then call the entrypoints in the file.  The VAPI file is also very powerful:  You can write one to describe a regular C library that doesn&#8217;t use GObject, and it provides assistance to be able to &#8220;objectify&#8221; that library if you want.  Creating this bindings is a manual process, but it isn&#8217;t terribly hard—though Vala documentation is, at the moment, lacking a bit in terms of consumer-oriented documentation.  As is the case with free software, when user documentation doesn&#8217;t exist, we can always refer to the source code for additional detail and clarification if necessary.  (And this isn&#8217;t terribly hard to do with the Vala compiler, it&#8217;s written in Vala!)</p>
<p>In the VAPI file, you can define one or more namespaces, and then enumerations, constants, classes, methods, etc., within those namespaces.</p>
<p><a name="trausch_us_vala_bindings_example"><br />
<h3>The Example</h3>
<p></a></p>
<p>For this example, we&#8217;ll use the <tt>libuuid</tt> library, which comes with e2fsprogs.  On Ubuntu, ensure that you have the development headers installed by executing <tt>sudo apt-get install uuid-dev</tt> prior to getting started—you&#8217;ll need those headers installed in order to be able to build software using the bindings.  Then, create yourself a working directory; <tt>~/uuid-vala</tt> is what I&#8217;ll be using in this example.  We&#8217;ll go through a few different iterations of this binding, progessively adding functionality and usefulness to it.  I&#8217;ll take you through the steps that I went through to generate this VAPI file, sans a few emails to the <a href="http://mail.gnome.org/mailman/listinfo/vala-list">Vala emailing list</a>.  <img src='http://mike.trausch.us/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>A good starting point for creating a binding in Vala is API documentation; in the case of <tt>libuuid</tt>, there are the man pages <tt>uuid</tt>, <tt>uuid_clear</tt>, <tt>uuid_compare</tt>, <tt>uuid_copy</tt>, <tt>uuid_generate</tt>, <tt>uuid_is_null</tt>, <tt>uuid_parse</tt>, <tt>uuid_time</tt>, and <tt>uuid_unparse</tt>.  From here, we can get the function prototypes that we need—the library’s <em>entrypoints</em>.  What we don&#8217;t get from them is the definitions of the data types and some of the other data.  For that, we refer to the header file—stated in the man pages as <tt>uuid/uuid.h</tt>.  The header gives us the rest of the information that we know; we need the definitions for <tt>uuid_t</tt>, <tt>UUID_VARIANT_*</tt> and <tt>UUID_TYPE_DCE_*</tt>.  Also, because we don&#8217;t have a complete set of class libraries/bindings wrapping basic POSIX functionality, we need to import <tt>time_t</tt> and <tt>struct timeval</tt>.</p>
<p>One thing to consider here before we actually write the VAPI file is which types are opaque for the purposes of the bindings, and which ones are transparent.  Again, if we had a complete set of class libraries/bindings, this wouldn&#8217;t be a problem—we&#8217;d just use the existing types.  For now, we&#8217;ll assume that the <tt>uuid_t</tt> type is opaque, and that we need to use the <tt>time_t</tt> and <tt>struct timeval</tt> types, but we&#8217;ll not be wrapping them in this first go-around.</p>
<p>Without futher ado, here&#8217;s the first iteration of the VAPI file, with commentary and explanation following:</p>
<pre lang="vala">/*
 * libuuid.vapi - Vala bindings for the e2fsprogs library libuuid
 * Copyright (c) 2009 Michael B. Trausch &lt;mike@trausch.us&gt;
 * License: GNU LGPL v3 as published by the Free Software Foundation
 *
 * This binding is a (mostly) strict binding to the function-oriented
 * nature of this C library.
 */

[CCode(cheader_filename = "uuid/uuid.h",
	   lower_case_cprefix = "uuid_", cprefix = "")]
namespace LibUUID {
	[CCode(cprefix = "UUID_VARIANT_")]
	public enum Variant {
		NCS,
		DCE,
		MICROSOFT,
		OTHER
	}

	[CCode(cprefix = "UUID_TYPE_DCE_")]
	public enum Type {
		TIME = 1,
		RANDOM = 4
	}

	[CCode(cname = "time_t")]
	public struct Time : int{}

	[CCode(cname = "struct timeval")]
	public struct TimeValue {
		[CCode(cname = "tv_sec")]
		public int seconds;

		[CCode(cname = "tv_usec")]
		public int microseconds;
	}

	[SimpleType]
	[CCode(cname = "uuid_t")]
	public struct UUID : char {}

	public void clear(UUID uu);
	public int compare(UUID uu1, UUID uu2);
	public void copy(UUID destination, UUID source);
	public void generate(UUID output);
	public void generate_random(UUID output);
	public void generate_time(UUID output);
	public int is_null(UUID uu);
	public int parse(string uuid_input, UUID uu);

	[CCode(cname = "uuid_time")]
	public Time get_time(UUID uu, out TimeValue time_ret);
	public void unparse(UUID uu,
						[CCode(array_length = false,
							   array_nullterminated = false)]
						char[37] uuid_asciiz);
	public void unparse_upper(UUID uu,
							  [CCode(array_length = false,
									 array_nullterminated = false)]
							  char[37] uuid_asciiz);
	public void unparse_lower(UUID uu,
							  [CCode(array_length = false,
									 array_nullterminated = false)]
							  char[37] uuid_asciiz);

	// Not documented in the man page, but exposed in the headers.
	[CCode(cname = "uuid_type")]
	public int get_type(UUID uu);

	[CCode(cname = "uuid_variant")]
	public int get_variant(UUID uu);

	// Part of the C library, but provided to make life easier on an
	// application programmer.
	[CCode(cname = "ctime", cheader_filename = "time.h")]
	public weak string get_unixtime_to_string(ref LibUUID.Time seconds);
}</pre>
<p>As I mentioned earlier, Vala is a language that is similar in many ways to the C# language.  If you&#8217;ve worked with C# code, you&#8217;ll recognize the <tt>[CCode …]</tt> immediately prior to the <tt>namespace LibUUID</tt> declaration as an <em>attribute</em>.  The attribute looks similar to a function call—and while I haven&#8217;t gotten terribly deep into Vala, I have the feeling that Vala doesn&#8217;t treat attributes as function calls.  After all, this isn&#8217;t the CLR that we&#8217;re talking about, where attributes are really classes, and instantiations of them are special ways of instantiating them and attaching them to classes.  Anyway, this particular attribute contains three parameters:</p>
<ul>
<li><tt>cheader_filename = "uuid/uuid.h"</tt> – This attribute informs Vala that the bindings come from the specified header file.  This attribute can be applied to (at least) <tt>namespace</tt>s and methods.</li>
<li><tt>lower_case_prefix = "uuid_"</tt> – This attribute informs Vala that the methods are prefixed with <tt>uuid_</tt> in C code.  Looking down a bit, this means that <tt>public void clear(UUID uu);</tt> is really <tt>void uuid_clear(uuid_t uu)</tt> when called from C.</li>
<li><tt>cprefix = ""</tt> – This states that we don&#8217;t want to use a C prefix for anything else.  Between this and the previous parameter, this means that if we have to bind something that doesn&#8217;t fit the naming conventions that we&#8217;ve already laid out, we&#8217;ll have to manually define them when we define the item in question.</li>
</ul>
<p>The next thing after the <tt>namespace</tt> declaration is the the enum declaration for Variant.  This enum maps the series of constants in the header file which define the <tt>UUID_VARIANT</tt> type.  The same goes for Type, for <tt>UUID_TYPE</tt>.  The <tt>cprefix</tt> parameter to the attached <tt>CCode</tt> attribute says that these enums are mapped to constants defined in the header file, and it will then generate C code which references those constants (which will then be “expanded” by the preprocessor when the C compiler gets to the source code).</p>
<p>After these, we find some type definitions that make the binding a little bit easier to use.  Specifically, for <tt>time_t</tt>, <tt>struct timeval</tt>, and <tt>uuid_t</tt>.  These definitions provide some help with type-safety in Vala, and are terribly useful.</p>
<p>Now, we are down to the methods.  The first 8 methods are regular, in that they follow all of the previously declared rules.  As an example, a call to <tt>LibUUID.clear(uu)</tt> (where <tt>uu</tt> is a <tt>UUID</tt> data type) will expand to uuid_clear(uu) in C code.  Since <tt>clear</tt> returns <tt>void</tt>, Vala doesn&#8217;t have to generate any code to handle the return value.  In the case of <tt>compare</tt>, it will of course assign the return value to a variable in C and support you working with it later.  The first <strong>non-regular</strong> function here is <tt>get_time</tt>, which has the real name <tt>uuid_time</tt>, not <tt>uuid_get_time</tt>.  I renamed it to make more sense in the context of writing new code in Vala, though this was an optional choice.</p>
<p>Next, we see the <tt>unparse</tt> family of functions.  These take a binary UUID and expand them to a string such that you can use the UUID in your user interface or when passing code to a database server or other external program.  This was challenging, and <em>it is the most fragile part of the binding</em>.  In other words, what I did here <strong>works</strong>, but it&#8217;s <strong>really</strong> not good practice to do generally.  This is an example of a fairly easy-to-implement binding.  I wouldn&#8217;t recommend distribution of the binding in production code, because you can still shoot yourself in the foot with it—the caller is tasked with the burden of creating a char buffer long enough to hold the return value, and if they don&#8217;t, it&#8217;s pretty likely that glibc will kill the program at run time with the message &#8220;buffer overrun detected&#8221; and a very verbose backtrace and memory mapping dump.</p>
<p>The <tt>unparse</tt> family takes a UUID as input, and a char buffer as output.  Because the library assumes that it will be passed a 37 byte buffer, it doesn&#8217;t have any parameters to specify the length and will go ahead and blindly overwrite whatever you may have in the buffer for the first 37 bytes (36 bytes hold the UUID, and the last byte holds the trailing NULL byte, as is common in C when dealing with strings).  We have the <tt>array_nullterminated</tt> parameter set to <tt>false</tt> because this is really an output parameter, though we&#8217;ve not told Vala that.  Why?  Because the UUID library deals with char[] buffers and char* strings, and when you pass those in C, you&#8217;re passing them by reference anyway.  You only have to explicitly pass the address of them if you&#8217;re using statically-allocated storage (in C, that is).  And even things that appear static (uuid_t type) aren&#8217;t because of the underlying type being a pointer to a char buffer.  Confused yet?  Ahh, the reasons I try to stay away from C most days&#8230;</p>
<p>Anyway, more of the same for the other <tt>unparse</tt> functions.</p>
<p>Now, we have those variant and type enumerations, but nothing in the man pages talked about using them; that&#8217;s fine, of course, since we got them from the header.  There were two other functions in the header, which we have mapped as <tt>get_type</tt> and <tt>get_variant</tt>, which can be used to get information on the UUID being worked with.</p>
<p>Finally, we have an import from <tt>time.h</tt>.  The reason that this is here, instead of leaving it up to the application programmer to provide it, is because of the way Vala seems to treat external references.  It seems to want to create a prototype for them if you declare them in a .vala file, but it doesn&#8217;t seem to do that when declared in a .vapi file.  Since it&#8217;s helpful to not have a fatal compiler error choking on conflicting prototypes, we&#8217;ve provided an interface to <tt>ctime()</tt> directly in this VAPI implementation.</p>
<p>So, is this a good binding or not?  Well, let&#8217;s take a look at a sample program that uses the binding, and judge from that:</p>
<pre lang="vala">/*
 * uuid-fo.vala - Test for libuuid.vapi bindings for libuuid.
 * Copyright (c) 2009 Michael B. Trausch &lt;mike@trausch.us&gt;
 * License: GNU GPL v3 as published by the Free Software Foundation
 */

public class Program {
	public static int main(string[] args) {
		LibUUID.UUID uuid_time = {};
		LibUUID.UUID uuid_rand = {};

		LibUUID.generate_time(uuid_time);
		LibUUID.generate_random(uuid_rand);

		print_uuid_info(uuid_time);
		print_uuid_info(uuid_rand);

		return(0);
	}

	public static void print_uuid_info(LibUUID.UUID uu) {
		stdout.printf("UUID:\t\t%s\n", helper_uuid_to_string(uu));
		stdout.printf("  Type:\t\t%s\n", helper_uuidtype_to_string(uu));
		stdout.printf("  Variant:\t%s\n",
					  helper_uuidvariant_to_string(uu));

		if(LibUUID.get_type(uu) == LibUUID.Type.TIME) {
			stdout.printf("  Time:\t\t%s\n", helper_uuidtime_to_string(uu));
		}

		stdout.printf("\n");
	}

	public static string helper_uuidtype_to_string(LibUUID.UUID uu) {
		int uuidtype = LibUUID.get_type(uu);

		switch(uuidtype) {
		case LibUUID.Type.TIME:
			return("Time");
		case LibUUID.Type.RANDOM:
			return("Random");
		default:
			return("Unknown, invalid, or not a UUID");
		}
	}

	public static string helper_uuidvariant_to_string(LibUUID.UUID uu) {
		int uuidvariant = LibUUID.get_variant(uu);

		switch(uuidvariant) {
		case LibUUID.Variant.NCS:
			return("NCS");
		case LibUUID.Variant.DCE:
			return("DCE");
		case LibUUID.Variant.MICROSOFT:
			return("Microsoft");
		case LibUUID.Variant.OTHER:
			return("Other");
		default:
			return("Unknown, invalid, or not a UUID");
		}
	}

	public static string helper_uuidtime_to_string(LibUUID.UUID uu) {
		LibUUID.Time uuidTime;
		LibUUID.TimeValue uuidTimeValue;
		uuidTime = LibUUID.get_time(uu, out uuidTimeValue);

		int seconds, microseconds;
		seconds = uuidTimeValue.seconds;
		microseconds = uuidTimeValue.microseconds;
		LibUUID.Time secs = (LibUUID.Time)seconds;

		string uuid_timestamp = LibUUID.get_unixtime_to_string(ref secs);
		GLib.StringBuilder sb = new GLib.StringBuilder();

		sb.append_printf("%s", uuid_timestamp);
		sb.truncate(24);

		sb.append_printf(" (and %d microseconds)", microseconds);

		return(sb.str);
	}

	public static string helper_uuid_to_string(LibUUID.UUID uu) {
		char[37] uu_chars = new char[37];
		LibUUID.unparse(uu, uu_chars);

		GLib.StringBuilder sb = new GLib.StringBuilder();

		foreach(char c in uu_chars) {
			if(c == '\0') break;
			sb.append_printf("%c", c);
		}

		return(sb.str);
	}
}</pre>
<p>This program&#8217;s output:</p>
<pre>Wednesday, 2009-Feb-18 at 14:25:19 - mbt@zest - Linux v2.6.29-rc5
Ubuntu Intrepid:[1-83/10081-0]:uuid-vala> valac -o uuid uuid-fo.vala --pkg libuuid --vapidir . -X -luuid

Wednesday, 2009-Feb-18 at 14:25:59 - mbt@zest - Linux v2.6.29-rc5
Ubuntu Intrepid:[1-84/10082-0]:uuid-vala> ./uuid
UUID:		fbf2a006-fdf1-11dd-859f-5ae5840a05cf
  Type:		Time
  Variant:	DCE
  Time:		Wed Feb 18 14:26:04 2009 (and 691047 microseconds)

UUID:		ae610032-d4bf-42c7-93ff-465dd2e712bb
  Type:		Random
  Variant:	DCE</pre>
<p>This program is a bit large for such a simple task, don&#8217;t you think?  Take a look at the helper functions that are required to make the bindings for <tt>libuuid</tt> usable.  We can certainly do better than this—those helper functions are likely to be needed by just about anyone that works with the <tt>libuuid</tt> library in Vala.  Nearly everyone is going to want to get the UUID as a string, and while the API provides a means of reaching that goal, it doesn&#8217;t do it for us, and there is no reason why it shouldn&#8217;t.  After all, the way it is &#8220;just works&#8221; in existing C code, and future Vala code should &#8220;just work,&#8221; too.</p>
<p>The hard part is that the way that the UUID library works is a bit unusual.  When you bind something with Vala&#8217;s VAPI support, you can create a class out of it, if it gives you a pointer type of some sort.  But this doesn&#8217;t, and attempting to do so will get the C compiler rather unhappy with you.  The answer in <em>this</em> case is to create the VAPI binding, and then create a class that wraps the binding.  The reason is that the UUID library doesn&#8217;t act very object-like at all, requiring that each UUID that you use be essentially statically allocated; no functions return a new UUID, and there is no way to free them that is consistent with the API.  You can certainly dynamically allocate them and work with them, but the UUID library doesn&#8217;t seem to think that way.</p>
<p>So, here is a much simplified binding, which we will use as a basis for a wrapper:</p>
<pre lang="vala">/*
 * libuuid.vapi - Vala bindings for the e2fsprogs library libuuid
 * Copyright (c) 2009 Michael B. Trausch &lt;mike@trausch.us&gt;
 * License: GNU LGPL v3 as published by the Free Software Foundation
 *
 * This is a bare simple binding which will be wrapped by a
 * newly-created Vala object.  It's only slightly different than the
 * first version, in that it makes no attempt to make life easier on
 * the programmer using this binding.
 */

[CCode(cheader_filename = "uuid/uuid.h",
	   lower_case_cprefix = "uuid_", cprefix = "UUID_")]
namespace Native.LibUUID {
	// Constants
	private const int VARIANT_NCS;
	private const int VARIANT_DCE;
	private const int VARIANT_MICROSOFT;
	private const int VARIANT_OTHER;
	private const int TYPE_DCE_TIME;
	private const int TYPE_DCE_RANDOM;

	[CCode(cname = "time_t")]
	public struct time_t : int{}

	[CCode(cname = "struct timeval")]
	public struct timeval {
		public int tv_sec;
		public int tv_usec;
	}

	[CCode(cname = "uuid_t")]
	public struct UUID : char {}

	public void clear(UUID uu);
	public void copy(UUID dest, UUID src);
	public void generate(UUID outp);
	public void generate_random(UUID outp);
	public void generate_time(UUID outp);
	public void unparse(UUID uu,
						[CCode(array_length = false,
							   array_nullterminated = false)]
						char[37] outp);
	public void unparse_upper(UUID uu,
							  [CCode(array_length = false,
									 array_nullterminated = false)]
							  char[37] outp);
	public void unparse_lower(UUID uu,
							  [CCode(array_length = false,
									 array_nullterminated = false)]
							  char[37] outp);

	public int compare(UUID uu1, UUID uu2);
	public int is_null(UUID uu);
	public int parse(string uu_in, UUID outp);
	public int type(UUID uu);
	public int variant(UUID uu);

	public time_t time(UUID uu, out timeval TimeInfo);

	[CCode(cname = "ctime_r", cheader_filename = "time.h")]
	public weak string unixtime_to_string(ref time_t secs,
										  [CCode(array_length = false,
												 array_nullterminated = false)]
										  char[] ret);
}</pre>
<p>This is (mostly) the same, with a few different choices made in representing information from C.  Now, the thing to do is create a wrapper around this; this wrapper will be either compiled into a Vala application or it could be compiled as a shared library, being useful generally to other GLib/GObject programs or other Vala programs.</p>
<pre lang="vala">/*
 * libwrapuuid.vala - Wrapper for the simple libuuid bindings.
 * Copyright (c) 2009 Michael B. Trausch &#038;ltmike@trausch.us&gt;
 * License: GNU LGPL v3 as published by the Free Software Foundation
 *
 * This is a wrapper around libuuid.vapi which presents an object-oriented
 * interface to libuuid.
 */

namespace Trausch.Vala.UUID {
	public enum Variant {
		NCS = Native.LibUUID.VARIANT_NCS,
		DCE = Native.LibUUID.VARIANT_DCE,
		Microsoft = Native.LibUUID.VARIANT_MICROSOFT,
		Other = Native.LibUUID.VARIANT_OTHER
	}

	public enum Type {
		Time = Native.LibUUID.TYPE_DCE_TIME,
		Random = Native.LibUUID.TYPE_DCE_RANDOM
	}

	public errordomain UUIDError {
		MALFORMED_STRING_INPUT,
		NOT_SET,
		WRONG_TYPE,
		FAILED
	}

	public class UUID : GLib.Object {
		private Native.LibUUID.UUID uuid;
		private Type defaultType;

		construct {
			this.defaultType = Type.Time;
			this.generate();
		}

		public static UUID create_from_string(string input) throws UUIDError {
			UUID newUUID = new Trausch.Vala.UUID.UUID();
			newUUID.UUID = input;

			return(newUUID);
		}

		public string? UUID {
			owned get {
				if((bool)Native.LibUUID.is_null(this.uuid)) {
					return(null);
				}

				return(this.to_string());
			}

			set {
				if(value == null) {
					Native.LibUUID.clear(this.uuid);
				}

				if(Native.LibUUID.parse(value, this.uuid) < 0) {
					throw new
						UUIDError.MALFORMED_STRING_INPUT("Malformed string");
				}
			}
		}

		public Type UUIDType {
			get {
				if((bool)Native.LibUUID.is_null(this.uuid))
					throw new UUIDError.NOT_SET("No UUID is currently stored");

				Type uuidType = (Type)Native.LibUUID.type(this.uuid);
				return(uuidType);
			}

			set {
				Type current_type = this.UUIDType;
				Type new_type = value;

				if(current_type != new_type) {
					this.defaultType = new_type;
					this.generate();
				}
			}

			default = Type.Time;
		}

		public Variant UUIDVariant {
			get {
				if((bool)Native.LibUUID.is_null(this.uuid))
					throw new UUIDError.NOT_SET("No UUID is currently stored");

				Variant uuidVariant =
					(Variant)Native.LibUUID.variant(this.uuid);
				return(uuidVariant);
			}
		}

		public void generate() {
			switch(this.defaultType) {
			case Type.Random:
				Native.LibUUID.generate_random(uuid);
				break;
			case Type.Time:
				Native.LibUUID.generate_time(uuid);
				break;
			default:
				Native.LibUUID.generate(uuid);
				break;
			}
		}

		public int compare(UUID that) {
			return(Native.LibUUID.compare(this.uuid, that.uuid));
		}

		public bool equals(UUID that) {
			bool retval = false;
			int compare_result = Native.LibUUID.compare(this.uuid, that.uuid);
			if(compare_result == 0) retval = true;

			return(retval);
		}

		public UUID duplicate() {
			Trausch.Vala.UUID.UUID newUUID = new Trausch.Vala.UUID.UUID();
			newUUID.UUID = this.to_string();

			return(newUUID);
		}

		public string to_string() {
			char[] chars = new char[37];
			Native.LibUUID.unparse(this.uuid, chars);
			GLib.StringBuilder sb = new GLib.StringBuilder();

			foreach(char c in chars) {
				if(c == '\0') break;

				sb.append_printf("%c", c);
			}

			string retval = sb.str;
			return(retval);
		}

		public void from_string(string input) throws UUIDError {
			this.UUID = input;
		}

		private Native.LibUUID.timeval get_raw_time() throws UUIDError {
			if(this.UUIDType != Type.Time)
				throw new UUIDError.WRONG_TYPE("Invalid op: not a time UUID");

			if((bool)Native.LibUUID.is_null(this.uuid))
				throw new UUIDError.NOT_SET("No UUID is currently stored");

			Native.LibUUID.timeval time;
			Native.LibUUID.time(this.uuid, out time);

			return(time);
		}

		/*
		 * This is a slight bit ugly, to format the time the way I wanted to
		 * do it.
		 */
		public string get_time() throws UUIDError {
			Native.LibUUID.timeval timestamp = this.get_raw_time();
			Native.LibUUID.time_t unixTime =
				(Native.LibUUID.time_t)timestamp.tv_sec;

			GLib.StringBuilder sb = new GLib.StringBuilder();
			char[] timeStr = new char[27];
			Native.LibUUID.unixtime_to_string(ref unixTime, timeStr);

			int spaces = 0;

			foreach(char c in timeStr) {
				if(c == '\n') break;
				if(c == ' ') spaces++;

				if(spaces == 4) {
					sb.append_printf("+%dus", timestamp.tv_usec);
					spaces++;
				}

				sb.append_printf("%c", c);
			}

			return(sb.str);
		}

		public string get_type_as_string() throws UUIDError {
			Type uuidType = this.UUIDType;
			string retval = "";

			switch(uuidType) {
			case Type.Time:
				retval = "Time";
				break;
			case Type.Random:
				retval = "Random";
				break;
			}

			return(retval);
		}

		public string get_variant_as_string() throws UUIDError {
			Variant uuidVariant = this.UUIDVariant;
			string retval = "";

			switch(uuidVariant) {
			case Variant.NCS:
				retval = "NCS";
				break;
			case Variant.DCE:
				retval = "DCE";
				break;
			case Variant.Microsoft:
				retval = "Microsoft";
				break;
			case Variant.Other:
				retval = "Other";
				break;
			}

			return(retval);
		}
	}
}</pre>
<p>Alright, so that's 234 lines of object-oriented goodness.  What does that get us, though?  The ability to focus more closely on an actual application!  Here is a simple UUID generator program which uses this wrapping.  This application is considerably more featureful than the last one with the last bindings without the wrapper class, as can be seen by looking at it:</p>
</pre>
<pre lang="vala">/*
 * uuid.vala - UUID generator program using libwrapuuid.vala and libuuid from
 * e2fsprogs.
 * Copyright (c) 2009 Michael B. Trausch &lt;mike@trausch.us&gt;
 * License: GNU GPL v3 as published by the Free Software Foundation
 */
using Trausch.Vala.UUID;

public class Program {
	public static bool cmdline_force_time;
	public static bool cmdline_force_random;
	public static bool cmdline_version;

	const OptionEntry[] options = {
		{ "force-time", 't', 0, OptionArg.NONE, ref cmdline_force_time,
		  "Force time-based UUIDs", null },
		{ "force-random", 'r', 0, OptionArg.NONE, ref cmdline_force_random,
		  "Force random UUIDs", null },
		{ "version", 'v', 0, OptionArg.NONE, ref cmdline_version,
		  "Show the program version", null },
		{ null }
	};

	public static int main(string[] args) {
		int howMany = 2;

		try {
			GLib.OptionContext ctx = new GLib.OptionContext("- display uuids");
			ctx.set_help_enabled(true);
			ctx.add_main_entries(options, null);
			ctx.parse(ref args);
		} catch(OptionError e) {
			err(e.message, args[0]);
			return(1);
		}

		if(cmdline_version == true) {
			show_version();
		}

		if(cmdline_force_time &#038;&#038; cmdline_force_random) {
			err("--force-time and --force-random are mutually exclusive",
				args[0]);
			return(1);
		}

		if(args.length > 1)
			howMany = (args[1].to_int() == 0 ? howMany : args[1].to_int());

		UUID[] uuids = generate_uuids(howMany);

		foreach(UUID u in uuids) {
			print_uuid_info(u);
		}

		return(0);
	}

	public static void err(string errMessage, string prog) {
		stdout.printf("%s: %s\n", prog, errMessage);
		stdout.printf("Run '%s --help' to see a full list of command line"+
					  " options.\n", prog);
	}

	public static void show_version() {
		stdout.printf("""Sample UUID Generator v0.1.2
Copyright © 2009 Michael B. Trausch &lt;mike @trausch.us&gt;
Licensed under the terms of the GNU GPL v3 as published by the FSF.

""");
	}

	public static UUID[] generate_uuids(int howMany) {
		UUID[] retval = new UUID[howMany];
		for(int cur = 0; cur < howMany; cur++) {
			retval[cur] = new UUID();
			Trausch.Vala.UUID.Type newType;

			if(cmdline_force_time == true) {
				newType = Trausch.Vala.UUID.Type.Time;
			} else if(cmdline_force_random == true) {
				newType = Trausch.Vala.UUID.Type.Random;
			} else {
				if(cur % 2 != 0) {
					newType = Trausch.Vala.UUID.Type.Random;
				} else {
					newType = Trausch.Vala.UUID.Type.Time;
				}
			}

			retval[cur].UUIDType = newType;
		}

		return(retval);
	}

	public static void print_uuid_info(UUID uuid) {
		GLib.StringBuilder sb = new GLib.StringBuilder();
		sb.append_printf("UUID:\t\t%s\n", uuid.to_string());
		sb.append_printf("  Type:\t\t%s\n", uuid.get_type_as_string());
		sb.append_printf("  Variant:\t%s\n", uuid.get_variant_as_string());
		if(uuid.UUIDType == Trausch.Vala.UUID.Type.Time)
			sb.append_printf("  Time:\t\t%s\n", uuid.get_time());
		stdout.printf("%s\n", sb.str);
	}
}</pre>
<p>One minor note:  You will need Vala's trunk revision from the Subversion or bzr repositories for Vala to build this as is (or wait for a version of Vala &gt;= 0.5.4 to be released).  To use Vala 0.5.3, remove the parenthesis on line 94—or the program will try to allocate a <strong>ton</strong> of memory (trust me, the allocation <em>will</em> fail).  It is a relatively new language/compiler, so all the kinks haven't yet been worked out.  That's not a big deal, though; as I mentioned earlier, Vala development appears to be very active.  When I reported the bug earlier today, the Vala people were very fast to fix the bug (it was fixed in under 30 minutes!) and commit the fix to the SVN repository.  I was very pleasantly surprised with that.</p>
<p>The latter version of the binding, the wrapper class, and the Vala source for the application itself should be pretty easy to mentally follow if you're used to reading things like C#, C++, or Java, though if any of it needs additional explanation I can certainly respond to requests.  Writing it isn't terribly much harder, though the one bug I found was a bit of a kink since the parenthesis removal wasn't any of the things I thought to check.  In any event, you should now know enough to get started with Vala.  Oh, and if you don't like systems without documentation, and you're good with documentation, you may contribute <em>documentation resources</em> to the Vala project, if you can at all; Vala is currently short on documentation!</p>
<p>Oh, and of course, a few runs of the new version:</p>
</pre>
<pre>Wednesday, 2009-Feb-18 at 18:05:39 - mbt@zest - Linux v2.6.29-rc5
Ubuntu Intrepid:[1-189/10177-0]:uuid-vala> ./uuid --help
Usage:
  uuid [OPTION...] - display uuids

Help Options:
  -?, --help             Show help options

Application Options:
  -t, --force-time       Force time-based UUIDs
  -r, --force-random     Force random UUIDs
  -v, --version          Show the program version

Wednesday, 2009-Feb-18 at 18:05:44 - mbt@zest - Linux v2.6.29-rc5
Ubuntu Intrepid:[1-190/10178-0]:uuid-vala> ./uuid -v -t 1
Sample UUID Generator v0.1.2
Copyright © 2009 Michael B. Trausch &lt;mike@trausch.us&gt;
Licensed under the terms of the GNU GPL v3 as published by the FSF.

UUID:		ad990d72-fe10-11dd-859f-5ae5840a05cf
  Type:		Time
  Variant:	DCE
  Time:		Wed Feb 18 18:05:47+640357us 2009

Wednesday, 2009-Feb-18 at 18:05:47 - mbt@zest - Linux v2.6.29-rc5
Ubuntu Intrepid:[1-191/10179-0]:uuid-vala> ./uuid -r 1
UUID:		a57c6345-df45-4417-9298-e1c07d2151a8
  Type:		Random
  Variant:	DCE

Wednesday, 2009-Feb-18 at 18:05:53 - mbt@zest - Linux v2.6.29-rc5
Ubuntu Intrepid:[1-192/10180-0]:uuid-vala> ./uuid 3
UUID:		b26b2c40-fe10-11dd-859f-5ae5840a05cf
  Type:		Time
  Variant:	DCE
  Time:		Wed Feb 18 18:05:55+728288us 2009

UUID:		5a431431-cc7c-44bf-99ee-8f967e724b17
  Type:		Random
  Variant:	DCE

UUID:		b26b2c42-fe10-11dd-859f-5ae5840a05cf
  Type:		Time
  Variant:	DCE
  Time:		Wed Feb 18 18:05:55+728288us 2009

Wednesday, 2009-Feb-18 at 18:05:55 - mbt@zest - Linux v2.6.29-rc5
Ubuntu Intrepid:[1-193/10181-0]:uuid-vala> ./uuid -t 3
UUID:		b402ee9e-fe10-11dd-859f-5ae5840a05cf
  Type:		Time
  Variant:	DCE
  Time:		Wed Feb 18 18:05:58+400579us 2009

UUID:		b402ee9f-fe10-11dd-859f-5ae5840a05cf
  Type:		Time
  Variant:	DCE
  Time:		Wed Feb 18 18:05:58+400579us 2009

UUID:		b402eea0-fe10-11dd-859f-5ae5840a05cf
  Type:		Time
  Variant:	DCE
  Time:		Wed Feb 18 18:05:58+400579us 2009

Wednesday, 2009-Feb-18 at 18:05:58 - mbt@zest - Linux v2.6.29-rc5
Ubuntu Intrepid:[1-194/10182-0]:uuid-vala> ./uuid -r 3
UUID:		275ca880-5ae7-44b3-bcaf-4d0084d00df3
  Type:		Random
  Variant:	DCE

UUID:		d270e2af-5ee0-456d-8ac6-e1d5685287d0
  Type:		Random
  Variant:	DCE

UUID:		9a0de010-aba3-4276-99e9-dcb6e28455f2
  Type:		Random
  Variant:	DCE</pre>
<p><strong>ETA:</strong> If you would like to download the final sources, they are <a href="http://zest.spicerack.trausch.us/~mbt/code/uuid-vala.tar.gz">online in a simple tarball</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://mike.trausch.us/blog/2009/02/18/vala-bindings-for-non-gobject-type-c-libraries/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Low-level X11 programming</title>
		<link>http://mike.trausch.us/blog/2009/01/06/low-level-x11-programming/</link>
		<comments>http://mike.trausch.us/blog/2009/01/06/low-level-x11-programming/#comments</comments>
		<pubDate>Tue, 06 Jan 2009 08:12:21 +0000</pubDate>
		<dc:creator>Michael Trausch</dc:creator>
				<category><![CDATA[AllTray]]></category>
		<category><![CDATA[computing]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[x11]]></category>

		<guid isPermaLink="false">http://www.trausch.us/?p=480</guid>
		<description><![CDATA[Hrm. Not sure what I should do about this one. GUI systems programming is a concept that is new to me, at least in all of its low-level glory. Traditionally, I write things in C# because I really like that language. Eventually, I&#8217;d love to see the majority of the software out there using something [...]]]></description>
			<content:encoded><![CDATA[<p>Hrm.  Not sure what I should do about this one.  GUI systems programming is a concept that is new to me, at least in all of its low-level glory.  Traditionally, I write things in C# because I really like that language.  Eventually, I&#8217;d love to see the majority of the software out there using something like it (specifically, managed code) since that would mean that there would have the true possibility of <em>actually</em> writing code once and running it on any computer platform, with any operating system.</p>
<p>Obviously, we&#8217;re not there yet.  Using managed code today is good for certain types of larger systems and eventually (IMHO) it&#8217;ll be good for smaller ones, after the majority of software is using it and there isn&#8217;t some extremely large overhead for small tools on the system.</p>
<p>In any case, that gets me to where I am going:  I need to learn fairly low-level X11 programming.  Why?  As I am looking at AllTray, it currently seems that it operates at multiple levels of abstraction, depending on GTK+ and GDK to handle some things, and talking directly to X11 for others.  Since AllTray is a program which should be suitable for running on <em>all</em> window managers/GUI toolkits/desktop environments, the core functionality of it should not carry a dependency on GTK.</p>
<p>Part of the work I am doing in AllTray in my current local branch is to refactor functionality, and part of that means fixing this in a decent way.  The code base should operate at a consistent level of abstraction for the core (so as to make the code easier to understand and lower the dependencies it carries), while the user interface for AllTray should be native to the environment the user is working in.  That is, if the user is running GNOME, AllTray should use GTK+ for presenting its user interface; if the user is running KDE3, AllTray should use KDE 3 for presenting its user interface.  This would follow for every environment for which someone wants to submit code for—it&#8217;ll be modular, so at build-time you&#8217;d specify the interfaces you want to build support for (or, someone could in theory create a standalone library which follows the planned UI API which AllTray will work with) and those interfaces will be probed and queried at runtime; it&#8217;s possible that a similar system can be used to work around the quirks of various window managers/GUI toolkits/desktop environments.  (I am thinking about a general-purpose plugin and hooking system for AllTray, but I can only think of two uses for it, so it may be better to just implement those special cases and generalize the idea later if it proves to be worth it.)  The idea of a plugin system, of course, being so that people can more easily write code to extend AllTray in the ways in which it should be easily extended.  Ahh, I digress.</p>
<p>In any case, does anybody know of a good book that will get a person started with X11 programming?  Something new would of course be desirable, but (so far) I have only found really old books.  Maybe enough hasn&#8217;t changed in X11 in the last several years to warrant books on programming directly for it, but I don&#8217;t know enough about it at that level to know&#8230; <img src='http://mike.trausch.us/blog/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://mike.trausch.us/blog/2009/01/06/low-level-x11-programming/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Back in GA</title>
		<link>http://mike.trausch.us/blog/2009/01/05/back-in-ga/</link>
		<comments>http://mike.trausch.us/blog/2009/01/05/back-in-ga/#comments</comments>
		<pubDate>Mon, 05 Jan 2009 22:22:49 +0000</pubDate>
		<dc:creator>Michael Trausch</dc:creator>
				<category><![CDATA[AllTray]]></category>
		<category><![CDATA[computing]]></category>
		<category><![CDATA[Launchpad]]></category>
		<category><![CDATA[plans]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[travel]]></category>
		<category><![CDATA[vacation]]></category>

		<guid isPermaLink="false">http://www.trausch.us/?p=477</guid>
		<description><![CDATA[So, I am back in GA (got back yesterday late afternoon) and am finding that I have to force myself to do anything that isn&#8217;t strictly relaxing. That having been said, I did get the movement of AllTray to Launchpad done while I was in Toledo—you can now go to its project page on Launchpad [...]]]></description>
			<content:encoded><![CDATA[<p>So, I am back in GA (got back yesterday late afternoon) and am finding that I have to force myself to do anything that isn&#8217;t strictly relaxing.  <img src='http://mike.trausch.us/blog/wp-includes/images/smilies/icon_razz.gif' alt=':-P' class='wp-smiley' /> </p>
<p>That having been said, I did get the movement of AllTray to Launchpad done while I was in Toledo—you can now go to its <a href="https://launchpad.net/alltray">project page on Launchpad</a> and see what&#8217;s there.  I am going to be working on attempting to study and refactor the code base prior to fixing any reported bugs on the software and continuing its development.  Mainly, I think that the important parts of it are going to wind up being the refactoring of the code, making it consistently use a single layer of abstraction.  From there, I am planning on adding session management support and fixing bugs.</p>
<p>I will (hopefully soon) have a new Web site up for it and have the old one at Sourceforge redirect to it.  Ideally, the site will provide an interface for the information that Launchpad exposes about the project, perhaps with a blog in addition to it.  It won&#8217;t be my primary thing, since there is another project that has been in the cooker for a while which will hopefully be finished early this year that I&#8217;ve been working on, but that doesn&#8217;t mean AllTray will be nothing in my schedule.  My intention is to finish up working with the refactoring process in the next two months or so, and then spend the next six months making changes and enhancements that will lead up to my first stable release of AllTray, which will be version 0.8.0.</p>
<p>For now, though, a little bit of TV watching and relaxing.  I am still somewhat wiped out from the drive back&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://mike.trausch.us/blog/2009/01/05/back-in-ga/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>On Replacing AllTray &amp; Other Docking Software</title>
		<link>http://mike.trausch.us/blog/2008/10/21/on-replacing-alltray-other-docking-software/</link>
		<comments>http://mike.trausch.us/blog/2008/10/21/on-replacing-alltray-other-docking-software/#comments</comments>
		<pubDate>Tue, 21 Oct 2008 19:27:26 +0000</pubDate>
		<dc:creator>Michael Trausch</dc:creator>
				<category><![CDATA[FLOSS]]></category>
		<category><![CDATA[GNU/Linux]]></category>
		<category><![CDATA[GPLv3]]></category>
		<category><![CDATA[UNIX]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[computing]]></category>
		<category><![CDATA[gnome]]></category>
		<category><![CDATA[AllTray]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://www.trausch.us/?p=432</guid>
		<description><![CDATA[This post is a bit of a “brain dump” of sorts for some thoughts that I have as to replacing AllTray with a more versatile, powerful, and robust tool to handle various needs of users when it comes to taking applications and docking them to the system tray. Why? I&#8217;ve used AllTray for a long [...]]]></description>
			<content:encoded><![CDATA[<p>This post is a bit of a “brain dump” of sorts for some thoughts that I have as to replacing AllTray with a more versatile, powerful, and robust tool to handle various needs of users when it comes to taking applications and docking them to the system tray.</p>
<h3>Why?</h3>
<p>I&#8217;ve used AllTray for a long time.  It is one of those pieces of software that performs a useful function, but you have to know its quirks to make it do what you want quite often, and you have to work around some of the things that it does for it to retain that usefulness.  Users shouldn&#8217;t have to do that—they should just be able to start using a program or utility and have it work properly.  Also, utilities should be (reasonably) independent of the environment that they run within, which AllTray isn&#8217;t.  And, good utilities should integrate with the system pretty well, which AllTray does not, since it carries a hard dependency on GDK/GTK.  (Kdocker is an alternative piece of software, and while I don&#8217;t know how well it works compared to AllTray, I know that it is bound to Qt, which is just as bad.)</p>
<p>The license will most likely be GPLv3, since nothing will actually link to it and it&#8217;s not a library.  If there is a library component, it will be LGPLv3.</p>
<h3>The actual &#8220;braindump&#8221;</h3>
<p>The actual *docking* part isn&#8217;t terribly hard, it would seem.  With GTK+ it can be done in only a few lines of code (especially in C#).  However, C# wouldn&#8217;t be the language to use for the this tool, because of the dependency on Mono.  My thinking is that the proper language to use would be C itself.  It makes me think of how easy everything would be if only the desktop environment and all its software were already written in managed code&#8230; the effective cost of using C# would be significantly less than it is already.</p>
<p>Using C as the language isn&#8217;t that big a deal to me.  What <em>is</em> a big deal to me is that the application be well-integrated and well-behaved.  For example, AllTray depends on GTK for some of its tasks, and uses a custom (ugly, IMHO) widget for displaying its title when you over over it in the system tray.  There&#8217;s another program out there, KDocker, that would appear to be slightly more featureful than AllTray, but it carries with it a dependency on Qt, which I don&#8217;t like.  Ideally, the core for such a docking utility should be able to have various back-ends that serve the purpose of integration with the system, with a single back-end that would apply without dependencies on anything else for the rare scenario where neither GTK+ nor Qt are available.</p>
<p>What would this thing be required to do?</p>
<ul>
<li>Dock any arbitrary application to the system tray, not just a single window from the application. (Using the <a href="http://standards.freedesktop.org/systemtray-spec/systemtray-spec-latest.html" title="System Tray Protocol Specification">System Tray Protocol Specification</a>)</li>
<li>Run in a single instance, managing multiple applications within that instance if necessary.</li>
<li>Provide <a href="http://en.wikipedia.org/wiki/Session_management" title="Wikipedia: Session management">session management</a> for those who use it, and act as a session manager for applications that are run underneath it that support session management.</li>
<li>Be able to use something like <code>inotify</code> to be able to show an indication of when the application&#8217;s title for its windows change.</li>
<li>Use a single icon for the application, with a window list if the application carries more than a single window.</li>
<li>Use individual backends which provide a native look and feel depending on the desktop environment currently in use.</li>
<li>Use the application’s icon to represent the application in the system tray.</li>
<li>Support blinking the icon when the application decides to do something like present a modal dialog box or something (if this is even possible, that much I am not quite sure of).</li>
<li>Detect the desktop environment currently in use and (if possible) load a backend to integrate with it.</li>
<li>Carry a dependency on <a href="http://en.wikipedia.org/wiki/GLib" title="Wikipedia: GLib">GLib</a> so as to make implementing it quicker and less error-prone.</li>
<li>NOT carry any hard dependencies on any widget libraries like <a href="http://en.wikipedia.org/wiki/GTK+" title="Wikipedia: GTK+">GTK+</a> or <a href="http://en.wikipedia.org/wiki/Qt_(toolkit)" title="Wikipedia: Qt (toolkit)">Qt</a>.</li>
<li>Return an error to the user if there is no running system tray, and there isn&#8217;t one after some sort of timeout (say, when starting the desktop environment, there may not be a system tray right away).  (I don&#8217;t think that sort of situation would be commonplace, but it&#8217;s not really the job of this program to create a system tray if one doesn&#8217;t exist, since this is the job of the desktop environment.)</li>
</ul>
<p>The backends would not have any specific configuration items (the entire configuration would be housed somewhere like <code>${HOME}/.config/docker</code>, for example).  There probably ought to be a backend entrypoint that would show a dialog for configuration, but I haven&#8217;t really figured out if that&#8217;d be the case yet.  The docker should probably do all of its configuration by way of the command line for each invocation, which is suitable for use as a desktop shortcut or panel launcher.</p>
<p>This approach requires that each individual desktop environment have its own backend, which might become a bit of a pain for supporting a great number of desktop environments, but the upshot of that is that the application then feels native no matter what environment the user is using.  Obviously support for GNOME and KDE would happen, and most everything else would depend on someone with programming experience for various environments to implement a backend for it.</p>
<p>The backend doesn&#8217;t handle, say, docking, since there&#8217;s a standard for that already.  It would handle things like displaying the tip when hovered over or displaying a menu when right-clicked.  So, the job that each backend would do would be pretty lightweight.  And as much as possible should be handled in the core, with the backend consisting of just enough &#8220;hooks&#8221; into the target system to be able to provide a useful interface.</p>
<p>The way that this would have to work, using C as the programming language, would be that the core would have to use <code>dlopen()</code> and friends to load the backend and then use the entrypoints that the backend provides.  Since <code>dlopen</code>, <code>dlclose</code>, <code>dlsym</code>, and <code>dlerror</code> are defined by POSIX.1-2001, support for those should be in every reasonably modern Unix-like system that supports at least a subset of POSIX.  This of course eliminates Windows, but I am not terribly worried about that since there are probably other Windows-only utilities that serve this purpose.</p>
<p>The primary goal, then, is to replace other DE-dependent and toolkit-dependent dockers with a utility that carries the goal to be universally useful and highly robust.  The aim of this goal is to replace AllTray entirely in (at the very least) Ubuntu, and hopefully be seen as useful in other distributions as well.</p>
<h3>I&#8217;ll need some help&#8230;</h3>
<p>This is the part where it&#8217;ll get interesting.  I&#8217;ll need some help in actually doing this, in many areas.</p>
<p>For the moment, where I&#8217;ll need help (be that from Google, or from people in-the-know that happen upon this post) is to find all of the documentation that I&#8217;ll need to understand how to implement the software.  I can use software that already exists to try to learn how the underlying system works, to a degree anyway.  But some of the software doesn&#8217;t handle various situations correctly (or I don&#8217;t have a way to see if it does) and so studying them would be less than useful for everything I am trying to do.  Namely, the things I need to find out yet are:</p>
<ul>
<li>How to run a program in such a way as to be able to reliably know what windows belong to the program and be able to dock them.  I <strong>suspect</strong> that it&#8217;d involve using <code>LD_PRELOAD</code> and some monitoring trickery, but I would hope that there is some sort of API to do this already.  Also, need to know how to manage the application itself; say it continues running but without any windows, the tray icon should obviously disappear while it&#8217;s running like that, until it has windows to manage again.</li>
<li>How to perform session management and be a session manager for subordinate programs.  (I might be able to study the source for KDocker to learn the answer to that, though I am not 100% certain yet of that.)  I also have a paper to read yet on the subject that may have all the information that I am looking for, though I am not certain there yet, either.</li>
<li>How to reliably detect the running desktop environment without resorting to ugly kludges and ad-hoc trickery.</li>
<li>How to work independent of the currently-running window manager and operate reliably for any standards-compliant WM that is running, without having to special-case for various types of software or various types of window managers.</li>
</ul>
<p>I suspect that there is useful documentation out there for most (if not all) of those things for X11 and other relevant points.  I just haven&#8217;t found what I am looking for yet for all of it.  Standards documents and system documentation are useful things to find, and maybe an example or two of source code on how to do it as well, are what I am looking for, so that I can try to understand these things better.</p>
<p>At some point down the road, I&#8217;ll need help with getting the backends written when they have an API to conform to.  I can, in all probability, write a GTK+ backend that will work for XFCE and GNOME since I use GNOME.  However, I don&#8217;t use KDE or anything that runs on top of Qt, so I will definitely need help from someone that is familiar with writing software for Qt to get a Qt backend written.  If XFCE has any sort of non-standard special UI guidelines that are incompatible with GNOME, then I&#8217;ll need some help there, too.  Any other non-GNOME or non-KDE environments (such as <a href="http://en.wikipedia.org/wiki/GNUstep" title="Wikipedia: GNUstep">GNUstep</a>, if it supports it anyway) that support the <a href="http://standards.freedesktop.org/systemtray-spec/systemtray-spec-latest.html" title="System Tray Protocol Specification">System Tray Protocol Specification</a> will need backends written for them by people that are able to do so.</p>
]]></content:encoded>
			<wfw:commentRss>http://mike.trausch.us/blog/2008/10/21/on-replacing-alltray-other-docking-software/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Want to play with Mono 2.0?  So do I&#8230;</title>
		<link>http://mike.trausch.us/blog/2008/10/13/want-to-play-with-mono-20-so-do-i/</link>
		<comments>http://mike.trausch.us/blog/2008/10/13/want-to-play-with-mono-20-so-do-i/#comments</comments>
		<pubDate>Mon, 13 Oct 2008 21:47:07 +0000</pubDate>
		<dc:creator>Michael Trausch</dc:creator>
				<category><![CDATA[GPLv3]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[computing]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[software testing]]></category>
		<category><![CDATA[mono]]></category>
		<category><![CDATA[mono 2.0]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://www.trausch.us/?p=423</guid>
		<description><![CDATA[Alrighty, so I wanted to play with Mono 2.0. I thought about packaging it up, but the packaging for Mono in Debian and Ubuntu is extremely complex, and would have taken me a lot of time that I simply don&#8217;t have. So, instead, I wrote a BASH script that pulls Mono 2.0 and friends from [...]]]></description>
			<content:encoded><![CDATA[<p>Alrighty, so I wanted to play with Mono 2.0.  I thought about packaging it up, but the packaging for Mono in Debian and Ubuntu is <em>extremely</em> complex, and would have taken me a lot of time that I simply don&#8217;t have.  So, instead, I wrote a BASH script that pulls Mono 2.0 and friends from the Internet, builds it, and installs it in ${HOME}/opt on your system.  The way it does this is based on <a href="http://www.mono-project.com/Parallel_Mono_Environments">the Parallel Mono Environments</a> page on the Mono Web site.  In the hope that this script will be useful on more than just Ubuntu, it <strong>DOES NOT</strong> try to pull in build-dependencies from the system.  If you&#8217;re using Ubuntu (and this will probably work on Debian, too), you can pull the build-dependencies pretty easily:</p>
<pre>$ sudo apt-get build-dep libgtksourceview2.0-cil \
 libgecko2.0-cil libgtk2.0-cil libgnome2.0-cil mono \
 libgluezilla</pre>
<p>The usage screen for the script:</p>
<pre>Mono 2.0 Home Directory Installer

Copyright (c) 2008 M. Trausch &lt;mike@trausch.us&gt;
License: GPLv3

Total download: ~206 MiB, total installed size: ~161 MiB.
Download &#038; build takes ~35 minutes on an AMD Phenom 9500 Quad-Core CPU w/ 8Mbps
downstream Internet connection (and happy servers, of course).

Logs are output to '/tmp/mono2-build.3044/log'.

usage: install-mono2.sh [options]

Available options:
  -s PKG
  --skip PKG	Skip building package PKG (one of libgdiplus, mono, mono-basic,
		gtk-sharp, gnome-sharp, gnome-desktop-sharp, gluezilla,
		monodoc, mono-tools, mono-addins, gecko-sharp,
		gtksourceview-sharp, heap-buddy, nant, monodevelop).  May
		be specified multiple times.

  -d
  --download-only
		Only download the packages, do not install them.

  -r
  --monodevelop-revision
		Specify which SVN revision of MonoDevelop trunk to install.
		Defaults to SVN HEAD.

  -S
  --skip-download
		Skip the download (if you're rebuilding, use this to
		save bandwidth.

  -m
  --monodevelop	Download, build, and install MonoDevelop only.  ONLY USEFUL
		FOR UPDATING MONODEVELOP AFTER YOU'VE RUN THIS SCRIPT TO
		INSTALL MONO 2.0.

  -1
  --single-cpu	Use ONLY single CPU/core for building.  Use this if you have
		trouble building and think it might be related to 'make -j'.</pre>
<p>Now, when this script runs, it will download the Mono files (and MonoDevelop from SVN) into <code>/tmp/monosrc</code>.  It will do the build in <code>/tmp/mono2-build.XXXXX</code> where <code>XXXXX</code> is the process ID number of the <code>install-mono2.sh</code> script.  When you&#8217;re finished and happy with the installation, you can safely remove those directories:</p>
<pre>$ rm -Rf /tmp/mono2-build.* /tmp/monosrc</pre>
<p><strong>If you want to track MonoDevelop within SVN</strong>, then it is better to <em>not</em> delete <code>/tmp/monosrc</code>, because the script uses <code>svn</code> to pull from the MonoDevelop Subversion repository.  This means that it can, if the directory already exists, save you bandwidth by only pulling a delta from the revision that you have and the current HEAD revision.  The astute probably noticed that you can select a revision explicitly as well.  I am currently using r115695, and have used it for a grand total of 20 minutes (and debugging, as best as I can tell, works quite wonderfully in it, but it <em>is</em> a work-in-progress, coming directly from the development mainline).  In short, the MonoDevelop is great for toying with but not for production use.  I may release a version of this script that lets you choose between the latest stable released version of MonoDevelop and an SVN revision, but I haven&#8217;t gotten there yet because I wanted to play with the SVN version (which uses features in Mono 2.0&#8230; that was the whole point of me wanting to play with Mono 2.0, actually).</p>
<p>In any case, the script is available for download <a href='http://www.trausch.us/wp-content/uploads/install-mono2.sh'>here from my Web site.</a></p>
<p>A few words about the script:  <strong><em>This script is released under the terms of the <a href="http://www.gnu.org/licenses/gpl-3.0.html">GNU General Public License, Version 3</a>.  It is version 3 ONLY.  There is NO SUPPORT for this software; I wrote it for myself, and it may change or it may stagnate.  I provide it in the hope that it is useful to someone out there other than myself, but it is AS-IS, WITHOUT WARRANTY, UNSUPPORTED software.  If it changes your dog&#8217;s gender, bursts your house into flames, destroys your whatchamacallermicroflobbermajag, do not come and yell at me.</em></strong>  That having been said, I welcome any modifications (at least to view them).  You can modify it for your own use, you can share it (in fact I expect you to!) and you can tinker with and tweak it.  Suggestions?  Welcome!  Comments?  Welcome!  Flames?  Hey, free speech is your right&#8230;</p>
<p>Lastly, <strong>I RECOMMEND THAT YOU RUN THE SCRIPT ON A CLEAN USER ACCOUNT, WITHOUT YOUR DATA, WITHOUT YOUR ANYTHING IN THE WAY.</strong>  Just create yourself another user, and login to it using Xnest or something, or log out of your user account completely—I don&#8217;t care how you do it.  Why do I make this recommendation?  Because while nothing bad should happen, it&#8217;s always best to sandbox things that you don&#8217;t trust.  After all, what reason do you have to trust me if you don&#8217;t know me?  You can also of course read through the script and audit it if you wish.  It doesn&#8217;t handle EVERY exceptional condition, but it handles just about anything that needs to be and tells you where things went awry if they go wrong.  And it logs everything (see the program output when you run it).  It also takes advantage of multiple processors or cores if you have them for those (few) builds that will permit it without going nutso, but YMMV.  If you have an issue with this aspect of the script, see the usage text.  If there are any issues that you can&#8217;t solve with that, or installing build-dependencies, then paste the relevant segments of your failing log file to something like <a href="http://pastebin.com/">pastebin</a> and ping me a comment here, and I can take a look at it and (try to) offer advice, depending on where the fail is.</p>
<p>Oh, yeah, and I used a hell of a lot of bandwidth putting it together and making sure that it did things like downloaded things right and all of that.  Sorry for hitting your servers repeatedly, Mono people—and thank you for the software!</p>
]]></content:encoded>
			<wfw:commentRss>http://mike.trausch.us/blog/2008/10/13/want-to-play-with-mono-20-so-do-i/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Sometimes, learning happens strangely</title>
		<link>http://mike.trausch.us/blog/2008/10/09/sometimes-learning-happens-strangely/</link>
		<comments>http://mike.trausch.us/blog/2008/10/09/sometimes-learning-happens-strangely/#comments</comments>
		<pubDate>Thu, 09 Oct 2008 18:43:58 +0000</pubDate>
		<dc:creator>Michael Trausch</dc:creator>
				<category><![CDATA[Stuff I Read]]></category>
		<category><![CDATA[computing]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[software testing]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[JIT]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[mono]]></category>

		<guid isPermaLink="false">http://www.trausch.us/?p=404</guid>
		<description><![CDATA[So, I was dinking around in Google Reader yesterday and reading my Daily WTF, when I came across this wonderful post. Of course, upon seeing the code listed in that post, I nearly excremented bricks, the code listed there being obviously stupid (I would so fire anyone that used 14 levels of nested if statements [...]]]></description>
			<content:encoded><![CDATA[<p>So, I was dinking around in Google Reader yesterday and reading my Daily WTF, when I came across <a href="http://thedailywtf.com/Articles/Out-of-All-the-Possible-Answers.aspx" title="Out of All the Possible Answers...">this wonderful post</a>.  Of course, upon seeing the code listed in that post, I nearly excremented bricks, the code listed there being <em>obviously</em> stupid (I would <strong>so</strong> fire anyone that used 14 levels of nested <code>if</code> statements when they are obviously not necessary, assuming that I were a manager of programmers).  Anyway, I followed the link to <a href="http://projecteuler.net/index.php?section=problems&#038;id=5" title="Project Euler: Problem 5">the problem</a> the code solved, and started poking around that Web site, and found myself wildly fascinated with it.</p>
<p>So, I signed up for it and decided that I would start with the first problem and work my way through them, using the problems to also try to learn or confirm various things that I know/think are true.  I&#8217;ve been using the C# programming language for some time now, so I thought, “What the hell, I’ll go ahead and do these and see what I learn.”  Having worked the first problem, I found some rather interesting things out about the Mono and .NET runtimes.</p>
<p>Firstly, I learned that the .NET runtime&#8217;s implementation of DateTime and/or TimeSpan sucks (my guess is DateTime is what sucks).  It is not capable of measuring very small amounts of time, say smaller than one hundredth or one thousandth of a second, and treats those small amounts of time as if they were zero time at all.  Which means that under .NET 2.0, I cannot measure things like I can under Mono.  Oh, well, I suppose.</p>
<p>I wrote a small program to compute the answer to <a href="http://projecteuler.net/index.php?section=problems&#038;id=1" title="Project Euler: Problem 1">the first problem</a>, and wrote a small library routine that computes the time spent computing the solution.  The program runs each method twice (because <a href="http://www.ddj.com/windows/184416872" title="Dr. Dobb's: .NET JIT Performance">the “JITter” compiles methods to native code upon the first invocation of a method</a>), and measures the execution time each time.</p>
<p>So, I implemented 5 different solutions to <a href="http://projecteuler.net/index.php?section=problems&#038;id=1" title="Project Euler: Problem 1">the problem</a>.</p>
<pre lang="c#">   public static void BruteForceMethod() {
    int total = 0;

    for(int i = 1; i < 1000; i++) {
      if((i % 3 == 0) || (i % 5 == 0)) {
        total += i;
      }
    }

    Console.WriteLine("The answer is {0} (brute force method).", total);
  }</pre>
<p>This is what I call the “brute force” method.  It is simple:  It checks every single number to determine if it is evenly divisible by either 3 or 5.  If so, it adds it to the total.  Pretty clear.</p>
</pre>
<pre lang="c#">  public static void SetMethod() {
    int total = 0;

    for(int i = 3; i < 1000; i += 3) {
      total += i;
    }

    for (int i = 5; i < 1000; i += 5) {
      if(i % 3 == 0) continue;
      total += i;
    }

    Console.WriteLine("The answer is {0} (set method).", total);
  }</pre>
<p>This method, I call the "set" method, because it breaks down the space a bit; instead of stepping through 1 to 999 using an increment of 1, it steps through 3 to 999 with a step of 3 and then 5 to 999 with a step of 5.  In the second pass, it checks to see if the number is _also_ evenly divided by 3, and if so, doesn't add it a second time.</p>
</pre>
<pre lang="c#">  public static int HelperMod(int target, int modBy) {
    int tmp = target / modBy;
    return(modBy * tmp * (tmp + 1) / 2);
  }

  public static void HelperMethod() {
    int target = 999;
    int total = HelperMod(target, 3) + HelperMod(target, 5) -
      HelperMod(target, 15);

    Console.WriteLine("The answer is {0} (helper method).", total);
  }</pre>
<p>These two methods together are the &#8220;helper method&#8221;.  I didn&#8217;t come up with this one, one of the other problem solvers did, in Ruby (though their implementation was a slight bit different, the method of operation is the same).  This one uses more in-depth math to perform the computation, instead of a larger number of simpler math operations.  Specifically, the function:</p>
<div style="text-align: center;"><img src="http://www.trausch.us/wp-content/uploads/equation.png" alt="f(x,y) = (x(y/x(y/x+1)))/2 = (y^2+xy)/(2x)" title="equation" width="270" height="46" class="aligncenter size-medium wp-image-406" /></div>
<p>&#8230; where <em>x</em> is the interval and <em>y</em> is the inclusive upper limit on the natural number, provides the result.  The middle value is the calculation I extracted from the Ruby code, and the simplified form on the right is how it&#8217;d be done if it were being done by hand (and is far less confusing for humans).</p>
<pre lang="c#">  public static void TableMethod() {
    int[] numbers = { 10, 100, 102, 105, 108, 110, 111, 114, 115, 117,
                      12, 120, 123, 125, 126, 129, 130, 132, 135, 138,
                      140, 141, 144, 145, 147, 15, 150, 153, 155, 156,
                      159, 160, 162, 165, 168, 170, 171, 174, 175, 177,
                      18, 180, 183, 185, 186, 189, 190, 192, 195, 198,
                      20, 200, 201, 204, 205, 207, 21, 210, 213, 215,
                      216, 219, 220, 222, 225, 228, 230, 231, 234, 235,
                      237, 24, 240, 243, 245, 246, 249, 25, 250, 252,
                      255, 258, 260, 261, 264, 265, 267, 27, 270, 273,
                      275, 276, 279, 280, 282, 285, 288, 290, 291, 294,
                      295, 297, 3, 30, 300, 303, 305, 306, 309, 310,
                      312, 315, 318, 320, 321, 324, 325, 327, 33, 330,
                      333, 335, 336, 339, 340, 342, 345, 348, 35, 350,
                      351, 354, 355, 357, 36, 360, 363, 365, 366, 369,
                      370, 372, 375, 378, 380, 381, 384, 385, 387, 39,
                      390, 393, 395, 396, 399, 40, 400, 402, 405, 408,
                      410, 411, 414, 415, 417, 42, 420, 423, 425, 426,
                      429, 430, 432, 435, 438, 440, 441, 444, 445, 447,
                      45, 450, 453, 455, 456, 459, 460, 462, 465, 468,
                      470, 471, 474, 475, 477, 48, 480, 483, 485, 486,
                      489, 490, 492, 495, 498, 5, 50, 500, 501, 504,
                      505, 507, 51, 510, 513, 515, 516, 519, 520, 522,
                      525, 528, 530, 531, 534, 535, 537, 54, 540, 543,
                      545, 546, 549, 55, 550, 552, 555, 558, 560, 561,
                      564, 565, 567, 57, 570, 573, 575, 576, 579, 580,
                      582, 585, 588, 590, 591, 594, 595, 597, 6, 60,
                      600, 603, 605, 606, 609, 610, 612, 615, 618, 620,
                      621, 624, 625, 627, 63, 630, 633, 635, 636, 639,
                      640, 642, 645, 648, 65, 650, 651, 654, 655, 657,
                      66, 660, 663, 665, 666, 669, 670, 672, 675, 678,
                      680, 681, 684, 685, 687, 69, 690, 693, 695, 696,
                      699, 70, 700, 702, 705, 708, 710, 711, 714, 715,
                      717, 72, 720, 723, 725, 726, 729, 730, 732, 735,
                      738, 740, 741, 744, 745, 747, 75, 750, 753, 755,
                      756, 759, 760, 762, 765, 768, 770, 771, 774, 775,
                      777, 78, 780, 783, 785, 786, 789, 790, 792, 795,
                      798, 80, 800, 801, 804, 805, 807, 81, 810, 813,
                      815, 816, 819, 820, 822, 825, 828, 830, 831, 834,
                      835, 837, 84, 840, 843, 845, 846, 849, 85, 850,
                      852, 855, 858, 860, 861, 864, 865, 867, 87, 870,
                      873, 875, 876, 879, 880, 882, 885, 888, 890, 891,
                      894, 895, 897, 9, 90, 900, 903, 905, 906, 909,
                      910, 912, 915, 918, 920, 921, 924, 925, 927, 93,
                      930, 933, 935, 936, 939, 940, 942, 945, 948, 95,
                      950, 951, 954, 955, 957, 96, 960, 963, 965, 966,
                      969, 970, 972, 975, 978, 980, 981, 984, 985, 987,
                      99, 990, 993, 995, 996, 999 };
    int total = 0;

    foreach(int num in numbers) total += num;
    Console.WriteLine("The answer is {0} (table method).", total);
  }</pre>
<p>In this method, I precomputed the numbers that needed to be added together (using <code>(for i in 3 5; do for j in $(seq 0 $i 999); do echo $j; done; done) | sort | uniq | tr '\n' ',' | sed 's/,/, /g;s/, $/\n/g;'</code>, goodness Unix is great) and put them into an array, adding each of the values of the array together to come up with the total.</p>
<p>Finally, there&#8217;s this method:</p>
<pre lang="c#">  public static void PrecomputedMethod() {
    int total = 233168;

    Console.WriteLine("The answer is {0} (precomputed).", total);
  }</pre>
<p>This method simply contains the answer and prints it.</p>
<p>So, what can be learned from this?  Let&#8217;s take a look at a single run:</p>
<pre>Project Euler: Problem 1
Find the sum of all the multiples 3 OR 5 that are below 1,000.

The answer is 233168 (brute force method).
Execution time: 00:00:00.0184820

The answer is 233168 (brute force method).
Execution time: 00:00:00.0000600

The answer is 233168 (set method).
Execution time: 00:00:00.0001280

The answer is 233168 (set method).
Execution time: 00:00:00.0000100

The answer is 233168 (helper method).
Execution time: 00:00:00.0001300

The answer is 233168 (helper method).
Execution time: 00:00:00.0000070

The answer is 233168 (table method).
Execution time: 00:00:00.0001870

The answer is 233168 (table method).
Execution time: 00:00:00.0000110

The answer is 233168 (precomputed).
Execution time: 00:00:00.0000650

The answer is 233168 (precomputed).
Execution time: 00:00:00.0000070</pre>
<p>So, we run through each of these twice, and display the time computed to be the runtime for each method.  (I&#8217;ll show just how I did that here in a little bit, it was pretty simple.)  The obvious thing is that for each method, the first execution was a good deal slower than the second method, usually by more than an order of magnitude.  That shows the delay created by JIT compilation of the method.  It also shows that the very first brute-force method JIT takes longer than any of the others.  My hypothesis there was that the methods called after the first one benefited from some sort of caching (probably at the hardware level) in working with the opcodes for the for loop in the Mono runtime.  It wouldn&#8217;t make sense for it to be a delay in JIT itself, since by the time we start measuring things, the JIT has already compiled at least 5 different methods, and probably more depending on the internal implementation of things such as <code>System.Console.Write</code> and <code>System.Console.WriteLine</code>.  By changing the order of execution and moving the brute force method to be the second one tested, that would seem to be the case:</p>
<pre>Project Euler: Problem 1
Find the sum of all the multiples 3 OR 5 that are below 1,000.

The answer is 233168 (set method).
Execution time: 00:00:00.0179120

The answer is 233168 (set method).
Execution time: 00:00:00.0000600

The answer is 233168 (brute force method).
Execution time: 00:00:00.0001400

The answer is 233168 (brute force method).
Execution time: 00:00:00.0000410

The answer is 233168 (helper method).
Execution time: 00:00:00.0001310

The answer is 233168 (helper method).
Execution time: 00:00:00.0000080

The answer is 233168 (table method).
Execution time: 00:00:00.0001760

The answer is 233168 (table method).
Execution time: 00:00:00.0000100

The answer is 233168 (precomputed).
Execution time: 00:00:00.0000670

The answer is 233168 (precomputed).
Execution time: 00:00:00.0000080</pre>
<p>Now, the set method contains the longest delay.  That is an interesting find; it would seem to confirm that the JIT benefits somewhat from some form of caching.  Just what caching, I don&#8217;t exactly know, and I don&#8217;t know how to find that out just yet.</p>
<p>In any event, we know that the first time we call each of these methods, the JIT converts the method from IL bytecode into native object code, and then executes the native object code.  Pretty nice, that.  On subsequent runs of the method, no more JIT needs to be done, and so the method&#8217;s object code executes directly, since that is retained in memory by the Mono runtime.</p>
<p>Now, let&#8217;s take a look at the runtimes for each method type, specifically, the second run of each, from the first run above:</p>
<div style="text-align: center;">
<table style="text-align: center; margin-left: auto; margin-right: auto;">
<tr>
<th>Method</th>
<th>Execution Time</th>
</tr>
<tr>
<td>Brute Force</td>
<td>0.0000600 sec</td>
</tr>
<tr>
<td>Table</td>
<td>0.0000110 sec</td>
</tr>
<tr>
<td>Set</td>
<td>0.0000100 sec</td>
</tr>
<tr>
<td>Helper</td>
<td>0.0000070 sec</td>
</tr>
<tr>
<td>Precomputed</td>
<td>0.0000070 sec</td>
</tr>
</table>
</div>
<p>These are interesting in that they show what&#8217;s more efficient, relatively speaking.  The &#8220;brute force&#8221; method is clearly the loser.  Though if you look at the second output above, you&#8217;ll notice that the &#8220;set&#8221; method lost when it was first in line.  Still, though, we can see from the two sets of numbers that the brute force method takes longer than the set method even when run in the same place.  That&#8217;s not surprising, because it is a stupid <code>for</code> loop compared to two more intelligently designed <code>for</code> loops.  The fact that the table method performs fairly similarly to the set method was expected, and shows that they are roughly the same in terms of efficiency.</p>
<p>Perhaps what I found the <em>most</em> interesting was the execution time of the helper method.  It&#8217;s nearly the same (well, it <strong>is</strong> the same, in this run) as the static answer, even though there are 3 additional function calls.  The JIT compiler can inline methods when it sees fit, and I am going to wager a guess that is exactly what it did, so the helper method winds up being nothing more than a calculation which then gets printed.  The interesting part is that both methods compile to what one would expect in IL bytecode (that is, the method calls and such are preserved), so any inlining that is happening would be happening at runtime, when the JIT compiler evaluates <code>HelperMethod()</code> and <code>HelperMod()</code>.</p>
<p>Alright, so this made me more curious, and I wanted to see what would happen if there were an <acronym title="Ahead-of-Time">AOT</acronym> compiled version of the code on my system.  So I compiled both the executable and the small library that I made to time execution using Mono&#8217;s <code>--aot</code> flag.  I saw no difference; I am going to guess for the time being that the version of Mono in Intrepid doesn&#8217;t do AOT quite right.  It&#8217;s lacking some of the functionality of Mono 2.0 that enables you to force the AOT binaries to be the only thing executed, and so I am not quite sure what is happening there.  It&#8217;s not majorly important for my purposes, though, so I&#8217;m just not going to pursue that any further now.</p>
<p>The only lingering question left is &#8220;how efficient is the JITted code compared to native binary code?&#8221;  To answer that, of course, the program has to be done in C.  Not a big issue, here&#8217;s the output from a compiled C version, compiled using <code>gcc -o p1 p1.c</code>, along side with the first run from earlier, with the program info header removed for space reasons.:</p>
<table>
<tr>
<th>C Version</th>
<th>C# Version</th>
</tr>
<tr>
<td>
<pre>The answer is 233168 (brute force method)
Execution time: 00:00:00.0000460 sec

The answer is 233168 (brute force method)
Execution time: 00:00:00.0000300 sec

The answer is 233168 (set method)
Execution time: 00:00:00.0000110 sec

The answer is 233168 (set method)
Execution time: 00:00:00.0000110 sec

The answer is 233168 (helper method)
Execution time: 00:00:00.0000050 sec

The answer is 233168 (helper method)
Execution time: 00:00:00.0000070 sec

The answer is 233168 (table method).
Execution time: 00:00:00.0000160 sec

The answer is 233168 (table method).
Execution time: 00:00:00.0000090 sec

The answer is 233168 (precomputed).
Execution time: 00:00:00.0000030 sec

The answer is 233168 (precomputed).
Execution time: 00:00:00.0000030 sec</pre>
</td>
<td>
<pre>The answer is 233168 (brute force method).
Execution time: 00:00:00.0184820

The answer is 233168 (brute force method).
Execution time: 00:00:00.0000600

The answer is 233168 (set method).
Execution time: 00:00:00.0001280

The answer is 233168 (set method).
Execution time: 00:00:00.0000100

The answer is 233168 (helper method).
Execution time: 00:00:00.0001300

The answer is 233168 (helper method).
Execution time: 00:00:00.0000070

The answer is 233168 (table method).
Execution time: 00:00:00.0001870

The answer is 233168 (table method).
Execution time: 00:00:00.0000110

The answer is 233168 (precomputed).
Execution time: 00:00:00.0000650

The answer is 233168 (precomputed).
Execution time: 00:00:00.0000070</pre>
</td>
</tr>
</table>
<p>Clearly, that is faster.  Of course, we already knew that would happen because 100% of the compilation for a C program is done by the C compiler, the assembler, and then the binary is put together by the linker for a specific operating system and CPU architecture combination.  But&#8230; look at those numbers again, and there is one thing that is unexpected—at least it was to me.  The helper method has the same execution time when JITted under Mono as when compiled ahead of time by GNU GCC for one of the invocations. The set method was pretty close, too.  And comparing the JITted code execution time with the code output by GCC shows that Mono&#8217;s JIT compiler isn&#8217;t doing a horrible job with compiling things.  It could do better, but it&#8217;s not doing bad.</p>
<p>If you want to check it all out yourself, the both the C code and the C# code are available here: <a href='http://www.trausch.us/wp-content/uploads/euler-p1.zip'>Source code for Euler Problem 1 (C and C#)</a>.  But, having learned all of this, and compared the two programs together, I have to say that I am pretty pleased to see how well Mono performs something like this.  It&#8217;s surely a very, very small sample, and it&#8217;s not an authoritative, tell-all benchmark—just some informal little tests, running things a few more times, and seeing what happens.  But it&#8217;s telling enough to help figure things out when trying to determine, say, how much the delay on the first invocation to a method will be, or something like that.  It&#8217;s fascinating to me, anyway.  And I think that it shows the potential that the Mono runtime has, too.  There&#8217;s no (technical) reason to avoid using Mono, clearly.</p>
]]></content:encoded>
			<wfw:commentRss>http://mike.trausch.us/blog/2008/10/09/sometimes-learning-happens-strangely/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>&#8220;It&#8217;s Not About Lines of Code&#8221;</title>
		<link>http://mike.trausch.us/blog/2008/05/08/its-not-about-lines-of-code/</link>
		<comments>http://mike.trausch.us/blog/2008/05/08/its-not-about-lines-of-code/#comments</comments>
		<pubDate>Thu, 08 May 2008 18:11:33 +0000</pubDate>
		<dc:creator>Michael Trausch</dc:creator>
				<category><![CDATA[Stuff I Read]]></category>
		<category><![CDATA[computing]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[metrics]]></category>
		<category><![CDATA[question]]></category>

		<guid isPermaLink="false">http://www.trausch.us/2008/05/08/its-not-about-lines-of-code/</guid>
		<description><![CDATA[I just read an interesting article on how lines of code are a poor measure of a programmer’s productivity. Of course, it makes sense to me: some of the projects I have worked on have been cut in half in my work on them, and many in at least 3/4, because of the way that [...]]]></description>
			<content:encoded><![CDATA[<p>I just read an <a href="http://www.developer.com/java/other/article.php/988641">interesting article</a> on how lines of code are a poor measure of a programmer’s productivity.  Of course, it makes sense to me: some of the projects I have worked on have been cut in half in my work on them, and many in at least 3/4, because of the way that I write code.  Sometimes, there is nothing to do <em>but</em> add code, but I have found that more often than not, this is not the case for many projects—particularly closed-source ones—where code often has a <em>lot</em> of room for improvement.</p>
<p>But, managers like metrics.  So, the question remains, how do you metricize jobs like programming jobs, where quantitative measures are relatively meaningless?  Quality is what matters in software production, not quantity of code, and quality of software is something that (while widely agreed upon in terms of its definition) is a non-objective measure.  Some might wonder how I can call it subjective.  Easy:  Nearly everyone would agree that writing readable code is a good thing when it comes to programming.  However, two programmers can differ widely in their opinion of what&#8217;s easily readable and what&#8217;s not.  Or, programmers A and B might agree that code duplication is a bad thing, but programmer A might take that to mean that code that performs similar tasks should be consolidated and simplified, and programmer B might take it to mean that only duplicate code is bad, and not necessarily duplicate functionality (I have seen that happen before, and honestly the position programmer B takes is easily defensible if programmer B claims that even apparently identical code has different technical purposes, but then things boil down to semantics).</p>
<p>Even worse, programming is largely arbitrary:  Ask ten programmers to write code to perform action <em>x</em>, and you&#8217;ll likely get ten very different implementations.  These variations can even occur among programmers who have similar experience and knowledge, because everyone has a different writing style.  So, programming can be likened to writing something in human languages in a way.  How are authors of human written-language works “graded” on their writing performance?  I&#8217;d imagine that it&#8217;s probably also something arbitrary, maybe popularity.  However we know that <a href="http://www.gnu.org/gnu/why-gnu-linux.html" title="GNU: “Why GNU/Linux?”">popularity is bad compared to various other things (see ¶ 8 here for an example)</a>, depending on the goal you are trying to accomplish.  So, if the goal is high-quality software, popularity isn&#8217;t necessarily a marker of that, and isn&#8217;t appropriate either.  After all, Windows is the most popular system around—and it&#8217;s not what I&#8217;d call of remarkably high quality.</p>
<p>I&#8217;d like to think that I have an answer to it, but I don&#8217;t, really.  If I were going to hire a programmer, my test for them would be to take something real-world, fairly trivial in nature in the language I was hiring them for, and ask them to make a modification that suited a particular purpose.  If I liked the result, I&#8217;d (probably) hire them.  If I thought it was nasty and ugly and it didn&#8217;t need to be, I probably won&#8217;t hire them.  Either way, I&#8217;d probably award more weight to their code if they can successfully (again, in my view) defend the reason they wrote it the way that they did, and held their explanation well, and maybe even convinced me of it if I wasn&#8217;t to begin with.  After all, there are <em>some</em> times in a programmer&#8217;s life where they will have to write code that they must defend in an argument.  That&#8217;s the nature of the best—and it&#8217;s highly subjective.</p>
<p>What sort of metrics have you seen in the field of programming?  Is it lines of code, or average successful implementation time of features/projects, or number of hours that other people have to spend to understand your code?  What about in single-programmer environments (though I am not sure that I know anyone out there in that situation)?</p>
]]></content:encoded>
			<wfw:commentRss>http://mike.trausch.us/blog/2008/05/08/its-not-about-lines-of-code/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

