<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Rambles around computer science</title>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/</link>
    <description>Diverting trains of thought, wasting precious time</description>
    <language>en</language>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>blosxom/2.1.2</generator>

  <item>
    <title>A curiously recurring explanation</title>
    <pubDate>Sat, 23 Feb 2013 19:58:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2013/02/23#curiously-recurring</link>
    <category>/devel</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/devel/curiously-recurring</guid>
    <description>
&lt;p&gt;In conversation recently(-ish), 
I tried to explain the infamous &lt;a href=&quot;http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern&quot;&gt;Curiously Recurring Template Pattern&lt;/a&gt; (CRTP) of C++
by relating it to mixins. 
That just turned one surprisingly tricky problem into two. 
Here I will try to rectify both problems by proivding a somewhat coherent explanation
of how to realise mixins using CRTP.
&lt;/p&gt;

&lt;pre&gt;
/* defining a mixin */
template &amp;lt;class Instantiator&amp;gt;
class my_mixin
{
	int some_state;
public:
	void invoke_feature() { /* using some_state, somehow */ }
};

/* &quot;mixing in&quot; a mixin */
class built_from_mixins
 : public 
      my_mixin&amp;lt;built_from_mixins&amp;gt; /* , other mixins ... */
{
    /* ... */
};
&lt;/pre&gt;

&lt;p&gt;
Unlike normal base classes, 
a mixin is designed to attach at an arbitrary point 
in the subtyping hierarchy. 
It&apos;s an orthogonal feature that can be &amp;ldquo;mixed in&amp;rdquo; to many 
potential classes, rather than an increment on a particular class.
Therefore, rather than referencing a specific base class, 
a mixin leaves this reference unbound. 
Nevertheless, it still gives a name to the class it is extending. 
Here it is called 
&lt;tt&gt;Instantiator&lt;/tt&gt;. 
This can be thought of as a &amp;ldquo;forward reference&amp;rdquo;
to the class that is &amp;ldquo;mixing it in&amp;rdquo;. 
The name is a placeholder for 
the class that the programmer will extend using the mixin. 
&lt;/p&gt;

&lt;p&gt;
(There are other variations on this theme 
in other mixin-like constructs. 
Anyone interested in the many meanings of &amp;ldquo;mixin&amp;rdquo; 
could do worse than to start with Richard Gabriel&apos;s 
&lt;a href=&quot;http://www.dreamsongs.com/Files/Incommensurability.pdf&quot;&gt;essay&lt;/a&gt; which is based around this subject&amp;mdash;
though I note that its actual point about incommensurability is deeper, completely distinct, and 
very interesting!)
&lt;/p&gt;

&lt;p&gt;
Looking at the code, we see there is a 
cyclical reference chain: from the mixin user 
&lt;tt&gt;built_from_mixins&lt;/tt&gt; 
to a specialisation of the mixin itself &lt;tt&gt;my_mixin&amp;lt;built_from_mixins&amp;gt;&lt;/tt&gt;
&lt;em&gt;and back&lt;/em&gt; (via &lt;tt&gt;Instantiator&lt;/tt&gt;, which 
is instantiated to &lt;tt&gt;built_from_mixins&lt;/tt&gt;). 
These references are a bit strange. 
We haven&apos;t even defined &lt;tt&gt;built_from_mixins&lt;/tt&gt; at the point where 
we use it to parameterise our mixin instance. 
Why does the compiler even allow this?
&lt;/p&gt;

&lt;p&gt;
The answer is that of course it&apos;s allowed, and 
the compiler allows it simply by 
virtue of the usual C++ (and C) rules about incomplete types. 
Cyclic reference among data type definitions is not unique to mixins. 
Consider a linked list, where it&apos;s no problem to 
create a recursive &amp;ldquo;next&amp;rdquo; pointer inside 
the list node type. Since pointers-to-incompletes are allowed, 
and the list node type is just another incomplete type at that location in the code, 
the code compiles fine. 
&lt;/p&gt;

&lt;p&gt;
It takes only a small generalisation to apply this not just to incomplete pointer target types, 
but more generally to incomplete types used as template parameter instances. 
Of course we can refer to &lt;tt&gt;built_from_mixins&lt;/tt&gt; inside its own 
inheritance clause&amp;mdash;but we can only do things 
that we can do with an incomplete type.
Using it as a template parameter is one such thing&amp;mdash;so long as 
the template&apos;s definition is consistent with its parameter being incomplete. 
In particular, possible usages of &lt;tt&gt;Instantiator&lt;/tt&gt; inside &lt;tt&gt;my_mixin&lt;/tt&gt;, above, 
are limited if we want to use the incomplete &lt;tt&gt;my_mixin&lt;/tt&gt; as our &lt;tt&gt;Instantiator&lt;/tt&gt;: 
we can only do the things we can do with any other incomplete types inside a class definition. 
Happily, &lt;tt&gt;my_mixin&lt;/tt&gt;&apos;s definition sticks to this regime, so is well-formed. 
Moreover, it itself is a &lt;em&gt;complete&lt;/em&gt; data type! 
(Similarly, if you defined a mutually recursive pair of data types using pointers, 
whichever one of them you defined first in your source file would be complete immediately, 
even though it contains a pointer to the yet-to-be-defined second data type.)
Being complete, our instantiation of &lt;tt&gt;my_mixin&lt;/tt&gt; is fair game for deriving from. 
This is what allows us to 
derive &lt;tt&gt;build_from_mixins&lt;/tt&gt; from &lt;tt&gt;my_mixin&amp;lt;built_from_mixins&amp;gt;&lt;/tt&gt;:
the latter &lt;em&gt;is&lt;/em&gt; complete, 
even though its type parameter &lt;tt&gt;built_from_mixins&lt;/tt&gt; 
(known as &lt;tt&gt;Instantiator&lt;/tt&gt; inside the mixin) isn&apos;t. 
&lt;/p&gt;

&lt;p&gt;
In fact, we haven&apos;t used &lt;tt&gt;Instantiator&lt;/tt&gt; at all inside &lt;tt&gt;my_mixin&lt;/tt&gt;. 
So, why include it? What &lt;em&gt;can&lt;/em&gt; we do with it?
Well, we can safely use it in any way we can use any other incomplete type: 
as a pointer (or reference) target type, 
or as a type parameter.  
An example is &lt;a href=&quot;http://boost.org/&quot;&gt;boost&lt;/a&gt;&apos;s 
&lt;a href=&quot;http://www.boost.org/libs/smart_ptr/enable_shared_from_this.html&quot;&gt;&lt;tt&gt;enable_shared_from_this&lt;/tt&gt;&lt;/a&gt;, 
a mixin which adds the necessary state and member functions 
for allowing a class to provide a &lt;tt&gt;shared_ptr&lt;/tt&gt; version of its &lt;tt&gt;this&lt;/tt&gt; pointer. 
You can&apos;t safely create a &lt;tt&gt;shared_ptr&lt;/tt&gt; from a regular pointer in general 
because you don&apos;t know where the target object&apos;s reference count lives.
The &lt;tt&gt;enable_shared_from_this&lt;/tt&gt; mixin fixes this by embedding a pointer to the refcount, 
in the guise of a &lt;tt&gt;weak_ptr&lt;/tt&gt; subobject, into the mixing-in class. 
The guts of &lt;tt&gt;enable_shared_from_this&lt;/tt&gt; are basically as follows.
&lt;/p&gt;

&lt;pre&gt;
template&amp;lt;class T&amp;gt; class enable_shared_from_this
{
private:
    mutable weak_ptr&amp;lt;T&amp;gt; weak_this_;
public:
    shared_ptr&amp;lt;T&amp;gt; shared_from_this()
    {
        shared_ptr&amp;lt;T&amp;gt; p( weak_this_ );
        return p;
    }
};
&lt;/pre&gt;

&lt;p&gt;
Just as in our first example, we have some private state and a public 
interface which
implement an orthogonal feature that can be &amp;ldquo;mixed in&amp;rdquo;
to any class. The mixin-instantiating class &lt;tt&gt;T&lt;/tt&gt;
is referenced only in an incompleteness-tolerant way, 
to instantiate other templates and (eventually, inside the definition of &lt;tt&gt;weak_ptr&lt;/tt&gt;, which is not shown)
to define a pointer target type.
&lt;/p&gt;

&lt;!--
BUT we can also reference its members (as we&apos;re about to)... 
requiring it to be complete; 
non-sequitur?
--&gt;

&lt;p&gt;
I&apos;ve also seen CRTP described as 
&amp;ldquo;virtual functions without polymorphic behaviour&amp;rdquo;. What does
that mean?  Since our mixin has a reference to its instantiating class, 
it can call its methods&amp;mdash;even though the binding to that specific 
class has not yet been formed. In other words, 
we have deferred the binding of methods&amp;mdash;but not until run time.
Rather, we have deferred them to later in compile time, 
when our templates are elaborated. Let&apos;s look at an example.
&lt;/p&gt;

&lt;p&gt;
Let&apos;s try to get this deferred binding without using CRTP, but also 
without using virtual functions. Unsurprisingly, it doesn&apos;t work. 
The best we can do is to try non-polymorphic inheritance, by writing something like this.

&lt;pre&gt;
class X
{
public:
	void f() { /* unimplemented */ }
	void g() { f(); }
};

class Y : public X
{
public:
	void f() { cout &amp;lt;&amp;lt; &quot;Done something&quot;; }
};
&lt;/pre&gt;

&lt;p&gt;Of course, if we call &lt;tt&gt;X::g()&lt;/tt&gt;, it calls &lt;tt&gt;X::f()&lt;/tt&gt; and not &lt;tt&gt;G::f()&lt;/tt&gt;. 
Using CRTP, we can get it to call &lt;tt&gt;G::f()&lt;/tt&gt; without resorting to virtual functions. 
&lt;/p&gt;

&lt;!--
&lt;p&gt;
this doesn&apos;t do what we want it to! The base class&apos;s function &lt;tt&gt;g()&lt;/tt&gt;
is still bound to the placeholder of &lt;tt&gt;f()&lt;/tt&gt;. To get the behavour we want, which is 
&amp;ldquo;derivation-time binding&amp;rdquo;, we can use CRTP.
&lt;/p&gt;
--&gt;

&lt;pre&gt;
template &amp;lt;class Derived&amp;gt;
class X
{
public:
	void f() { /* unimplemented */ }
	void g() { Derived::f(); }
};
class Y : public X&amp;lt;Y&amp;gt;
{
public:
	void f() { cout &amp;lt;&amp;lt; &quot;Done something&quot;; }
};
&lt;/pre&gt;

&lt;p&gt;
CRTP allows the base class to leave certain functions undefined, 
for definition later in many possible derived classes. 
The derived classes are not derived the usual way, though: 
they are derived using CRTP, passing the derived class
back to the base class as a type parameter.
&lt;/p&gt;

&lt;p&gt;
This sets up a now-familiar kind of cyclic reference: the base class refers to its
(potentially many) derived classes, through its template parameter. 
Having this &amp;ldquo;forward&amp;rdquo; reference, down the inheritance 
hierarchy, as well as the usual backward reference up it, 
is what allows derivation-time binding. It&apos;s also limiting: 
we can&apos;t subsequently &amp;ldquo;re-override&amp;rdquo; &lt;tt&gt;Y::f()&lt;/tt&gt;. 
&lt;tt&gt;Y&lt;/tt&gt;&apos;s method bindings are fixed at derivation time. 
We have to create a new specialization of &lt;tt&gt;X&lt;/tt&gt; and derive
immediately from that, 
using some other means to get at &lt;tt&gt;Y&lt;/tt&gt;&apos;s functionality if we need it. 
&lt;/p&gt;

&lt;p&gt;
Interestingly, note that it&apos;s okay for us to do &lt;tt&gt;Derived::f()&lt;/tt&gt; 
in our &lt;tt&gt;X&lt;/tt&gt; class template. 
This is surprising because at the point where we instantiate &lt;tt&gt;X&lt;/tt&gt;, 
&lt;tt&gt;Derived&lt;/tt&gt; is an incomplete type. 
I mentioned earlier that we were restricted in what we could do with incomplete template parameters, 
but in this case, here we are happily calling a method of ours. 
At definition time, there are at least two possibilities for the code that must 
be generated at the site of our call to &lt;tt&gt;Derived::f()&lt;/tt&gt;, because &lt;tt&gt;f()&lt;/tt&gt; 
might be an instance member function or a static. 
(It could also be a function object overloading &lt;tt&gt;operator()&lt;/tt&gt;.)
When we instantiate &lt;tt&gt;X&lt;/tt&gt;, 
if we read the code strictly top-to-bottom, 
we haven&apos;t yet got to the body of &lt;tt&gt;Y&lt;/tt&gt;, 
so it is not yet decided whether it will define &lt;tt&gt;f()&lt;/tt&gt; as a static or an instance member function. 
Somehow, the compiler is examining looking ahead at the definition of &lt;tt&gt;Y&lt;/tt&gt; 
at the point where it elaborates &lt;tt&gt;X&amp;lt;Y&amp;gt;&lt;/tt&gt;, even though 
&lt;tt&gt;Y&lt;/tt&gt; cannot be complete yet (because we&apos;re in the middle of 
elaborating its base class). 
I must confess, this is where my understanding of the C++ language runs out. 
Thte standard contains complicated rules about name lookup 
in templates&amp;mdash;principally the infamous &amp;ldquo;two-phase name lookup&amp;rdquo;. 
In short, &amp;ldquo;unqualified names&amp;rdquo; in templates are looked up at template definition time, 
whereas &amp;ldquo;qualified names&amp;rdquo; are looked up at instantiation time. 
Clearly our use of &lt;tt&gt;Derived::f()&lt;/tt&gt; is a qualified name. 
No doubt there is some part of the standard detailing how the second-phase lookup 
is permitted (and required) to look into an incomplete type, namely 
&lt;tt&gt;Y&lt;/tt&gt; in our example (incomplete at the time of &lt;tt&gt;X&lt;/tt&gt;&apos;s instantiation), 
to understand the meaning of &lt;tt&gt;Y::f()&lt;/tt&gt;. 
I haven&apos;t yet found a reference to it though. 
If anyone can point me to it, I&apos;d be much obliged.
&lt;/p&gt;</description>
  </item>
  <item>
    <title>Systems versus languages</title>
    <pubDate>Thu, 10 Jan 2013 15:16:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2013/01/10#systems-and-languages</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/systems-and-languages</guid>
    <description>
&lt;p&gt;Somewhere buried within one recent &lt;a
href=&quot;http://www.inf.usi.ch/postdoc/kells/blog/research/tools-or-not-tools.html&quot;&gt;magnum opus&lt;/a&gt; in these
pages  I highlighted a contrast between &lt;em&gt;systems&lt;/em&gt; and &lt;em&gt;languages&lt;/em&gt;.  I
also noted that &lt;a href=&quot;http://www.oopsla.org/oopsla-history/&quot;&gt;OOPSLA&lt;/a&gt;
conspicuously contained the word &amp;ldquo;systems&amp;rdquo; in its title.  This
juxtaposition probably seems incongruous to some, but it is one close to my heart.
I see myself as a researcher tackling problems usually labelled as
&amp;ldquo;programming languages&amp;rdquo;, but with a &amp;ldquo;systems&amp;rdquo; mindset.&lt;/p&gt;

&lt;p&gt;Richard Gabriel&apos;s very interesting &lt;a
href=&quot;http://www.dreamsongs.com/Files/Incommensurability.pdf&quot;&gt;piece&lt;/a&gt; about
incommensurability  in scientific (and engineering) research, using mixins as an
example, makes some remarkably similar observations. (There&apos;s also a &lt;a
href=&quot;http://www.infoq.com/presentations/Mixin-based-Inheritance&quot;&gt;video&lt;/a&gt; of a
presentation from last year&apos;s ClojureWest, but I haven&apos;t yet watched it.) He
distinguishes the &amp;ldquo;engineering&amp;rdquo; papers that first discussed mixins from
the &amp;ldquo;scientific&amp;rdquo; papers that subsequently studied and formalised
them.  And, without disparaging the latter, he very much emphasises the underrated
value of the former.  (He also makes some very incisive observations about apparent
misunderstandings and omissions in the influential &lt;a
href=&quot;http://dx.doi.org/10.1145/97946.97982&quot;&gt;Bracha &amp;amp; Cook paper&lt;/a&gt;. A major
point, of course, is that they need not be 
misunderstandings per se&amp;mdash;incommensurability is the posited explanation.)&lt;/p&gt;

&lt;p&gt;It&apos;s nice to get a historical perspective on these matters, from someone like
Richard Gabriel who has seen a lot of ideas come and go. In part, his appraisal of
the changing role of engineering papers offers me some reassurance that I might not
be crazy. In conversation with other researchers, it can be frustrating that
declaring my interest in programming languages is taken so often to imply that I do
theoretical work. But I am more interested in languages as systems&amp;mdash;my
interest has to do with their &amp;ldquo;useful-for&amp;rdquo; properties, not 
&amp;ldquo;abstractly-is&amp;rdquo; properties. (Of course, I&apos;m glad people are working on
the latter, and I try to relate their findings to what I do... while accepting that
it&apos;s &lt;em&gt;not&lt;/em&gt; what &lt;em&gt;I&lt;/em&gt; do.)  Another interesting historical tidbit is
that Gabriel estimates that my kind of work&amp;mdash;engineering approaches to
programming problems, you could say&amp;mdash;was &amp;ldquo;outlawed&amp;rdquo; from (yikes!)
roughly 1990 to 2005. I suppose it&apos;s handy that I started my PhD in 2006. The feeling
of &amp;ldquo;separate camps&amp;rdquo; is still very much there, of course.&lt;/p&gt;</description>
  </item>
  <item>
    <title>Bridge that gap</title>
    <pubDate>Thu, 06 Dec 2012 11:01:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2012/12/06#bridge-that-gap</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/bridge-that-gap</guid>
    <description>
&lt;p&gt;
I don&apos;t do IDEs. 
&lt;/p&gt;
&lt;p&gt;
(This post isn&apos;t really about IDEs, but humour me.)
&lt;/p&gt;
&lt;p&gt;
I used to do IDEs, back in my Turbo Pascal days. And I &lt;em&gt;want to&lt;/em&gt; now: I value the things
they promise. But the reality, for me, always seems infuriating and limited. They get in my way
more than they help me.
&lt;/p&gt;
&lt;p&gt;
One example: Eclipse. I used Eclipse for Java programming back when I was an undergraduate, and
mostly bent it to my will. Since then I&apos;ve done fairly little Java programming, and a combination
of mind-rot (mine) and evolution (Eclipse&apos;s) has left me sufficiently unfamiliar with recent
versions that I am unable to use them effectively.
&lt;/p&gt;
&lt;p&gt;
I just tried again. I wanted to open a third-party Java codebase&apos;s Eclipse project that I had
downloaded from that codebase&apos;s web page. I am in the Java perspective, and I click the
&amp;ldquo;Project&amp;rdquo; menu, hoping it will let me &amp;ldquo;Open project&amp;rdquo;. But no! &amp;ldquo;Open
project&amp;rdquo; is greyed out. Woe is me. 
&lt;/p&gt;
&lt;p&gt;
Greying out UI elements is a terrible, terrible practice that should never have been invented,
because it doesn&apos;t tell you &lt;em&gt;why&lt;/em&gt; something was greyed out, so leaves you clueless about how
to ungrey it. But no matter. Being a researcher, two ideas occur. Both are ways in which we could,
for &amp;ldquo;little cost&amp;rdquo;,  add back the ability for a program to &lt;em&gt;explain&lt;/em&gt; why a widget
is greyed. 
&lt;/p&gt;
&lt;p&gt;
Idea one: we should really be using some modern programming technology under which the
&amp;ldquo;greyedness&amp;rdquo; state is described declaratively. In that case, the program&apos;s code will
contain a concise description of exactly what causes the menu item to be greyed. I could check out
the code to understand why it was greyed. Or perhaps this condition could be reflectively exported
to the user. Either way, if only we had written our UI in some declarative style! Then our problem
would be easily solved. But, alas, we haven&apos;t written it like that. Instead, greyedness is the
emergence of some maze of twisty little imperative procedures.
&lt;/p&gt;
&lt;p&gt;
Idea two, luckily, is more immediately applicable. Let&apos;s &amp;ldquo;shadow&amp;rdquo; each UI element with some extra
information to do with its greyedness or otherwise. When we set its state to greyed, we snapshot
some property of the program state, like the address of the caller who is turning on greying, or
the whole callchain, or whatever. Then I can somehow query this shadow&amp;mdash;maybe by attaching a debugger
to Eclipse, or whatever&amp;mdash;and have it tell me why it was greyed.
&lt;/p&gt;
&lt;p&gt;
A thought occurs. Is this a general-purpose approach to &amp;ldquo;programs that explain
themselves&amp;rdquo;? (Hat-tip: &amp;ldquo;Functional programs that explain their work&amp;rdquo;, by Perera,
Acar, Cheney and Levy, seeded that phrase in my mind, although the general idea has been with me
for much longer.) Interactively querying for explanations of program state or program output seems
like a general, powerful tool, both for programmers programming and users UI-using. 
&lt;/p&gt;
&lt;p&gt;
Aha! you might say: this could work for a Dr Expert Developer , but there&apos;s a problem for poor Joe
User. The &amp;ldquo;explanations&amp;rdquo; will be in terms of program objects, not &amp;ldquo;something the
user understands&amp;rdquo;. Therefore, you would argue, my approach is not very useful except 
to niche-case users like me. But to this, my rejoinder is: why shouldn&apos;t they understand? If an
object-oriented program is properly abstracted, it will have a &amp;ldquo;surface&amp;rdquo; level of
objects which model the domain as the user sees it. Dialogs and buttons and widgets and text entry
areas are all just objects, and users understand these more-or-less fine (accepting caveats from
the HCI audience). 
&lt;/p&gt;
&lt;p&gt;
It seems to me that paving this continuum, between user-facing and program-level abstractions, is
one of the great promises of object-oriented programming. I wouldn&apos;t say it&apos;s fulfilled, but then,
I wouldn&apos;t say we program in a terribly object-oriented way most of the time. When I was quite a
bit younger, I found it odd that Alan Kay would simultaneously have been working on user
interfaces and on object-oriented programming. More recently I think I have begun to grok this
connection. My latest Eclipse problem is yet more evidence of why it&apos;s a useful one. 
&lt;/p&gt;
&lt;p&gt;
This connection is also one which functional programmers of the Lisp-y, Scheme-y schools
understand. The abstractive power of these languages is supposed to be used&amp;mdash;I&apos;ve heard it said,
at least&amp;mdash;to construct domain-specific abstractions which naturally model the elements of the
program&apos;s work (its &amp;ldquo;objects&amp;rdquo;, you could say, except that here we won&apos;t). In this way,
the program itself is lifted up to a level of abstraction which the user, by definition, would
understand. (Emacs users might be able to tell me how well this can work out... anyone? Oh, all right.)
I lean more towards the object abstraction than the lambda, but perhaps it&apos;s six versus half-a-dozen. 
&lt;/p&gt;
&lt;p&gt;
Perhaps disappointingly, that&apos;s mostly the end of this post. But I can&apos;t resist appending a rant about 
my own work. What I&apos;m convinced of is that the object abstraction is everywhere... it&apos;s just &lt;em&gt;latent&lt;/em&gt; a lot of
the time. It&apos;s in C programs, functional programs, windowing systems, filesystems, OS kernels,
spreadsheets, web browsers, IDEs. It&apos;s latent in any chunk of state at all. Yet the promise of
seamlessly bridging that gap&amp;mdash;of constructing a continuum between the programmatic and the
user-facing&amp;mdash;is not yet with us. That&apos;s because there are hundreds of different ways in which this state has been
constructed and encoded, and no infrastructure unifies them. Classically, we can only shrug and say
that people weren&apos;t enlightened enough to write their code the &amp;ldquo;right way&amp;rdquo;, using the
right languages, targeting the right runtime infrastructure, and so on. But more likely, those &amp;ldquo;right&amp;rdquo;
things were never fully realised, and never will be. Either way, what we need is a
&lt;em&gt;postmodern&lt;/em&gt; object-oriented runtime: one that can find the object abstraction, and present
it to us where it exists, even if that presentation is something of an illusion&amp;mdash;an adaptation,
you could say&amp;mdash;of reality. (This concept is also similar to views in a relational database.)
&lt;/p&gt;

&lt;p&gt;
What would such a runtime look like? What&apos;s a precise definition of the problem it&apos;s solving,
even?  Both of these are hard questions to which I have no complete answer. But it&apos;s no coincidence
my &lt;a href=&quot;http://www.inf.usi.ch/postdoc/kells/#phd&quot;&gt;PhD&lt;/a&gt; was about adaptation (although I&apos;m not saying you should
read it). And my more recent side project on &lt;a
href=&quot;http://www.inf.usi.ch/postdoc/kells/research/papers/kell11virtual-author-preprint.pdf&quot;&gt;DwarfPython&lt;/a&gt; (that I
would love to pursue, if only I could find a way of getting paid for doing so) is also tackling a
subset of the same problem space. Instead of a language implementation owning its object
representation, can we build one which gives up that ownership, but rather takes on the job of
&amp;ldquo;seeing&amp;rdquo; arbitrary chunks of state as objects it can manipulate? The idea of
DwarfPython is to use object producers&apos; debugging information to do just that. More generally, 
in-memory state is not the only kind of object; I also have an interest in unifying files with
objects. Again, rather than the classical approach of persistent programming languages, we can take
a more postmodern approach in which each file has the freedom to represent its contents, or
&amp;ldquo;object state&amp;rdquo;, in a different way, or a variety of ways,  subject to appropriate
interpretation. This is thematically similar to the work of my &lt;a
href=&quot;http://www.inf.usi.ch/postdoc/kells/research/prehistory/&quot;&gt;Bachelor&apos;s dissertation&lt;/a&gt;; although that pursued a far
too classical approach, it was still trying to unify files with objects. So, finding the object
abstraction in unusual places seems to have been a theme of my work from day &amp;#8722;1, even if I
didn&apos;t realise it at the time....&lt;/p&gt;</description>
  </item>
  <item>
    <title>Tools or not tools</title>
    <pubDate>Mon, 03 Dec 2012 11:56:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2012/12/03#tools-or-not-tools</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/tools-or-not-tools</guid>
    <description>
&lt;p&gt;Jim Coplien&apos;s keynote at SPLASH this year was a peculiar one. It featured two particularly
provocative sentiments: firstly that too much abstraction is a bad thing, and secondly
that building tools is not what we want to be doing. (The latter was actually due to Dave
Ungar, during questions, but met with vociferous agreement from the speaker.)&lt;/p&gt;

&lt;p&gt;These remarks met with some puzzlement from much of the audience, judging by a series of
apparently disparaging remarks during subsequent conference talks and question sessions. 
Who could disapprove of abstraction or tools? I think there are some reasonable answers to
that question; what follows is my attempt. (I have no idea whether it coincides with
Coplien&apos;s or Ungar&apos;s.)&lt;/p&gt;

&lt;h4&gt;Abstraction all the way up&lt;/h4&gt;
 
&lt;p&gt;The abstraction issue is perhaps not terribly controversial. Most programmers are aware that
abstractions present a trade-off. The temptation to abstract
endlessly can be a rat-hole that distracts from  actual progress on the task at hand. Ian
Lance Taylor once &lt;a href=&quot;http://www.airs.com/blog/archives/342&quot;&gt;blogged&lt;/a&gt; a fairly similar opinion. If you
abstract too far, you abstract away essential features of the domain, rendering it
unrecognisable. This yields &amp;ldquo;abstractions&amp;rdquo; that are actually 
complex, not simple, to use. Abstracting over multiple use cases, i.e. generality, 
is a common offender here. For example, rolling your own  implementation of a graph algorithm can be easier than
figuring out how to tame the monstrous generality of  something like the Boost graph
library. (Pardon my C++; no doubt you can think of your own examples.)&lt;/p&gt;

&lt;p&gt;Sometimes, abstractions exploit specificity, by packaging up common case usage patterns. This
can be very useful. In fact, in interesting counterpoint to the Taylor piece above was Rustan
Leino&apos;s note about loop structures in a subsequent SPLASH keynote: inferring loop invariants is one
of the hard problems faced by any verifier. By constraining the form of a loop, it becomes easier
to find its invariant. Abstract loops are an extreme case of this, since the loop itself is in
library code and not in user code, so the invariant need be found only once. But of course, just as
Taylor hinted at, any user forcing themselves only to use such loops will end up spending rather a
lot of time structuring their code to accommodate this constraint. (In this way, it shares a lot
with other syntax-directed reasoning tools, including type checkers. These tools  are superficially
easy to market&amp;mdash;hey, look, it shows you bugs in your code. But there is a  hidden cost to
using them, deriving from implicit constraints  on how you can structure your code such that it
interacts nicely with the tool. If you don&apos;t stick to these, your tool fails in some way, like
false-positive type errors  or solver timeouts.)&lt;/p&gt;

&lt;p&gt;To end my rants about abstraction on a complaint, I could also roll out one of my &lt;a
href=&quot;http://www.inf.usi.ch/postdoc/kells/blog/research/functional-programming-not-yet-part-1.html&quot;&gt;previously-blogged&lt;/a&gt;
complaints about common styles of functional programming&amp;mdash;with liberal use of polymorphism, or
unification of higher-order with &amp;ldquo;ordinary&amp;rdquo; operations (think currying, or 
juxtaposition-is-application), code can become needlessly hard to read. Lazy languages add the
unification of storage with computation, which I concede is sometimes an incredibly useful
abstraction, but easily makes the memory behaviour of your program incredibly difficult to
understand.&lt;/p&gt;

&lt;!-- 
examples of &quot;too much abstraction&quot;: 
parser combinators? or other DSLs?
something from the C++ templates world? 
something infamously &quot;click&quot;y? distributed version control systems? 
--&gt;

&lt;h4&gt;What about tools?&lt;/h4&gt; 

&lt;p&gt;For me, the most interesting issue concerns tools. Dave Ungar phrased it something like as
follows: &amp;ldquo;if every bolt under my car had a little handle on it, I wouldn&apos;t need to
get out to go and get a wrench&amp;rdquo;. So, let me frame the contrast I believe he was
making as one of &lt;em&gt;tools versus run-time systems&lt;/em&gt;. Dynamic O-O environments are very
much &lt;em&gt;systems&lt;/em&gt;, geared around the ability to push new capabilities down into the
system&apos;s fabric, rather than having them sit on top.  This &amp;ldquo;fabric&amp;rdquo; 
is what emerges from combining the messaging metaphor (messages are fundamentally
proxyable) with dynamic extensibility (adding new messaging behaviour is a local change
during runtime, not a far-reaching change at compile time). As I have rambled about &lt;a
href=&quot;http://www.inf.usi.ch/postdoc/kells/blog/research/end-to-end-razor.html&quot;&gt;previously&lt;/a&gt;,
the lower some functionality is integrated into a system, the more
pervasively available it is, so the more power and leverage it confers. Smalltalkers and
other dynamic language advocates know this. It&apos;s a very tricky thing to convey to the
unfamiliar. It&apos;s even harder to measure. Most of us don&apos;t use runtimes that have
this amount of dynamism and immediacy, although Javascript may yet change that. 
Operating systems, not least Unix, are also dynamic runtimes in this way, although their 
inability to see inside application means (unfortunately, and avoidably) 
that a large amount of useful code and data (hence potential &amp;ldquo;extension&amp;rdquo;)
is opaque to them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tools are fragmentary; runtimes are integrating&lt;/strong&gt; One reason people develop
tools and not runtime extensions is that integration is hard. If you write a command-line
tool, you get to define its input domain, output domain and behaviour from a clean slate,
according to your convenience. This is often (though not always) easier than plumbing
something into a runtime, which is a bunch of code somebody else wrote. But let&apos;s imagine
making the leap. To get slightly more concrete, suppose the &amp;ldquo;tool&amp;rdquo;
we&apos;re interested in is a dynamic analysis tool&amp;mdash;pick your favourite bug-finding, 
race detection, memory leak detection or other tool that fits the general mould.
What&apos;s better about having it as a &amp;ldquo;runtime&amp;rdquo; rather than just a &amp;ldquo;tool&amp;rdquo;?
Well, its functionality would be embedded right there in your running program. As a consequence,
it supports exploratory, interactive, programmatic use. If you dropped to a REPL in your
program, the innards of the tool would be laid out across your program state,
pushed into fields on program objects. If your tool is a race detector using a lock-set
algorithm, for example, then each object&apos;s lock-set would be accessible as a field on that
object. If you&apos;re using timestamps or vector clocks, they would be there too. You&apos;re also
not stuck with a fixed amount of insight the tool&apos;s authors saw fit to provide
(e.g.&amp;nbsp;when trying to track down the source of a data race); the tool&apos;s code is a
service you&apos;re free to extend. Getting interactive, exploratory, programmatic usage seems like a 
useful payoff for the effort of integrating your tool into a runtime. Arguably, then, 
the challenge is building runtime infrastructures that are not unduly difficult to extend 
like this.&lt;/p&gt; 

&lt;p&gt;&lt;strong&gt;Progress?&lt;/strong&gt; Is the &amp;ldquo;tools not runtimes&amp;rdquo; tendency getting stronger?
&amp;ldquo;Systems, languages, applications&amp;rdquo; is the conference title&apos;s invariant.
&amp;ldquo;Tools&amp;rdquo; is nowhere to be found. My vague impression is that today&apos;s programming
research is more tool-focused, and less system-focused, than 20--30 years ago. (A near-dual
property is also true: self-proclaimed  &amp;ldquo;systems&amp;rdquo; research has less  programming focus
than it used to. I used to bemoan this frequently while doing my PhD in the systems research group
in Cambridge.) But why? Simplistically, we might just say that integration is hard. I think there
is something more subtle at work. Integration of research techniques into runtimes arguably scales 
poorly&amp;mdash;since  we all have to integrate into the same runtime, we have to achieve consensus
on that runtime&apos;s interfaces. Tools, being freestanding
and piecemeal, arguably scale better.  You could say that lots of small, freestanding tools are the
postmodern way,  whereas &amp;ldquo;one true runtime system&amp;rdquo; is a classical ideal. (It&apos;s fitting
that Noble and Biddle&apos;s &amp;ldquo;Notes on Postmodern Programming&amp;rdquo; was recognised at SPLASH this
year for its influence, in the Onward! strand.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Avoiding classical fallacy&lt;/strong&gt; In the battle of the classical versus the
postmodern, normally I side with the postmodern. How can we square this with the desire for the
benefits of the runtime approach as I described it? I should probably save my thoughts for another
post. But two ideas come to mind. The first is one I&apos;ve already mentioned: design a runtime 
infrastructure that is specifically easy to extend. But that seems to be begging the question: if
we knew how to build this magical runtime, and what kinds of extension it would  need to support,
we&apos;d already have done it and solved the problem ages ago. For this reason,  we also need the
second idea:  we need to get into the mindset of tolerating a lot more heterogeneity. Very briefly,
it means pushing radically downwards our notion of  &amp;ldquo;runtime&amp;rdquo; so that most of the
typical implementation decisions of an  object-oriented runtime, such as dispatch mechanisms,
introspection mechanisms and object layout,  are actually &lt;em&gt;user-level&lt;/em&gt; decisions in such a
system, but still &lt;em&gt;recognisable&lt;/em&gt;  as the abstractions they represent. In other words, our
system can descriptively extract  extract &lt;em&gt;latent&lt;/em&gt; object abstractions from the contexts in
which they emerge in existing systems, given &lt;em&gt;descriptions&lt;/em&gt; of these latent abstractions. 
This contrasts with traditional runtimes, in which  the object abstraction &lt;em&gt;constructed&lt;/em&gt; by
the runtime implementor in a way that is  &lt;em&gt;prescriptive&lt;/em&gt;. And hey presto, we are back to my
VMIL 2011 &lt;a href=&quot;http://www.inf.usi.ch/postdoc/kells/research/papers/kell11virtual-author-preprint.pdf&quot;&gt;workshop
paper&lt;/a&gt;:  we already have a very powerful descriptive technology,  in the form of debugging
infrastructure for native code; our task is to bend it to this new purpose. So, end of rant for
today.&lt;/p&gt;
</description>
  </item>
  <item>
    <title>32 bits should be enough for anyone</title>
    <pubDate>Wed, 27 Jun 2012 11:55:00 +0200</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2012/06/27#32bits-enough</link>
    <category>/devel</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/devel/32bits-enough</guid>
    <description>
&lt;p&gt;For a brief while, 32-bit Intel machines were the de facto standard
in commodity hardware , and life was simple. Certainly, it&apos;s an ugly
architecture, gigantically overcomplicated by backwards-compatibility.
Its virtual addressing features are terrifying. But the subset of it
which user-level programmers on modern OSes use is fairly
comprehensible. There is an ISA-defined stack with its own registers and
a well-defined calling convention. Pointers and most integers are both
32 bits, meaning that the &amp;ldquo;word&amp;rdquo; is a useful and
well-understood unit of storage.&lt;/p&gt;

&lt;p&gt;All this changed in the early 2000s as AMD&apos;s 64-bit extension of the
ISA came into popularity. Upon us were forced bigger integers, bigger
pointers, and a more complicated stack and calling convention (in the
name of &amp;ldquo;performance&amp;rdquo;, but at huge cost in complexity). I
believe these were completely retrograde steps. Now that pointers are 64
bits, our software&apos;s memory footprint and disk footprint are bloated
considerably. To &amp;ldquo;alleviate&amp;rdquo; this, and to avoid certain
paradoxes about the size relationships between &lt;tt&gt;short&lt;/tt&gt;,
&lt;tt&gt;int&lt;/tt&gt; and &lt;tt&gt;long&lt;/tt&gt;, an &lt;tt&gt;int&lt;/tt&gt; in most C compilers 
stayed at 32 bits. Unfortunately, this is completely braindead, because
&lt;tt&gt;int&lt;/tt&gt; is very much supposed to be a word-sized type. This is the
reason that C&apos;s &amp;ldquo;defaults to &lt;tt&gt;int&lt;/tt&gt;&amp;rdquo; semantics, as
applying to unprototyped functions and untyped variables, are sane.&lt;/p&gt;

&lt;p&gt;Does this matter? Yes! Here is some code that was mysteriously
segfaulting for me this morning. It&apos;s from &lt;a
href=&quot;http://dtrace.org/&quot;&gt;DTrace&lt;/a&gt;,  or more specifically, Paul Fox&apos;s
&lt;a href=&quot;http://github.com/dtrace4linux/&quot;&gt;Linux port&lt;/a&gt; of it.&lt;/p&gt;

&lt;pre&gt;if ((P-&amp;gt;rap = rd_new(P, P-&amp;gt;pid)) != NULL)
  (void) rd_loadobj_iter(P-&amp;gt;rap, map_iter, P);
&lt;/pre&gt;

&lt;p&gt;Somehow, the pointer returned by the &lt;tt&gt;rd_new&lt;/tt&gt;---which just
wraps a simple &lt;tt&gt;calloc()&lt;/tt&gt; call---gets corrupted immediately after
returning. Suspiciously, said corruption is that the top four bytes are
&lt;tt&gt;0xffffffff&lt;/tt&gt;, whereas the lower four bytes are those of the
pointer returned by &lt;tt&gt;calloc()&lt;/tt&gt;. Inspecting the disassembly
around the &lt;tt&gt;rd_new&lt;/tt&gt; call, we see something suspicious.&lt;/p&gt;

&lt;pre&gt;   0x000000000047ed12 &amp;lt;+150&amp;gt;:   callq  0x462bc6 &amp;lt;rd_new&amp;gt;
=&gt; 0x000000000047ed17 &amp;lt;+155&amp;gt;:   cltq   
&lt;/pre&gt;

&lt;p&gt;What&apos;s this &lt;tt&gt;cltq&lt;/tt&gt; thing? Well, it takes the lower 32 bits of
&lt;tt&gt;%rax&lt;/tt&gt; (the 64-bit register holding the return value from
&lt;tt&gt;rd_new()&lt;/tt&gt;) and sign-extends them to fill the full 64 bits. This
is exactly the corruption I was seeing. Why did the compiler insert this
unwanted instruction? The answer is revealed if we recompile the file
with &lt;tt&gt;-Wall&lt;/tt&gt;.&lt;/p&gt;

&lt;pre&gt;Psymtab.c:645:3: warning: implicit declaration of function `rd_new&apos; [-Wimplicit-function-declaration]&lt;/pre&gt;

&lt;p&gt;The function is not prototyped, so its return value defaults to
&lt;tt&gt;int&lt;/tt&gt;. But because &lt;tt&gt;int&lt;/tt&gt; is now 32 bits wide, and the
register holding the return value is 64 bits wide, the compiler
helpfully obliterates the top 32 bits of the return value for us by
sign-extending the lower 32 bits into them. If the compiler implementors
had stuck with the intention of the &lt;tt&gt;int&lt;/tt&gt; data type, that it be
exactly a word in size, and therefore that &amp;ldquo;defaults to
&lt;tt&gt;int&lt;/tt&gt;&amp;rdquo; is sensible, this would not have arisen.&lt;/p&gt;

&lt;p&gt;Now, this is clearly sloppy code. We should just fix it so that
&lt;tt&gt;rd_new()&lt;/tt&gt; is prototyped. It probably seems a bit of a
nonsequitur that I am blaming this problem on 64-bit architectures. But
on the other hand, how often in your code have you actually wanted
integers that can store values in excess of 2&lt;sup&gt;32&lt;/sup&gt;?  If you are
a systems programmer, you might value the ability to encode large
offsets. But we already had &lt;tt&gt;long long&lt;/tt&gt; for this. In other cases,
the vast bulk of our code deals with small integers, characters and
pointers. Giving us an extra 32 bits of width in our ALU operations is a
waste of transistors.&lt;/p&gt;

&lt;p&gt;Why did we waste them this way? Well, we had to waste them somehow.
In the early 2000s, we didn&apos;t really know what else to do with them,
because (I suspect) there was little perceived demand for multiple cores
in the commodity market (outside of servers). Nowadays, we have even
more transistors, and even hardware guys realise that giving us 128-bit
architectures would be a pointless waste. So, they spent some effort
convincing us that we really did want multiple cores after all. And now
we are busy complicating our software so that we can
&amp;ldquo;exploit&amp;rdquo; these too. I have &lt;a
href=&quot;http://www.inf.usi.ch/postdoc/kells/teaching/papers/kell09dont.pdf&quot;&gt;ranted&lt;/a&gt; before
about how that risks generating a generation&apos;s worth of bad software.
Perhaps I should say &amp;ldquo;another generation&apos;s worth&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;By the way, I&apos;ll concede that 64-bit address spaces can be useful, if
they are used to support persistence or sharing. No need for pointer
swizzling! But AMD&apos;s 64-bit x86 extensions do not provide the separation
of protection from mapping to realise the sharing use-case. In other
words, switching protection domains still means invalidating the TLB
entries of shared mappings. Meanwhile, I haven&apos;t seen anyone using
the extra address space for accessing persistent storage in a radically
new way, although I&apos;d love to see some approaches in this space.&lt;/p&gt;

&lt;p&gt;I don&apos;t completely doubt the value of multiple cores either. The
right way to see parallelism is as an enabler for radically more
computation-intensive applications---likely to be in domains such as
scientific computation, machine learning, and simulation---than what we
can currently support. As I have also &lt;a
href=&quot;http://www.inf.usi.ch/postdoc/kells/blog/research/multicore-madness.html&quot;&gt;ranted
about&lt;/a&gt; before, I am deeply disturbed by the fervour for mass
rewriting of everyday software, and the disruption to the infrastructure
it runs on, that is resulting from mindless multicore mania, in the same
way that the 64-bit shift has disrupted our infrastructure. It&apos;s all in
the name of performance, but it costs us far more of human beings&apos; time
and energy than it saves.&lt;/p&gt;</description>
  </item>
  <item>
    <title>Metacircularity (or: &amp;ldquo;what&apos;s Java got to do with it?&amp;rdquo;)</title>
    <pubDate>Fri, 01 Jun 2012 16:48:00 +0200</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2012/06/01#metacircularity</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/metacircularity</guid>
    <description>
&lt;p&gt;Before I begin, here&apos;s an executive summary. Metacircularity is not about
self-interpretation at all. Rather, it&apos;s an engineering approach to re-using as
much code as possible between different parts of a toolchain (including
compiler, runtime and debugger). This is noble, but limiting ourselves to
working in a single language is needlessly restrictive. If we get over our
presumptions about&amp;ldquo;language barriers&amp;rdquo; (cf. Oracle&apos;s 
&lt;a href=&quot;https://wikis.oracle.com/display/MaxineVM/Glossary#Glossary-Metacircular&quot;&gt;disappointing attempt&lt;/a&gt; at explaining
metacircularity), we can apply the same re-use
philosophy to supporting a diversity of languages, not just one.&lt;/p&gt;

&lt;p&gt;I&apos;ve recently found myself wanting to understand the concept and purpose of
metacircularity in language implementations. This is because I&apos;ve become
interested in understanding the &lt;a
href=&quot;https://wikis.oracle.com/display/MaxineVM/Home&quot;&gt;Maxine&lt;/a&gt; JVM, which is
often described  as having a metacircular design.&lt;/p&gt;

&lt;p&gt;All this meant to me at the time was that it&apos;s written in Java---making it a
self-interpreter, certainly. But is it meta-circular?  What does that mean? Why
might it be a good thing? As I will show, if we&apos;re even just a tiny bit pedantic
(which I hope we are), then metacircularity is not really a special case of
self-interpretation, but a completely separate concept.&lt;/p&gt;

&lt;p&gt;I&apos;ve found two very helpful papers describing metacircularity. The first is
that of Chiba, Kiczales and Lamping talking about the &lt;a
href=&quot;http://dl.acm.org/citation.cfm?id=756984&quot;&gt;&amp;ldquo;meta-helix&amp;rdquo;&lt;/a&gt;.
The other is Ungar, Spitz and Ausch  &lt;a
href=&quot;http://dx.doi.org/10.1145/1094855.1094865&quot;&gt;describing&lt;/a&gt; the Klein VM, a
metacircular implementation of Self. The first paper really emphasises the idea
of &lt;em&gt;implementation by extension&lt;/em&gt; which is at the heart of
metacircularity. They note that use of metacircularity [is]  &amp;ldquo;to allow
extensions to be implemented in terms of the original non-extended
functionality&amp;rdquo;. As the paper goes on to discuss,  there is a tricky
bootstrapping problem inherent in this. If we don&apos;t keep careful track of the
dependencies between all these extensions, subtle and not-so-subtle bugs,
most obviously infinite recursions, can arise. The paper is about avoiding
confusion of metalevels, and as they propose, the shape of a helix, not a
circle, makes much more sense in describing what supposedly meta-circular
systems are actually doing.&lt;/p&gt;&lt;/p&gt;

&lt;p&gt;The second paper, by Ungar et al, is more of a practitioners&apos; view: it shows
what VM builders consider to be a metacircular design, and what they hope to
achieve by it. After reading these two papers, reading some other things, and
scratching my head a lot, it became apparent the primary goal of metacircularity
is to solve two very practical engineering problems concerning re-use: re-use of
code and re-use of debugging tools. They mention the code re-use issue directly,
by saying that in traditional designs &amp;ldquo;an operation such as array access
must be implemented once for the runtime, once for the simple compiler,  and
once for the optimizing compiler&amp;rdquo;. The question of tool support is also an
explicit motivation in the same work: they lament that in the non-metacircular
Self VM, &amp;ldquo;to inspect a Self object... [in]  an application that has
crashed the VM, one must invoke a print routine in the VM being debugged, [an
approach of]  dubious integrity&amp;rdquo;, that the VM &amp;ldquo;must be able to parse
both Self and C++ stack frames&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;So, perhaps prematurely, I&apos;d like to propose a new characterisation of
metacircular VMs that I think captures their true nature. Metacircular VMs are
interpreters (in the general sense)  that are carefully constructed to have a
dense re-use structure. They do this by expressing as much as
possible---front-end, compiler, runtime---as extensions over a small common
core. This core has some interesting properties: it is designed explicitly for
extension,  and includes the necessary foundations of debugger support. It is
the former which allows code re-use, and the latter which enables the same tools
to see all the way up the stack, from various levels of VM code up to
application-level code.&lt;/p&gt;

&lt;p&gt;Note that this is fundamentally different from a self-hosted compiler. Under
self-hosting, the compiling compiler is not re-used at all in the compiled
compiler. It is just used to implement a translation function, from end to end;
how it does it is completely opaque. By contrast, in a metacircular VM, you can
invoke your hosting runtime to perform part of your work---asking it do 
&amp;ldquo;do what you would do in case X&amp;rdquo; by calling the corresponding
function (or sending the corresponding message, for Smalltalkers). The trick is
to ensure that these helper requests are correct and well-defined, meaning they
do not cause infinite regress (the obvious bug) and do not confuse meta-levels
(the more subtle bugs mentioned by Chiba et al).&lt;/p&gt;

&lt;p&gt;As a consequence of this fundamental difference, the key challenge of
metacircularity is not just that of &amp;ldquo;implementing language X in language
X&amp;rdquo; it&apos;s dealing with the bootstrapping problem. What is a suitable common
core? How can we make it small?  What extensions must it permit, or may it
permit?  How can we structure the extensions on top of one another, so that they
can express what we want, re-using what we want to re-use, and efficiently?&lt;/p&gt;

&lt;pIn fact, we can re-state that more strongly. &amp;ldquo;Written in the same
language it implements&amp;rdquo; is not a necessary feature of a metacircular
design at all. If we replace &amp;ldquo;self-interpreter&amp;rdquo; with just
&amp;ldquo;interpreter&amp;rdquo;, it doesn&apos;t seem to break the idea. Another way to
think about this is that the language implemented by the core (&amp;ldquo;bootstrap
image&amp;rdquo;) and the language offered by the front-end high above it need not
resemble each other---so long as the latter is derived from the former by a
continuous chain of extensions.  So,  being a self-interpreter is irrelevant to
metacircularity, even though it is the first thing anyone will tell you about
it.&lt;/p&gt;

&lt;p&gt;So, we&apos;ve established that &amp;ldquo;self-interpretation&amp;rdquo; is irrelevance.
But it seems that most metacircular designs are, in fact, self interpreters,
right?  I actually consider this to be false. Even when staying within
&amp;ldquo;one language&amp;rdquo;, the fundamentals of the bootstrapping process means
that at a given level in the interpreter, certain language features may only be
used in restricted ways.  Sometimes these restricted subsets are given a name,
like  &amp;ldquo;RPython&amp;rdquo; in the &lt;a href=&quot;http://pypy.org/&quot;&gt;PyPy&lt;/a&gt; project.
In other cases, they are not named. But in all cases,   there are restrictions
on what functionality at some level in the system it is is safe and meaningful
to invoke at the metalevel. Indeed, this is exactly the &amp;ldquo;helix&amp;rdquo;
shape that Chiba et al were describing. In other words, different parts of the
interpreter are written in different sub-languages, precisely in order to avoid
infinite regress. Just because there is continuity between the core language and
the eventual top-level language doesn&apos;t make them &amp;ldquo;the same&amp;rdquo;, and
for this reason, metacircular VM designs are &lt;em&gt;not&lt;/em&gt; self-interpreters.&lt;/p&gt;

&lt;p&gt;If I were to write a ranty summary of the above paragraphs, it would be that
the apparently &amp;ldquo;beautiful&amp;rdquo;, head-twisting, recursive,
quasi-mathematical aspects of the metacircular design---the things which
language nerds get excited about---are both irrelevant and illusory.  
Metacircularity is motivated by engineering pragmatics, not 
&amp;ldquo;deep&amp;rdquo; linguistical or mathematical concepts. (Homoiconicity, 
itself a concept of overrated interest, is an orthogonal concept to metacircularity, 
despite what &lt;a href=&quot;http://weblog.raganwald.com/2006/11/significance-of-meta-circular_22.html&quot;&gt;
at least one blogger&lt;/a&gt; has written.) I believe
this fixation with superficial observations about language stems from the
documented inability  of many programmers to divorce concepts from language.
(For &amp;ldquo;documented&amp;rdquo;, I can say at least that Lamport has &lt;a
href=&quot;http://research.microsoft.com/en-us/um/people/lamport/pubs/pubs.html#teaching-concurrency&quot;&gt;commented&lt;/a&gt;
on the problem, and in this case I agree with him. I have big disagreements with
other parts of the same article though. I will post about those in the near
future.)&lt;/p&gt;

&lt;p&gt;So, having stated that re-use is the good thing about metacircularity,
&lt;em&gt;why&lt;/em&gt; is re-use so much easier in a metacircular design? The reason is
that we have a common core providing a coherent and adequate set of
services---the services embodied in the &amp;ldquo;bootstrap image&amp;rdquo;. And I say
&amp;ldquo;services&amp;rdquo; and not &amp;ldquo;language&amp;rdquo; for a reason. The core
really is a set of runtime services. As I have explained, is only a distant
relation of whatever high-level language the author is intending to realise. In
our current technology, re-using code and re-using tools &lt;em&gt;across
languages&lt;/em&gt; is hard, and so &amp;ldquo;build everything in the same
language!&amp;rdquo; seems like a useful answer to a VM author&apos;s problems of
API-level interoperation and of tool support. Metacircular designs are the
result (because it&apos;s the closest you can get to doing everything in one
language). But as I&apos;ve just described, the &amp;ldquo;same language&amp;rdquo; property
is an illusion, and there are inevitably many languages involved. It just
happens that in current projects, those languages are designed to be as similar
as possible to one another---featurewise increments, in effect. But instead of
this unimaginative perspective, anyone building a metacircular VM should ask
themselves: how can I design my core services---the core of the VM---to support
&lt;em&gt;as many different languages as possible&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;This will sound familiar to anyone (so, hmm, maybe ten people on the planet)
who has read my &lt;a
href=&quot;http://www.inf.usi.ch/postdoc/kells/research/papers/kell11virtual-author-preprint.pdf&quot;&gt;&amp;ldquo;Virtual Machines
Should Be Invisible&amp;rdquo;&lt;/a&gt; paper. Although it doesn&apos;t approach the problem
from a metacircularity perspective, this paper is all about building an
infrastructure that can support a diverse variety of languages, sharing code and
tools between all of them.&lt;/p&gt;

&lt;p&gt;Currently, our shared base infrastructure is a POSIX-like operating system. 
Every VM author (even those interested in Windows, which I&apos;m cool with) 
implicitly targets this infrastructure.  Unfortunately,  these systems don&apos;t
provide enough abstractions.   As such, different language implementors build
their own infrastructure which reinvents similar abstractions in incompatible
ways---including functions, objects, garbage collected storage, run-time self
description,  exceptions,  closures,  continuations,  and so on. We can clearly
avoid this pointless diversity without sacrificing innovation. Just as with
operating system interfaces, there is never complete quiescence or consensus,
but we still manage to share a lot more software between OSes than we did in the
pre-Unix or pre-POSIX days.&lt;/p&gt;

&lt;p&gt;One of the mitagating techniques which my VMIL paper describes but which
metacircular designs don&apos;t use  is: &lt;em&gt;describe your implementation
decisions&lt;/em&gt;. Don&apos;t encapsulate them!  If you implement a certain language
feature a certain way, describe it. There is nothing fragile about this, 
because your descriptions will be  written in a standard way and consumed by an
automated interpreter---called a debugger. This is what native debugging
infrastructure does. VM-hosted debuggers, of the Java or Smalltalk flavours,
don&apos;t do this. To make the value of this approach clear, let me finish with
another example from the Ungar paper, where they proudly state that Klein VMs
can be debugged remotely, and in a post-mortem fashion, using another Klein or
Self VM. &amp;ldquo;A separate, possibly remote, Self VM hosts an environment that
manifests the innards of the Klein VM at the source level. Thanks to Klein&apos;s
metacircularity and Self&apos;s mirror-based reflection model, Klein can reuse a vast
amount of already-written Self programming environment code.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;What the authors are forgetting here is that this is not a new facility. 
Native debuggers have long had the capacity to inspect remote processes. 
Smalltalk-, Self-, and Java-like designs took a retrograde step by forcing
debugging to exploit the help of a server within the VM.  Although this has the
benefit of allowing the debugger implementation to share the introspection
services already present inside the VM,  it requires a core of the VM to remain
working correctly,  even after a failure, which  precludes many cases of
post-mortem debugging. By contrast, trusty (or crusty? your choice) old native
debugging is necessarily designed for this as a common use-case.&lt;/p&gt;

&lt;p&gt;The approach I advance instead, as described in the VMIL paper, is to
implement introspection on the same infrastructure that supports remote
inspection---which happens to be the DWARF infrastructure, in the case of
DwarfPython and modern Unix-based compiler toolchains. This is very similar to
the Klein approach, in which mirror objects may reflect both local and remote
state. But it completely avoids the myth that we should implement everything in
a single language. Indeed, debugging information formats like DWARF are actively
concerned with supporting a wide variety of languages. One Klein process can
inspect another because they share a set of implementation decisions. By
contrast, a native debugger need share nothing with its debuggee, because native
debugging infrastructure includes a facility  which is fundamentally omitted
from VM-hosted debuggers: the language implementation explicitly  describes its
own implementation decisions. It does this down to the machine level, and
moreover, up from the machine level.&lt;/p&gt;

&lt;p&gt;The result is that given a memory image of a crashed program, we can recover 
a source-level view of its state at the time of a crash. VM-hosted debuggers are
fine for user code because encapsulation and memory-safety protect enough of the
VM implementation that the debug server can still work. (Notice I don&apos;t say
&amp;ldquo;type-safety&amp;rdquo;! Type-safety is just an enforcement mechanism for
encapsulation, not the key property that ensures encapsulated state is not
corrupted.)  These VM-level guarantees do not have such a nice property  if the
failure was due to a bug in the VM itself. This is because the invariants of the
VM&apos;s own data structures are by definition broken in this case. Some might argue
that this is a minority use case, so VM-hosted debugging is fine for general
use. Personally I don&apos;t mind, as long as I have a debugger that can see all the
way down. Currently this doesn&apos;t include any VM-hosted debugger, but perhaps it
could do. (One of my perhaps-future small projects is to create an
implementation of JDWP that knows how to answer queries about native code.)&lt;/p&gt;

&lt;p&gt;In summary, I think of the solution to re-use proposed by metacircular
designs as a degenerate case of the approach I am pursuing. It sounds strange to
most people, but it is not too much to ask for a language-agnostic runtime
infrastructure that supports a plurality of language implementations (going
right down to native code), direct sharing of code and data, and orthogonality
of tool support from language. As I ranted about in the VMIL paper, this
infrastructure is a modest and  very feasible generalisation of what already
exists, with basically only performance questions outstanding. (I&apos;m working on
it.)  Given this infrastructure, the same careful bootstrapping  approach can be
used to share code and retain tool support throughout higher-level language
implementations. But we can do this without the requirement that everything be
in a single language, which doesn&apos;t make sense anyway.&lt;/p&gt;</description>
  </item>
  <item>
    <title>Link order</title>
    <pubDate>Fri, 01 Jun 2012 16:48:00 +0200</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2012/06/01#link-order</link>
    <category>/devel</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/devel/link-order</guid>
    <description>
&lt;p&gt;Initialization order of static state is a thorny problem. It&apos;s particularly
tricky to get right portably. But until recently I didn&apos;t realise how tricky it
could be even when restricting oneself to GNU tools on Unix platforms. Consider
the following three-part program, consisting of an executable &lt;tt&gt;prog&lt;/tt&gt; and
two shared libraries &lt;tt&gt;lib1&lt;/tt&gt; and &lt;tt&gt;lib2&lt;/tt&gt;. The dependency order is
left-to-right in that list: &lt;tt&gt;prog&lt;/tt&gt; depends on &lt;tt&gt;lib1&lt;/tt&gt; which depends
on &lt;tt&gt;lib2&lt;/tt&gt;.&lt;/p&gt;

&lt;pre&gt;
/* prog.c */
#include &amp;lt;stdio.h&amp;gt;

/* from lib1 */
void greeting(void);

/* constructor */ 
static void init(void) __attribute__((constructor));
static void init(void)
{
	fprintf(stderr, &quot;Initializing prog\n&quot;);
}

int main(void)
{
	greeting();
	return 0;
}

/* end prog.c */

/* lib1.c */
#include &amp;lt;stdio.h&amp;gt;

/* from lib2 */
void hello(void);

/* constructor */ 
static void init(void) __attribute__((constructor));
static void init(void)
{
	fprintf(stderr, &quot;Initializing lib1\n&quot;);
}

void greeting(void)
{
	hello();
}

/* end lib1.c */

/* lib2.c */
#include &amp;lt;stdio.h&amp;gt;

/* constructor */ 
static void init(void) __attribute__((constructor));
static void init(void)
{
	fprintf(stderr, &quot;Initializing lib2\n&quot;);
}

void hello(void)
{
	printf(&quot;Hello, world!\n&quot;);
}

/* end lib2.c */

&lt;/pre&gt;

&lt;p&gt;Here&apos;s a GNU Makefile to tie it all together.&lt;/p&gt;

&lt;pre&gt;
CFLAGS := -g -fPIC
LDFLAGS := -L$$(pwd) -Wl,-R$$(pwd)
LDLIBS := -l1 -l2

default: lib1.so lib2.so prog

%.so: %.c
	$(CC) $(CFLAGS) -shared -o &quot;$@&quot; &quot;$&lt;&quot;

clean:
	rm -f lib1.so lib2.so prog
&lt;/pre&gt;

&lt;p&gt;Now when you do &lt;tt&gt;make&lt;/tt&gt; (or &lt;tt&gt;gmake&lt;/tt&gt;) it will build a program
that initializes its libraries in right-to-left order: from the &amp;ldquo;most
depended on&amp;rdquo; to the &amp;ldquo;least depended on&amp;rdquo;. We can verify this
by running the program.&lt;/p&gt;

&lt;pre&gt;$ ./prog
Initializing lib2
Initializing lib1
Initializing prog
Hello, world!
&lt;/pre&gt;

&lt;p&gt;Moreover, if you try flipping around the link order in the &lt;tt&gt;LDLIBS&lt;/tt&gt;
line, the link will fail with &lt;tt&gt;undefined reference to `hello&apos;&lt;/tt&gt;, because
the reference to &lt;tt&gt;hello&lt;/tt&gt; (in &lt;tt&gt;lib1&lt;/tt&gt;) is introduced &lt;em&gt;after&lt;/em&gt;
the reference to &lt;tt&gt;lib2&lt;/tt&gt;, and the linker&apos;s defined behaviour is to avoid
re-scanning for new undefined references---it&apos;s up to the invoker to order the
libraries so that this works.&lt;/p&gt;

&lt;p&gt;Let&apos;s try this on a BSD system. I have a NetBSD 5.0 VM hanging around, so
I&apos;ll try that. It has recent GNU make, GCC and GNU binutils installed.&lt;/p&gt;

&lt;pre&gt;$ gmake
cc -g -fPIC -shared -o &quot;lib1.so&quot; &quot;lib1.c&quot;
cc -g -fPIC -shared -o &quot;lib2.so&quot; &quot;lib2.c&quot;
cc -g -fPIC  -L$(pwd) -Wl,-R$(pwd)  prog.c  -l1 -l2 -o prog
$ ./prog
Initializing lib1
Initializing lib2
Initializing prog
Hello, world!
&lt;/pre&gt;

&lt;p&gt;Strangely, our initialization order is flipped. This doesn&apos;t matter for our
program, but if &lt;tt&gt;lib1&lt;/tt&gt; consumed some static state in &lt;tt&gt;lib2&lt;/tt&gt;, it
would matter quite a bit. What happens if we flip the link order around to
compensate? We edit the &lt;tt&gt;LDLIBS&lt;/tt&gt; line and re-make.&lt;/p&gt;

&lt;pre&gt;$ nano Makefile
$ gmake clean &amp;&amp; gmake
rm -f lib1.so lib2.so prog
cc -g -fPIC -shared -o &quot;lib1.so&quot; &quot;lib1.c&quot;
cc -g -fPIC -shared -o &quot;lib2.so&quot; &quot;lib2.c&quot;
cc -g -fPIC  -L$(pwd) -Wl,-R$(pwd)  prog.c  -l2 -l1 -o prog
$ ./prog
Initializing lib2
Initializing lib1
Initializing prog
Hello, world!
&lt;/pre&gt;

&lt;p&gt;This has done what we want. But what&apos;s going on? This link order didn&apos;t even
work on GNU/Linux. Not only does it work on BSD, but it&apos;s required if we want a
sensible initialization order. Our initializers run in left-to-right order, so
we need to put the &amp;ldquo;most depended on&amp;rdquo; libraries first, not last.
This isn&apos;t a BSD quirk per se, because we&apos;re using the GNU linker in both cases.
I suspect the linker scripts are nevertheless different in the two cases.
However, I haven&apos;t had time to look into the details of why. I&apos;d be interested
to hear, if anyone knows. I guess this is the sort of pecularity that gives &lt;a
href=&quot;http://www.gnu.org/software/libtool/&quot;&gt;&lt;tt&gt;libtool&lt;/tt&gt;&lt;/a&gt; a reason to
exist.&lt;/p&gt;

</description>
  </item>
  <item>
    <title>Cathedrals, bazaars and research groups</title>
    <pubDate>Tue, 20 Dec 2011 19:49:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/12/20#cathedral-bazaar-research</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/cathedral-bazaar-research</guid>
    <description>
&lt;p&gt;[Post-hoc clarification: at the time I wrote 
this rather grumbly post, I was working in the Department
of Computer Science at the University of Oxford. 
It doesn&apos;t necessarily reflect any on other institution whose domain 
you might currently be seeing in your address bar!]

&lt;p&gt;A fe months ago I finally got around to watching the &lt;a
href=&quot;http://video.google.com/videoplay?docid=-8860158196198824415&quot;&gt;video&lt;/a&gt;
of Guy Steele&apos;s &amp;ldquo;Growing a Language&amp;rdquo; &lt;a
href=&quot;http://www.sigplan.org/oopsla/oopsla98/ap/tech/tpram.htm#is&quot;&gt;talk&lt;/a&gt;
from &lt;a href=&quot;http://www.sigplan.org/oopsla/oopsla98/&quot;&gt;OOPSLA &apos;98&lt;/a&gt;. It&apos;s
a spectacularly entertaining and insightful talk.&lt;/p&gt;

&lt;p&gt;(It&apos;s also a nice demo of how a good keynote doesn&apos;t have to be
Earth-shattering, as long as it&apos;s compelling in concept and delivery.
Really, the meat of the talk is quite specific: it&apos;s about how language
evolution should be managed, with particular reference to the then-ongoing
attempts to add two features to Java: generic data types, which we all know
and love, and operator overloading, which still hasn&apos;t made it.)&lt;/p&gt;

&lt;p&gt;It was a nice reminder of the two &amp;ldquo;organisational modes&amp;rdquo; of
collaborative effort that Eric Raymond called &lt;a href=&quot;http://en.wikipedia.org/wiki/The_Cathedral_and_the_Bazaar&quot;&gt;The Cathedral and the Bazaar&lt;/a&gt;.
Building software is one activity where these metaphors apply. Designing
languages is another. Research groups are a third.&lt;/p&gt;

&lt;p&gt;Like language design and the construction of any &lt;em&gt;large&lt;/em&gt; software
project (think Linux), research groups aren&apos;t a &amp;ldquo;fully
collaborative&amp;rdquo; activity. Rather, they are &amp;ldquo;partially
collaborative&amp;rdquo;---it&apos;s not that everyone is working with everyone else,
but rather, different participants are interested in different pieces of the
overall puzzle. There will
always be multiple frontiers of progress open concurrently---but all
building on a shared central core.&lt;/p&gt;

&lt;p&gt;When I was in Cambridge, the group I was in was very much a bazaar in
style. There was no unique leader (but rather a gaggle of four or five
faculty). Group communications revolve around a mailing list and weekly
meetings where discussion was open, informal talks were  and anyone would
be free to raise questions big and small.&lt;/p&gt;

&lt;p&gt;It wasn&apos;t a problem-free group, either in general or for me personally.
For my first year in the group, the bazaar was dead. That was a tough
time---mainly because communication structures reverted to small
cathedrals (and I wasn&apos;t really a part of any of them). Even later on, I must admit
I didn&apos;t always feel completely at home. I was
a programmer-oriented researcher in a performance-  and
applications-oriented group. But in hindsight I appreciate that the
group&apos;s bazaar-like communication structure and ethos were a very good fit
for me, even if the topic selection wasn&apos;t great. By the end of
my PhD, I found I was getting some reward from my participation in the
group. in two ways. For one, my work had gained some degree of 
recognition in the wider group---I felt I had, in my own small way,
&amp;ldquo;shaped  the agenda&amp;rdquo; at least in a tiny corner. (Sadly this was not enough to
get others on board with similar work, but also not miles away from
that either.)  For another, I had participated  in the more topic-independent
community aspects of a research group---organising the talks for a while,
participating in discussions at talks and on the mailing list, being
around, organising events, and so on.&lt;/p&gt;

&lt;p&gt;I was recently lamenting to myself---a favourite pastime of mine---how right
now, my work isn&apos;t a &amp;ldquo;part of&amp;rdquo; anything. Nobody cares about
what I&apos;m doing, or so it seems, and conversely, I find it hard to get
enthused about what those around me seem to be doing. But then again, I
have very little idea of what their work is, nor they of mine. There is a
lack of transparency and a consequent lack of spontaneity. Without
cross-linking communication structures, there just aren&apos;t the
opportunities to spot synergies and find common interests.  I have found this
a bewilderingly opaque and unsatisfying environment almost since I arrived, 
but I only recently realised the reason: that it is a severely cathedral-organised group. 
There is no institutionalised process for cross-talk
(such as frequent group meetings or mailing list), and while there are multiple frontiers
open, each is coordinated from the top. This clearly works for a lot of people,
but not for me. Does that say anything about the kind of researcher I am,
or others are?&lt;/p&gt;

&lt;p&gt;As an addendum: it&apos;s worth briefly mentioning the &amp;ldquo;agile research
groups&amp;rdquo; idea, one example of which is &lt;a
href=&quot;http://www.cs.umd.edu/~mwh/papers/hicks80scram.html&quot;&gt;Scram&lt;/a&gt; of
Mike Hicks and Jeff Foster. Eric Eide also mentioned to me he uses some of
these ideas, to varying degrees of success, in the &lt;a
href=&quot;http://www.flux.utah.edu/&quot;&gt;Flux group&lt;/a&gt; at Utah. Coincidentally, I
recently dropped in on both these groups! I think these techniques are
mostly orthogonal to the cathedral-versus-bazaar issue: they  concern the
manner (frequency, duration) of communications, not the topology. I expect
Scram works best when participants have a common goal, i.e. there may also
be tighter topic-coherence requirements on its suitability. These may
perhaps even be more likely to hold in a cathedral-style group, although
there is certainly no hard-and-fast causal relationship there.&lt;/p&gt;
</description>
  </item>
  <item>
    <title>Heterogeneity or homogeneity: what&apos;s the problem?</title>
    <pubDate>Wed, 14 Dec 2011 14:01:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/12/14#heterogeneity-or-homogeneity</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/heterogeneity-or-homogeneity</guid>
    <description>
&lt;p&gt;My attention was recently drawn to a problem that some web
developers  call the &amp;ldquo;language heterogeneity problem&amp;rdquo;. I&apos;m not
sure where the term comes from; in fact it is not as widely used as
I was led to believe. But still, most people who have done web
programming know that there are a lot of languages that people use
for the web, not usually out of choice per se, and that this is
somehow a problem.&lt;/p&gt;

&lt;p&gt;The phrase &amp;ldquo;language heterogeneity problem&amp;rdquo;
immediately jarred with me, since some of my work has been looking
at heterogeneity of language as a goal, not a problem. Surely, we
want to choose the best language for each part of our program, and
not pay any unnecessary cost when doing so? Of course, the problem
is about choice versus imposition. It&apos;s not that the
&lt;em&gt;ability&lt;/em&gt; to use multiple languages is bad. It&apos;s that in any
given context, we don&apos;t have that ability! Consequently, you&apos;re
&lt;em&gt;forced&lt;/em&gt; to use &lt;em&gt;particular&lt;/em&gt; languages for a given
piece of code. This is the true &amp;ldquo;heterogeneity
problem&amp;rdquo;. I&apos;d couch the problem as lots of small homogeneity
problems, not one big heterogeneity problem.&lt;/p&gt;

&lt;p&gt;One of my recent student project ideas, sadly not yet attempted
(or indeed advertised), is to develop a compiler back-end and
run-time library that would let us compile vanilla C programs into
web applications. So, for example, if I do &lt;tt&gt;printf()&lt;/tt&gt; it
will write some text to the page, and if I do &lt;tt&gt;fgets(...,
stdin)&lt;/tt&gt;, it will generate a form field whose submission action
is to activate the continuation of the program. There are some
interesting extensions to this project. How do we partition a
program into its client- and server-side halves, or its client-,
server- and database-side thirds? Can we tune the partitioning
given a set of requirements for security, interaction latency,
client code size, and so on?&lt;/p&gt;

&lt;p&gt;(There is also an interesting converse to this problem. Most
programming languages&apos; standard libraries are designed around a
Unix-like model of I/O. And the first programs we teach---like the
Hello World program---use this facility explicitly, by printing to
streams and reading from them. But we now live in a world where
most familiar forms of computing don&apos;t have an obvious terminal- or
stream-style of I/O evident in their interface. So perhaps clinging
to these examples is creating a barrier in front of potential
students---who won&apos;t relate to the idea of a program doing I/O
through a terminal?)&lt;/p&gt;

&lt;p&gt;At SPLASH, I discovered that one chunk of my proposed student
project effort has been scooped by &lt;a
href=&quot;https://github.com/kripken/emscripten&quot;&gt;Emscripten&lt;/a&gt;, an
LLVM-to-Javascript compiler. However, since writing such a compiler
would be too much work for a single project anyway, this might
actually be helpful in enabling a single student project to achieve
more working stuff. In other words, they could focus on matters
other than the compiler, or on doing interesting domain-specific
analyses on user code. Alternatively, perhaps a keen student could
try to make their own compiler that does a better job than
Emscripten, in some way. Hopefully I will managed to advertise the
project in time for the next academic year.&lt;/p&gt;</description>
  </item>
  <item>
    <title>Load addresses</title>
    <pubDate>Tue, 13 Dec 2011 18:16:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/12/13#ldd-and-load-addresses</link>
    <category>/devel</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/devel/ldd-and-load-addresses</guid>
    <description>
&lt;p&gt;For reasons I will only hint at, I want to predict the load address of a
set of shared libraries, given an executable that links against them.
Naturally, I have turned off address space layout randomization.&lt;/p&gt;

&lt;p&gt;At first, I thought I could use &lt;tt&gt;ldd&lt;/tt&gt; for this. It seems to
work.&lt;/p&gt;

&lt;pre&gt;$ ldd /usr/local/src/git-1.7.5.4/git
        linux-vdso.so.1 =&gt;  (0x00007ffff7fdd000)
        libz.so.1 =&gt; /lib/x86_64-linux-gnu/libz.so.1 (0x00007ffff7dc3000)
        libpthread.so.0 =&gt; /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ffff7ba5000)
        libc.so.6 =&gt; /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffff7806000)
        /lib64/ld-linux-x86-64.so.2 (0x00007ffff7fde000)
&lt;/pre&gt;

&lt;p&gt;But also, there is an environment variable called
&lt;tt&gt;LD_TRACE_LOADED_OBJECTS&lt;/tt&gt; that is supposed to have the same
effect. As it happens, &lt;tt&gt;ldd&lt;/tt&gt; is just a small wrapper script which
sets this variable and invokes the dynamic linker, which on my system is
&lt;tt&gt;/lib64/ld-linux-x86-64.so.2&lt;/tt&gt;. Let&apos;s try doing this directly.&lt;/p&gt;

&lt;pre&gt;$ LD_TRACE_LOADED_OBJECTS=1 /usr/local/src/git-1.7.5.4/git
        linux-vdso.so.1 =&gt;  (0x00007ffff7ffb000)
        libz.so.1 =&gt; /lib/x86_64-linux-gnu/libz.so.1 (0x00007ffff7bc4000)
        libpthread.so.0 =&gt; /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ffff79a7000)
        libc.so.6 =&gt; /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffff7608000)
        /lib64/ld-linux-x86-64.so.2 (0x00007ffff7ddc000)
&lt;/pre&gt;

&lt;p&gt;That seems to work too. But wait! It&apos;s given us different load
addresses than &lt;tt&gt;ldd&lt;/tt&gt; did. Have I really turned off randomization?
Well, yes. In fact, repeating either of these commands will reliably
yield the output above, and they are reliably different from one
another. What is going on?&lt;/p&gt;

&lt;p&gt;Let&apos;s hack &lt;tt&gt;ldd&lt;/tt&gt; so that it prints exactly what command it is
going to execute.&lt;/p&gt;

&lt;pre&gt;$ ldd /usr/local/src/git-1.7.5.4/git
About to eval:  LD_TRACE_LOADED_OBJECTS=1 LD_WARN= LD_BIND_NOW= LD_LIBRARY_VERSION= LD_VERBOSE= /lib64/ld-linux-x86-64.so.2 /usr/local/src/git-1.7.5.4/git
verify_out is 
        linux-vdso.so.1 =&gt;  (0x00007ffff7fdd000)
        libz.so.1 =&gt; /lib/x86_64-linux-gnu/libz.so.1 (0x00007ffff7dc3000)
        libpthread.so.0 =&gt; /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ffff7ba5000)
        libc.so.6 =&gt; /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffff7806000)
        /lib64/ld-linux-x86-64.so.2 (0x00007ffff7fde000)
&lt;/pre&gt;

&lt;p&gt;So, it has set a bunch of other environment variables to empty
strings. They look innocuous enough. But also, it is invoking the loader
directly, whereas we were just letting &lt;tt&gt;execve&lt;/tt&gt; call the loader
for us. Can we reproduce the result of &lt;tt&gt;ldd&lt;/tt&gt; by running the same
command it does?&lt;/p&gt;

&lt;pre&gt;$ LD_TRACE_LOADED_OBJECTS=1 LD_WARN= LD_BIND_NOW= LD_LIBRARY_VERSION= LD_VERBOSE= /lib64/ld-linux-x86-64.so.2 /usr/local/src/git-1.7.5.4/git
        linux-vdso.so.1 =&gt;  (0x00007ffff7fdd000)
        libz.so.1 =&gt; /lib/x86_64-linux-gnu/libz.so.1 (0x00007ffff7dc3000)
        libpthread.so.0 =&gt; /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ffff7ba5000)
        libc.so.6 =&gt; /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffff7806000)
        /lib64/ld-linux-x86-64.so.2 (0x00007ffff7fde000)
&lt;/pre&gt;

&lt;p&gt;Yes, we can. Now, the big question: which one is correct? Let&apos;s run our
program under &lt;tt&gt;gdb&lt;/tt&gt; and inspect the memory map.&lt;/p&gt;

&lt;pre&gt;$ gdb --args /usr/local/src/git-1.7.5.4/git
... snipped ...
(gdb) break main
Breakpoint 1 at 0x404bf0: file git.c, line 509.
(gdb) run
Starting program: /usr/local/src/git-1.7.5.4/git 
[Thread debugging using libthread_db enabled]

Breakpoint 1, main (argc=1, argv=0x7fffffffddd8) at git.c:509
509     {
(gdb) print getpid()
$1 = 27023
(gdb) shell cat /proc/27023/maps | grep &apos;lib.*\.so.*&apos;
7ffff7608000-7ffff779d000 r-xp 00000000 08:07 356590                     /lib/x86_64-linux-gnu/libc-2.13.so
... snipped ...
&lt;/pre&gt;

&lt;p&gt;So, &lt;tt&gt;libc-2.13.so&lt;/tt&gt; has been loaded at address
&lt;tt&gt;0x7ffff7608000&lt;/tt&gt;, which is what we got from running with just the
&lt;tt&gt;LD_TRACE_LOADED_OBJECTS&lt;/tt&gt; flag set, and &lt;em&gt;not&lt;/em&gt; what we got
with &lt;tt&gt;ldd&lt;/tt&gt; or with invoking &lt;tt&gt;ld-linux.so.2&lt;/tt&gt; specially.&lt;/p&gt;

&lt;p&gt;Why the difference? Clearly, first &lt;tt&gt;execve&lt;/tt&gt;ing the loader
perturbs the address assignment. It&apos;s not clear why this should
be---isn&apos;t the loader itself the first thing to be loaded anyway? I&apos;m
not yet sure what is going on.&lt;/p&gt;

&lt;p&gt;Another question: is predicting the load address even a sound thing
to do? Given that we had to disable randomization in the first place, it
seems like a bad idea. In my case, this approach will do for now, but
ultimately I should defer my work until application start-up time. Then
we can discover the actual loaded addresses of the various libraries,
which is much more robust.&lt;/p&gt;</description>
  </item>
  <item>
    <title>Refactoring refactoring</title>
    <pubDate>Mon, 05 Dec 2011 12:23:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/12/05#refactoring-refactoring</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/refactoring-refactoring</guid>
    <description>
&lt;p&gt;A little while ago I embarrassed myself in conversation by blurting out a
sceptical opinion of refactoring. In this post I&apos;ll explain some opinions on
refactoring and related research, hopefully in a more considered and coherent
manner that I managed on that occasion.&lt;/p&gt;

&lt;p&gt;I admit that my inclination to be a bit negative comes from prejudice, with a couple of origins. 
One is that a while
ago, I had to fend off (rhetorical) claims that refactoring solved what my PhD was
doing. It clearly didn&apos;t, but then again, it was well worth writing an explanation of
why not. (These claims were from my supervisor, not my examiners, thankfully,
and I think were being advanced rhetorically.)  In that
context, interface evolution scenarios were the issue. I still contend that refactoring
is not the solution to interface evolution. (Endlessly editing code to stay in sync with
&amp;ldquo;one true&amp;rdquo; &amp;ldquo;current&amp;rdquo; version of an interface, whether with or
without the help of refactoring tools, is an unnecessarily burdensome approach;
an automated assist for editing code doesn&apos;t make that editing work- or risk-free.)&lt;/p&gt;

&lt;h4&gt;More refactoring&lt;/h4&gt;

&lt;p&gt;Happily, most uses of refactoring are quite different from interface evolution:
they&apos;re about the internal structure of code, not &amp;ldquo;edge&amp;rdquo; interface details.
I&apos;m a big fan of refactoring in these cases. As a practitioner I&apos;d love to have more and
better refactoring. In that space, one clear improvement would be refactoring tools for
more languages. This doesn&apos;t mean starting again; most languages are more alike than
they are different. At the moment, the popularity of refactoring serves to cement the
Java hegemony. This is my other unreasonable prejudice: 
I dislike this hegemony, and so refactoring culture is tained by
association (unfairly) in my mind. It&apos;d be really nice to have some decent refactorings
available for C++, but I&apos;m not holding my breath. That said, I might not know about them
if they do exist.&lt;/p&gt;

&lt;p&gt;(Aside: the real problem with C++ is not pointer arithmetic or lack of garbage
collection or lack of type safety or anything else that people usually trot out; it&apos;s
&lt;em&gt;complexity&lt;/em&gt;. I&apos;ll rant about that in a future post. By contrast, Java does well
because it&apos;s a simple language. Actually it does unfairly well because researchers abuse
its syntax tree as an intermediate representation for program analyses. I might rant
about &lt;em&gt;that&lt;/em&gt; in yet another post.)&lt;/p&gt;

&lt;p&gt;That&apos;s my practitioner&apos;s view over with. As a researcher, I have one qualm remaining
about refactoring. Rather than doing research on making refactoring work in more and
more scenarios, I want to see some exploration of a few bigger ideas in the same general
space. There are ideas that are more powerful, more &amp;ldquo;revolutionary&amp;rdquo; than
refactoring but have (so far) less currency.&lt;/p&gt;

&lt;h4&gt;Language-independent refactoring&lt;/h4&gt;

&lt;p&gt;Language-independent refactoring is an obvious goal. The means by which to achieve it
is less obvious. A shared metamodel seems sensible. The need for a shared metamodel is
arguably a limitation. But I don&apos;t buy that argument! My reasoning is based on the
observation that most languages have large sets of features that are &lt;em&gt;cognate&lt;/em&gt;.
By this I mean they are not just theoretically equivalent in what they can express (or
perhaps not at all equivalent in that way), but rather, a human user understands them in
the same way. (I wish we had the empirical foundations to substantiate that, but that&apos;s
another matter.) So if we can capture these, we can probably come up with a metamodel
that works well in practice, even if it fails for adversarially-constructed cases.&lt;/p&gt;

&lt;p&gt;Conversely, just to throw another controversial claim into the mix:
languages that have such a pared-down set of primitives that they &lt;em&gt;don&apos;t&lt;/em&gt; offer a
cognate of some recurring feature---like purely functional languages without mutable
objects, or C without virtual calls---in practice &lt;em&gt;do&lt;/em&gt; have cognates, but
appearing as  &lt;em&gt;patterns&lt;/em&gt; of use rather than delineated language features. So I
seem positing some sort of Chomskyan &amp;ldquo;universal language feature set&amp;rdquo; that
is in programmers&apos; minds if not explicitly in all languages. That feels a bit strong;
I&apos;ll have to take some time to see whether I agree with myself there.&lt;/p&gt;

&lt;p&gt;(As an aside: of course, many languages have &lt;em&gt;too many&lt;/em&gt; features, in that they
are mutually cognate:  do I use static variables, or a singleton object, e.g. in Java? 
Do I use typeclasses or traits, e.g. in Scala? Do I specialise using template
specialisation, overloading or overriding in C++? These self-cognate features usually
have arbitrary limitations, and their diversity exists for implementation reasons. 
Exposing a choice among them leaks implementation details to the programmer,
along with consequent performance characteristics. So, forcing the programmer to select among
these early on, as these languages all do, 
is an evil akin to the evil of premature optimisation.
Fortunately, it&apos;s an evil that refactoring exists to fight!&lt;/p&gt;

&lt;p&gt;(Continuing the aside: we perceive &amp;ldquo;clean&amp;rdquo; languages to have few mutually cognate
features. Conversely, most mutually-cognate features differ along some potentially-separable
dimensions: each feature mixes a particular setting on each dimension. For the &amp;ldquo;static versus
singleton&amp;rdquo;, having a chunk of data that is &amp;ldquo;one per program instance&amp;rdquo; is the main
concern, and dynamic-versus-static allocation is the orthogonal issue that is unhelpfully mixed with
it. In a Java-like implementation, object identity is another mixed concern: it&apos;s something you get in
the singleton case, not the static field case, and effectively for reasons of implementation leakage.
Conversely, in C and C++, statically-allocated stuff can still have its address taken, so there is
better separation of concerns in that case.)&lt;/p&gt;

&lt;h4&gt;Non-behaviour-preserving transformations&lt;/h4&gt;

&lt;p&gt;Digging deeper than language-independent refactoring, it seems that refactoring&apos;s
main value is in its ability to improve code by reversing bad decisions that were
somehow expedient earlier. But underneath that, there are two cases. Firstly there are
cases where you refactor because you got the abstract design wrong earlier (e.g. you
assumed there was only one Frob per Widget, and in fact there might be many). Secondly
are the cases where you got the abstract design right, but the code-level design wrong,
i.e. you didn&apos;t map the abstract design optimally onto language features (with respect
to maintainability, efficiency, ...). To me, it feels like there is too much emphasis on
the second case, while the first one is harder and more interesting.&lt;/p&gt;

&lt;p&gt;I think this is because automated refactorings aim to be behaviour-preserving.  But
since the two problems are very close---they both arise from forced premature commitment
and the programmer&apos;s failure to anticipate the future---we should perhaps use the same
tools to combat both of them. In other words, the requirement that refactorings should
be behaviour-preserving actively limits what we can do. So how about some bolder
approaches that might sidestep the problem?  While these approaches might violate the
letter of the definition of refactoring, for me, they retain the most useful charateristic of
refactoring: by a single localised change, we can effect global changes on
our codebase.&lt;/p&gt;

&lt;p&gt;The only work I know that does automated non-local code edits that can change program behaviour is
&lt;a href=&quot;http://coccinelle.lip6.fr/&quot;&gt;Coccinelle&lt;/a&gt;, based on the &amp;ldquo;semantic patch&amp;rdquo; idea. 
Aspect-oriented programming is a similar technique, but works by  effectively (and controversially)
delocalising run-time semantics rather than performing  non-local code edits. I&apos;d like to know if
there are others more like Coccinelle already in existence.&lt;/p&gt;

&lt;p&gt;So, suppose we discard the restriction of limiting ourselves to behaviour-preserving edits.
One direction under this auspice is to creep closer towards model-driven development. I want the
ability to change my &amp;ldquo;model&amp;rdquo; (either in my head, or in some modelling notation) and
see changes reflected in source code. And also, vice-versa: if we do have a modelling notation,
code changes should update the model. This is a hard but interesting problem in bidirectional
transformation, which has something of a currency at the moment (witness the &lt;a
href=&quot;http://www.program-transformation.org/BX12&quot;&gt;BX workshop&lt;/a&gt;).&lt;/p&gt;

&lt;h4&gt;Logic metaprogramming&lt;/h4&gt;

&lt;p&gt;A final thought is about logic metaprogramming. This is a very cool idea that I have not yet
got up to speed on. In fact, almost all I know about it is from the abstract of a &lt;a
href=&quot;http://portal.acm.org/citation.cfm?id=1869499&quot;&gt;paper&lt;/a&gt; I saw at SPLASH last year, which
said: &amp;ldquo;In logic metaprogramming, programs are... derived from a deductive database.&amp;rdquo;
But this one sentence is so intriguing that I want to run for a while with what I think it might
entail, before I find out what is actually done in existing systems (of which there are
few!).&lt;/p&gt;

&lt;p&gt;I&apos;ve often wanted to program not by writing code directly---since I&apos;m often aware that the
code I&apos;m writing will probably turn out &amp;ldquo;wrong&amp;rdquo; or &amp;ldquo;bad&amp;rdquo; once I&apos;ve done
a bunch more coding---but by making a sequence of simpler statements that I have more confidence
in. Each statement should be small, freestanding and less of a commitment than writing a line of
code would be. These statements might be such that none of them, by itself confers enough
information to write a &quot;known good&quot; piece of source code. E.g. I might write that each instance
of class A &amp;ldquo;has a[n]&amp;rdquo; associated instance of class B, but I don&apos;t yet know whether
this association should be expressed as pointers, or by some associative data structure, say.
This decision could be determined later, by solving constraits originated by other small
statements. Ties could be broken (i.e. multiple candidate solutions selected among) by
extrafunctional requirements such as performance (which might favour pointers over associative
structures).&lt;/p&gt;

&lt;p&gt;This is related to program synthesis and refinement methodologies, I guess. But I am
particularly interested in making it exploratory. By having a tool explore the implications of
the programmer&apos;s statements, we can potentially refine our understanding of the problem (a.k.a.
&amp;ldquo;debug the design&amp;rdquo;) without going through the circuitous path of  first writing some
&amp;ldquo;bad&amp;rdquo; code and then either finding it&apos;s not the right design (and cleaning it up by
heavyweight code changes) or finding it&apos;s incidentally messy (and cleaning it up, just by
automatic refactoring if we&apos;re lucky). We can also have a tool tell us what the &amp;ldquo;right
way&amp;rdquo; to code something is, but &lt;em&gt;early&lt;/em&gt;. If the only solution to a particular set of
requirements is to use a particular language feature, then the tool can tell us this, rather
than letting us find it out by making the wrong choice and then backtracking. Of course, we need
to get the requirements right up front, so this technique will only ever be a complement to more
backtracking-oriented techniques.&lt;/p&gt;

&lt;h4&gt;Multi-dimensional representations of software&lt;/h4&gt; 

&lt;p&gt;It is a very classical notion that programs have one true form, being their source code in the
form of a string of symbols. Refactoring sticks with this idea but tries to make it easier to
alter that form, by abstracting and automating certain common complex non-local edit patterns.
But we can go further by rejecting the notion of &amp;ldquo;one true form&amp;rdquo; altogether, at
least in the sense that that form is manipulated by programmers.&lt;/p&gt; 

&lt;p&gt;Of course, this is the &lt;a href=&quot;http://www.research.ibm.com/hyperspace/MDSOC.htm&quot;&gt;MDSoC&lt;/a&gt; holy
grail. I think the idea is just slightly too big for its own good, at present. Ironically, or
fittingly, it has not been decomposed properly: aspects,  refactoring and typeclasses are the main
programming weapons that share its spirit, but none has its power or elegance. It&apos;s a shame that work
on the idea seems to have fizzled out. (It&apos;s also a shame that the &lt;a
href=&quot;http://dl.acm.org/citation.cfm?id=302457&quot;&gt;paper&lt;/a&gt; isn&apos;t on more reading lists!)&lt;/p&gt;

&lt;p&gt;Somewhat relatedly, there&apos;s been some interesting work on subjective/transient/dual encodings
of language features, as with the &lt;a
href=&quot;http://portal.acm.org/citation.cfm?id=1869521&quot;&gt;registration-based&lt;/a&gt; stuff at last year&apos;s
Onward!, or Rob Ennals&apos; &lt;a href=&quot;http://jekyllc.sourceforge.net/&quot;&gt;Jekyll&lt;/a&gt;. But I&apos;m still not aware of
any mature tools that can really rip apart the modular structure of code and transform it on demand.
Perhaps one problem is that we need to be able to define what primitive entities these queries
&amp;ldquo;select&amp;rdquo;, and how they reformulate them into the appropriate bigger chunks---ideally
in a language-agnostic way. So it&apos;s back to the shared metamodel. Again, better understanding of
&amp;ldquo;cognate&amp;rdquo; language features, and indeed of less intuitive correspondences between
language features (like the nontrivial correspondences between algebraic data types and class
hierarchies), will help here.&lt;/p&gt;</description>
  </item>
  <item>
    <title>Guided by folklore</title>
    <pubDate>Mon, 05 Dec 2011 11:31:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/12/05#guided-by-folklore</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/guided-by-folklore</guid>
    <description>
&lt;p&gt;In a recent chat with my internal examiner, Andy Rice, I had a few
thoughts which I decided to write down. It turns out he reads my
blog---along with (his words) &amp;ldquo;everyone in the department&amp;rdquo;
---so, hi Andy and everyone. One day I might stop writing as if my
audience consists only of myself, but not right now.&lt;/p&gt;

&lt;p&gt;In summary, I want to rant about two weird things that go on in the
research world. One is that there are some memes that seem to have a
real influence on how PhDs are examined, but seem to have no origin
other than folklore, and  are different from the standards used to judge
other research. The second rant, and perhaps the more oft-repeated, is
that we actively encourage boring research.&lt;/p&gt;

&lt;p&gt;(I should add that although this post is rather ranty, the chat was
not an argumentative one. So, this is mostly post-hoc ranting about
related topics, and not a direct reflection of our conversation.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A thesis is judged on criteria from folklore&lt;/strong&gt;, beyond
what applies to &amp;ldquo;normal&amp;rdquo; research. At various points in my
PhD, I heard it said that &amp;ldquo;a thesis should... [do
&lt;em&gt;X&lt;/em&gt;]&amp;rdquo;. Usually, &lt;em&gt;X&lt;/em&gt; was something to do with telling
a complete story, strongly substantiating a succinct hypothesis, and so
on. And now I have heard the same from my examiners.  Unfortunately,
these statements continue to be just that---hearsay. They&apos;re different
from the ways in which other research is judged. There are no
regulations or official guidance to support them. There are no clear
scientific or moral justifications for them either. The research
community happily publishes many papers that do not tick these boxes,
and at good venues. My own OOPSLA &apos;10 paper is one example, but there
are lots of others. But despite this, PhD examination seems to give a
lot of currency to these criteria, for apparently no reason other than
their having been handed down through the generations.&lt;/p&gt;

&lt;p&gt;During my PhD I didn&apos;t worry myself much about this,  since, like
most researchers, I don&apos;t put much weight on unsourced claims. Besides,
there seemed to be enough data downplaying their significance
anyhow---several other theses seemed to break the rules, and plenty of
published, respected research papers did too. Surely if a PhD is
training for research, the qualifying criterion should be focused on
doing good research? From my very limited experience, and from what I
gather from listening to others, this is not how things currently are.
Fortunately, I am of the bloody-minded type. I was aware that I might be
&amp;ldquo;creating trouble&amp;rdquo; for myself, but I personally preferred to
risk creating that trouble, thereby at least gathering some evidence
about it, rather than swerving to avoid an obstacle that was at best
nonexistent (I didn&apos;t &lt;em&gt;know&lt;/em&gt; it would cause trouble) and at
worst, worth challenging. So, consider it challenged! If you think a
thesis needs to be anything more or different than good research, I
challenge you to justify that position.&lt;/p&gt;

&lt;p&gt;Now, on to my second rant. &lt;strong&gt;The evaluability problem&lt;/strong&gt;
has an irrational hold on many practical computer scientists, to the
extent that research into many important problems is deliberately
avoided. I spoke to many experienced researchers about my PhD work as it
went along. Several of them suggested that I might have some trouble at
examination. This seemed odd to me, for the reasons I just ranted about.
Nevertheless, I didn&apos;t disbelieve them. But I had no intention of
applying the fix they suggested.  Rather than developing an alternative
evaluation strategy or (the best advice in hindsight) to maximise the
persuasiveness of the presentation of whatever evaluation data I did
have, the only &amp;ldquo;advice&amp;rdquo; I ever received on this point was a
not-so-veiled  encouragement to abandon my current problem and work on
something else. &amp;ldquo;Up and to the right&amp;rdquo; was what one
researcher told me---about the kind of graph that should be in my
evaluation chapter. (My evaluation chapter has no graphs, and is staying
that way.)&lt;/p&gt;

&lt;p&gt;This attitude is the tail wagging the dog. If a problem is important,
and we do some research that is not conclusive, we should damn well work
harder at it, not give up. The problems and curiosities of humankind are
not regulated by how easy it is to collect data and draw graphs about
them. If we avoid working on important but difficult-to-evaluate
problems, or discourage such work, it shows the worst kind of ivory
tower mentality. It is far from a pragmatic position, despite how (I&apos;m
sure) many of its adopters would try to spin it. What is pragmatic about
ignoring the real problems?&lt;/p&gt;

&lt;p&gt;I&apos;m not downplaying the importance of evaluation. It goes without
saying that measuring the value of innovations is important. Moreover,
our ability to measure is something we need to work on actively. After
all, many of those physicists and other &amp;ldquo;hard&amp;rdquo; scientists
seem to spend nearly &lt;em&gt;all&lt;/em&gt; their time working out ways of
measuring stuff. So I&apos;m completely in favour of rigorous evaluation. On
the other hand, I&apos;m not sure that a lot of evaluation that currently
passes muster is really rigorous anyway. We need to recognise evaluation
as a problem in its own right, whose hardness varies with the
problem---and make allowances for that. For many hard problems,
evaluation of a solution is comparably hard. That shouldn&apos;t mean that we
give up any attempt to tackle those problems. The preference for
conclusive results in published research has a deceptive influence,
being essentially the same phenomenon as the &amp;ldquo;decline
effect&amp;rdquo;, described in &lt;a
href=&quot;http://www.newyorker.com/reporting/2010/12/13/101213fa_fact_lehrer&quot;&gt;this&lt;/a&gt;
very interesting article from the New Yorker.&lt;/p&gt;

&lt;p&gt;There are some other problems with evaluation in particular kinds of
CS research. One is what I call &amp;ldquo;evaluation by irrelevant
measurement&amp;rdquo;: if you develop something that is supposed to help
programmers, but you can&apos;t measure that, how about measuring its
performance or proving its type-soundness? It says nothing about whether
you&apos;ve achieved your goals, but it still ticks those evaluation boxes.
And of course we have a big problem with reproducibility of experimental
results---at the VMIL workshop at SPLASH, &lt;a
href=&quot;http://www.cs.technion.ac.il/~yogi/&quot;&gt;Yossi Gil&lt;/a&gt; gave a great
talk about the non-reproducibility of VM-based microbenchmarks, and
Jeremy Singer&apos;s &lt;a
href=&quot;http://dl.acm.org/citation.cfm?id=2048249&quot;&gt;Literate
experimentation manifesto&lt;/a&gt; was a nice counterblast to the wider
problem.&lt;/p&gt; 

&lt;p&gt;I have found programming language researchers to be more sympathetic
than &amp;ldquo;systems&amp;rdquo; researchers to work &amp;ldquo;towards&amp;rdquo; a
goal, as distinct from work telling a complete story about some problem.
This is partly because the nature of programming language research makes
&lt;em&gt;reliable&lt;/em&gt; evaluation a very high-latency endeavour. In other
words, until real programmers have used your idea in a large number of
projects, there will be no clear experience about how well it works. So,
being computer scientists, we mitigate that latency, using pipelining.
Rather than a slow stop-and-forward algorithm which waits 20 years
between research projects, we have to be more amenable to two
approaches: argument, in the sense of paying attention to the reasoning 
that justifies the approach of a particular piece of work, and
speculation, meaning  allowing the research discourse to explore many
alternative approaches concurrently, and letting time tell which ones
will &amp;ldquo;stick&amp;rdquo; out of the many that have been given a chance.
The job of the researcher is less to conclusively show a problem as
solved, but to show that a technique is feasible and has some potential
for wide and successful application.&lt;/p&gt;

&lt;p&gt;Going back to the first point, perhaps I should add that I&apos;m not
saying that my thesis would have stood up any more strongly by
&amp;ldquo;good research&amp;rdquo; criteria. But having said that, a very large
chunk of it appeared at a top-tier venue, so it can&apos;t be all that bad.
Both of my examiners seemed to miss this fact, so the lesson is: always
put a prominent summary of your publications in your thesis! Personally
I can be very critical of my thesis work. But it seems bizarre to me
that folklore should have so much sway in the way that theses are
examined.&lt;/p&gt;
</description>
  </item>
  <item>
    <title>Weak dynamic symbols</title>
    <pubDate>Thu, 01 Dec 2011 16:59:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/12/01#weak-symbols</link>
    <category>/devel</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/devel/weak-symbols</guid>
    <description>
&lt;p&gt;Although I know more than the average bear about linkers, there&apos;s always
things I don&apos;t know. Until now I never had cause to understand the
following: how does the linker know which symbols to link dynamically,
and which to link statically?&lt;/p&gt;

&lt;p&gt;A bit of head-scratching reveals the only possible answer. Given a
command-line, it does the usual thing: look at the command-line options,
perform the standard library look-up procedure, gathering a list of
object files---some static, some dynamic. If a symbol is defined by a
dynamic library, make it dynamic. Otherwise, it stays static.&lt;/p&gt;

That sounds fairly sensible. But it can mean surprises. Suppose you have
a C program that wants to support an optional feature to be linked in at
load time. You might write something like the following.

&lt;pre&gt;int optional_function(int arg1, void *arg2) __attribute__((weak));

/* ... */

void do_something(void)
{
    if (optional_function) optional_function(42, &amp;amp;some_obj);
    /* else skip the optional part... */
}
&lt;/pre&gt;

&lt;p&gt;If you pull this sort of trick within a shared library, it works
fine. But inside an executable: no dice! If you compile this into an
executable and look for &lt;tt&gt;optional_function&lt;/tt&gt; in your dynamic
symbol table, you&apos;ll be disappointed.&lt;/p&gt;

&lt;pre&gt;$ objdump -T my-program | grep optional_function
$&lt;/pre&gt;

&lt;p&gt;What is going on? Well, it&apos;s in the static symbol table, silly.&lt;/p&gt;

&lt;pre&gt;$ objdump -t my-program | grep optional_function
0000000000000000  w      *UND*  0000000000000000          optional_function
$&lt;/pre&gt;

&lt;p&gt; What does it mean to have an undefined symbol in your executable&apos;s
static symbol table? It means it will silently take the value zero! In
fact, the relocation records referencing your symbol have already been
discarded.&lt;/p&gt;

&lt;pre&gt;$ objdump -rRd my-program | grep -A1 -B1 callq
(snip)
--
  400549:      bf 2a 00 00 00        mov    &amp;#36;0x2a,%edi
  40054e:      e8 ad fa bf ff        callq  0 &amp;lt;__init_array_end&amp;gt;
  400553:      b8 00 00 00 00        mov    &amp;#36;0x0,%eax
--
(snip)
&lt;/pre&gt;

&lt;p&gt;Cheerily, the linker has inserted a direct-bound call to address zero
in your code. That&apos;s not what we want! So, how can we fix it?&lt;/p&gt;

&lt;p&gt;The trick is in the linker&apos;s (or at least the GNU linker&apos;s)
&lt;tt&gt;--dynamic-list&lt;/tt&gt; option. First, create a file called whatever you
like (mine&apos;s called &lt;tt&gt;dynamic-list&lt;/tt&gt;), containing the following.&lt;/p&gt;

&lt;pre&gt;{ optional_function; };
&lt;/pre&gt;

&lt;p&gt;Now link your program passing &lt;tt&gt;--dynamic-list
&amp;lt;your-dynamic-list&amp;gt;&lt;/tt&gt; to the linker.&lt;/p&gt;

&lt;pre&gt;gcc -Wl,--dynamic-list -Wl,&amp;lt;your-dynamic-list&amp;gt; -o my-program my-program.c
&lt;/pre&gt;

&lt;p&gt;Hey presto! You should now have your weak symbol in the dynamic
symbol table.&lt;/p&gt;

&lt;pre&gt;$ objdump -t my-program | grep optional_function
0000000000000000  w   D  *UND*  0000000000000000          optional_function
$&lt;/pre&gt;

&lt;p&gt;That&apos;s a bit ugly. Recalling the linker behaviour I described at the
beginning, the simpler way to do it is just to link your executable
against a shared library defining &lt;tt&gt;optional_function&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;You might wonder (as I do): what is the point of putting undefined symbols in
an executable&apos;s static symbol table? Once the executable is output, it&apos;s too
late to link anything with them. Surely they should all be
&amp;ldquo;promoted&amp;rdquo; to dynamic symbols?  [Update, 2012-5-19: there is
of course a linker option for doing this, which in the GNU case is
&lt;tt&gt;--export-dynamic&lt;/tt&gt;. Still, I&apos;m not sure why it isn&apos;t the default.]&lt;/p&gt;

&lt;p&gt;It would also be nice to have an &lt;tt&gt;objcopy&lt;/tt&gt; option for adding
dynamic symbols in this way, so we can do it after the fact, rather than
changing the linker command like we did above. However, this is
nontrivial for the reason I mentioned---the relocation records that you
would want have already been eliminated. So, we would need to re-create
them. This is similar to &lt;a
href=&quot;http://www.inf.usi.ch/postdoc/kells/blog/research/unbinding-shared-objects.html&quot;&gt;something
I began work on before&lt;/a&gt;. At some point I might resurrect my
&lt;tt&gt;objcopy&lt;/tt&gt; patches and try to repurpose them to this problem. For
now, I will just hack in the extra linker options.&lt;/p&gt;</description>
  </item>
  <item>
    <title>Static versus dynamic analysis---an illusory distinction?</title>
    <pubDate>Sat, 12 Nov 2011 18:49:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/11/12#static-and-dynamic-analyses</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/static-and-dynamic-analyses</guid>
    <description>
&lt;p&gt;When writing a recent talk, I found myself arguing that static and dynamic 
analysis are not really that different. At least, people don&apos;t really agree on the 
distinction. Model checking people frequently argue that what they&apos;re doing is 
dynamic analysis, because it directly explores paths through a system&apos;s state space. 
Meanwhile, abstract interpretation people would argue the opposite, since clearly 
model checking is an instance of abstract interpretation, and so is all other static 
analysis.&lt;/p&gt;

&lt;p&gt;I&apos;d much rather avoid the debate entirely. Since model checking is a far cry from 
run-time checking or testing, my sympathies initially lay with the abstract 
interpretation camp on this particular issue. But the distinction becomes even more 
ill-defined in other cases. In particular, I&apos;ve been thinking a lot about symbolic 
execution, of the kind done by &lt;a href=&quot;http://klee.llvm.org/&quot;&gt;KLEE&lt;/a&gt; and other 
tools. Is it doing a static or a dynamic analysis? I&apos;d challenge you to defend 
either position.&lt;/p&gt;

&lt;p&gt;(Meanwhile, execution environments which are somewhat speculative, like 
transactional memories, lazy evaluators, or even plain old branch prediction, can be 
considered as partial runs of a static analysis. But I should save that line of 
thinking for another post.)&lt;/p&gt;

&lt;p&gt;So rather than talking about static or dynamic analyses, here are
some dimensions of analyses that I think are more interesting.&lt;/p&gt;

&lt;ul&gt; &lt;li&gt;&lt;strong&gt;Effecting versus effect-free&lt;/strong&gt;&amp;mdash;this is one killer 
distinction between traditional &amp;ldquo;static&amp;rdquo; and traditional 
&amp;ldquo;dynamic&amp;rdquo; analyses. If I run it, will it do the stuff that my program 
does (or might do)? Sandboxing, such as the environment modelling scaffolding in 
KLEE, can turn an effecting analysis into a non-effecting one without (necessarily) 
perturbing it along other dimensions (although KLEE also uses the same layer to 
enable symbolic I/O). &lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Exploratory versus single-path&lt;/strong&gt;&amp;mdash;this is what those 
model-checking people were talking about, and is the most essential distinction 
between testing and other analyses. &lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Terminating versus nonterminating&lt;/strong&gt;&amp;mdash;termination is a 
property that most static analyses, including abstract interpreters, like to have. 
By contrast, it&apos;s interesting that model checkers are happy with the approach of 
CEGAR, which is a (potentially) nonterminating loop. Also, type theorists have 
become increasingly comfortable with undecidable type systems in recent years, 
meaning that type checking need not terminate. For real programs, these methods 
still tend to terminate, of course. &lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Overapproximate, underapproximate, both, neither&lt;/strong&gt;&amp;mdash;more 
formal mindsets care to distinguish between overapproximating analyses from 
underapproximating analyses. The former which offer false positive error reports but 
no false negatives, so include &amp;ldquo;sound&amp;rdquo;type systems. The latter might 
miss real errors, so include most symbolic executors (which, aside from 
nontermination, fall back on underapproximation once the solver fails) and other 
bug-finding tools. Interestingly, people with a bug-finding mentality, including 
model checkers, call type checkers &amp;ldquo;unsound&amp;rdquo; because they report 
spurious errors---completely the opposite sense from abstract interpretation&apos;s 
&amp;ldquo;sound overapproximatino&amp;rdquo;. I think both parties are a little distracted 
here. Many practical analyses are both underapproximating and overapproximating, or, 
put differently, are neither sound nor complete (whichever way round you put the 
terminology). They can still be useful; indeed, they are often the most useful 
analyses from a practical perspective. Here&apos;s a &lt;a 
href=&quot;http://dl.acm.org/citation.cfm?id=1555052&quot;&gt;static deadlock detector&lt;/a&gt; that 
stuck in my mind as an unsound, incomplete yet effective analysis, from ICSE &apos;09. 
&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Augmenting versus abstracting&lt;/strong&gt;&amp;mdash;sometimes an analysis will 
focus on a particular subset of a program&apos;s observable behaviours---type errors are 
one example, being the focus of type checkers&apos; analyses. All the abstractions I know 
from the verification community---predicate abstraction, types, other abstract 
domains, and also slices---have this property. But conversely, some analyses are 
designed to tell you &lt;em&gt;more&lt;/em&gt; than you could discern from any program trace! 
They do this by actively computing additional information that the underlying 
program did not. I call these &amp;ldquo;augmenting&amp;rdquo; analyses. Most of the 
examples I know are instrumentation-based systems. &lt;a 
href=&quot;http://www.valgrind.org/&quot;&gt;Valgrind&lt;/a&gt;&apos;s Memcheck tool is arguably one such, 
since it computes the &amp;ldquo;definedness&amp;rdquo; of each memory location. You might 
quibble that this is not truly augmented, in that definedness can be retroactively 
derived from a trace of memory operations. So maybe a better example is Cachegrind&apos;s 
profiling information, since it is computed in conjunction with a CPU simulation 
which isn&apos;t part of the original program at all. Another class of example is 
hardware simulators which computing timing information for the circuits they 
simulate. This is what makes simulation-oriented HDL constructs special, and in 
particular, &amp;ldquo;non-synthesisable&amp;rdquo;---they operate on data not present in 
silicon (and not practical to capture in silicon), but available in the simulation 
environment. This environment is effectively doing an instrumented (or 
&amp;ldquo;augmented&amp;rdquo;) run of the physical hardware. &lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Exhaustive versus non-exhaustive&lt;/strong&gt;&amp;mdash;this is arguably the 
same as &amp;ldquo;terminating&amp;rdquo;, but I think it&apos;s a useful extra bit of vocabulary 
to have. You can make an analysis terminating by time- or space-bounding it, but an 
exhaustive analysis offers a stronger property: whatever abstract space it was 
traversing, it is designed to traverse all of it.  This means the space must not 
only be finite, but small enough for computationally feasible exhaustive search. 
&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Repeating versus non-repeating&lt;/strong&gt;&amp;mdash;again, this is related to 
exhaustiveness and termination, but I&apos;d argue it&apos;s not the same. Model checkers keep 
a history of the states they&apos;ve visited, so they can detect when exploration has 
covered all states. By contrast, symbolic executors like KLEE do not keep a history, 
but store only the frontier states, so (for simple enough programs) might 
indefinitely traverse the same path through a state space. This (along with the use 
of a symbolic representation) is one of the key distinctions between KLEE and its 
forebear &lt;a href=&quot;http://www.usenix.org/event/osdi02/tech/musuvathi.html&quot;&gt;CMC&lt;/a&gt;. 
&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Adaptive/iterative versus not&lt;/strong&gt;&amp;mdash;many analyses are tunable 
or configurable in some way. By incorporating feedback from one run to the next, we 
can build a more sophisticated analysis that adaptively configures itself. CEGAR is 
a notable example. These feedback loops can yield interesting analyses of both 
terminating and nonterminating kinds, CEGAR being of the latter. (I&apos;m sure there are 
other adaptive analysis approaches, but none springs to mind right now.)&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;That&apos;s all for now. Let me know if you can think of any more noteworthy
dimensions!&lt;/p&gt;</description>
  </item>
  <item>
    <title>LLVM structural typing</title>
    <pubDate>Thu, 06 Oct 2011 18:20:00 +0200</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/10/06#llvm-types</link>
    <category>/devel</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/devel/llvm-types</guid>
    <description>
&lt;p&gt;I&apos;m learning about the LLVM compiler infrastructure at the moment.&lt;/p&gt;

&lt;p&gt;LLVM bitcode includes a notion of data types. These are used to
control implicitly the size and encoding of values generated 
by various
operations, 
to hint about mappings to underlying machine data types (e.g. 
on architectures that distinguish floating-point from integer registers)
and to implicitly cause certain transformations 
to be effected, such as padding or sign extension.
(I&apos;m not yet sure whether all such operations need to be explicitly
rendered as an LLVM &amp;ldquo;bitcast&amp;rdquo; operation or not. At least,
LLVM&apos;s notion of types can be used to define validity of these operations,
whether or not they happen implicitly.)&lt;/p&gt;

&lt;p&gt;Moreover, addresses (pointers) are typed according to the type of the
values they reference (point to). The data types are in this sense
higher-order. (This is a weaker case of &amp;ldquo;higher-order&amp;rdquo; than
types specifying the behaviour of functions. But it has some things in common.
I will blog about this more in the future.)
These data types control implicitly how much data is read or written
by indirect loads and stores.&lt;/p&gt;

&lt;p&gt;A typical C front-end will encode C data types directly into this
type system. However, this is just a convenience. The 
encoding discards some of the semantics of
the C type system, because in LLVM, composite types are treated purely
structurally, whereas in C, they are always treated nominally. Consider
this program.&lt;/p&gt;

&lt;pre&gt;#include &amp;lt;stdlib.h&amp;gt;

struct Foo {
  int a;
  int b;
};

struct Bar {
  int x;
  int y;
};

int main(void)
{
  struct Foo *f = (struct Foo *) malloc(sizeof (struct Foo));
  struct Bar *b = (struct Bar *) malloc(sizeof (struct Bar));

  free(f);
  free(b);

  return 0;
}
&lt;/pre&gt;

&lt;p&gt;In LLVM bitcode, using &lt;tt&gt;llvm-gcc&lt;/tt&gt;, we get the following.&lt;/p&gt;

&lt;pre&gt;; ModuleID = &apos;test.o&apos;
target datalayout = &quot;e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-f128:128:128-n8:16:32:64&quot;
target triple = &quot;x86_64-unknown-linux-gnu&quot;

%struct.Bar = type { i32, i32 }
%struct.Foo = type { i32, i32 }

define i32 @main() nounwind {
entry:
  %retval = alloca i32
  %0 = alloca i32
  %f = alloca %struct.Bar*
  %b = alloca %struct.Bar*
  %&quot;alloca point&quot; = bitcast i32 0 to i32
  %1 = call noalias i8* @malloc(i64 8) nounwind
  %2 = bitcast i8* %1 to %struct.Bar*
  store %struct.Bar* %2, %struct.Bar** %f, align 8
  %3 = call noalias i8* @malloc(i64 8) nounwind
  %4 = bitcast i8* %3 to %struct.Bar*
  store %struct.Bar* %4, %struct.Bar** %b, align 8
  %5 = load %struct.Bar** %f, align 8
  %6 = bitcast %struct.Bar* %5 to i8*
  call void @free(i8* %6) nounwind
  %7 = load %struct.Bar** %b, align 8
  %8 = bitcast %struct.Bar* %7 to i8*
  call void @free(i8* %8) nounwind
  store i32 0, i32* %0, align 4
  %9 = load i32* %0, align 4
  store i32 %9, i32* %retval, align 4
  br label %return

return:                                           ; preds = %entry
  %retval1 = load i32* %retval
  ret i32 %retval1
}

declare noalias i8* @malloc(i64) nounwind

declare void @free(i8*) nounwind
&lt;/pre&gt;

&lt;p&gt;Notice that although the compiler has emitted two LLVM type
definitions, one for each of our &lt;tt&gt;struct&lt;/tt&gt; types, it then proceeds
to use only the first one of them. The second is redundant, because the
two are structurally equivalent. This starts to look even more peculiar
when we make our data types recursive.&lt;/p&gt;

&lt;pre&gt;#include &amp;lt;stdlib.h&amp;gt;

struct Foo {
  int a;
  int b;
};

struct Bar {
  int x;
  int y;
};

struct FooRecursive {
  int a;
  struct FooRecursive *next;
};

struct BarRecursive {
  int a;
  struct BarRecursive *next;
};

int main(void)
{
  struct Foo *f = (struct Foo *) malloc(sizeof (struct Foo));
  struct Bar *b = (struct Bar *) malloc(sizeof (struct Bar));

  struct FooRecursive *fr = (struct FooRecursive *) malloc(sizeof (struct FooRecursive));
  struct BarRecursive *br = (struct BarRecursive *) malloc(sizeof (struct BarRecursive));
  
  free(f);
  free(b);
  free(fr);
  free(br);
  
  return 0;
}
&lt;/pre&gt;

&lt;p&gt;This gives us the following.&lt;/p&gt;

&lt;pre&gt;; ModuleID = &apos;test.o&apos;
target datalayout = &quot;e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-f128:128:128-n8:16:32:64&quot;
target triple = &quot;x86_64-unknown-linux-gnu&quot;

%struct.Bar = type { i32, i32 }
%struct.BarRecursive = type { i32, %struct.BarRecursive* }
%struct.Foo = type { i32, i32 }
%struct.FooRecursive = type { i32, %struct.BarRecursive* }

define i32 @main() nounwind {
entry:
  %retval = alloca i32
  %0 = alloca i32
  %f = alloca %struct.Bar*
  %b = alloca %struct.Bar*
  %fr = alloca %struct.BarRecursive*
  %br = alloca %struct.BarRecursive*
  %&quot;alloca point&quot; = bitcast i32 0 to i32
  %1 = call noalias i8* @malloc(i64 8) nounwind
  %2 = bitcast i8* %1 to %struct.Bar*
  store %struct.Bar* %2, %struct.Bar** %f, align 8
  %3 = call noalias i8* @malloc(i64 8) nounwind
  %4 = bitcast i8* %3 to %struct.Bar*
  store %struct.Bar* %4, %struct.Bar** %b, align 8
  %5 = call noalias i8* @malloc(i64 16) nounwind
  %6 = bitcast i8* %5 to %struct.BarRecursive*
  store %struct.BarRecursive* %6, %struct.BarRecursive** %fr, align 8
  %7 = call noalias i8* @malloc(i64 16) nounwind
  %8 = bitcast i8* %7 to %struct.BarRecursive*
  store %struct.BarRecursive* %8, %struct.BarRecursive** %br, align 8
  %9 = load %struct.Bar** %f, align 8
  %10 = bitcast %struct.Bar* %9 to i8*
  call void @free(i8* %10) nounwind
  %11 = load %struct.Bar** %b, align 8
  %12 = bitcast %struct.Bar* %11 to i8*
  call void @free(i8* %12) nounwind
  %13 = load %struct.BarRecursive** %fr, align 8
  %14 = bitcast %struct.BarRecursive* %13 to i8*
  call void @free(i8* %14) nounwind
  %15 = load %struct.BarRecursive** %br, align 8
  %16 = bitcast %struct.BarRecursive* %15 to i8*
  call void @free(i8* %16) nounwind
  store i32 0, i32* %0, align 4
  %17 = load i32* %0, align 4
  store i32 %17, i32* %retval, align 4
  br label %return

return:                                           ; preds = %entry
  %retval1 = load i32* %retval
  ret i32 %retval1
}

declare noalias i8* @malloc(i64) nounwind

declare void @free(i8*) nounwind
&lt;/pre&gt;

&lt;p&gt;Notice that the self-referencing structure of &lt;tt&gt;FooRecursive&lt;/tt&gt;
has been lost, again because a different type is structurally
equivalent.&lt;/p&gt; 

&lt;p&gt;Now for a final experiment: what about singleton structs? Are they
structurally equivalent to a single element? I&apos;ll throw in a
&lt;tt&gt;typedef&lt;/tt&gt; too, to see whether that appears.&lt;/p&gt;

&lt;pre&gt;#include &amp;lt;stdlib.h&amp;gt;

struct Foo {
  int a;
};
typedef int Baz;

int main(void)
{
  struct Foo *f = (struct Foo *) malloc(sizeof (struct Foo));
         Baz *b =        (Baz *) malloc(sizeof        (Baz));
  
  free(f);
  free(b);
  
  return 0;
}
&lt;/pre&gt;

&lt;p&gt;Here&apos;s the code it generates.&lt;/p&gt;

&lt;pre&gt;; ModuleID = &apos;test.o&apos;
target datalayout = &quot;e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-f128:128:128-n8:16:32:64&quot;
target triple = &quot;x86_64-unknown-linux-gnu&quot;

%struct.Foo = type { i32 }

define i32 @main() nounwind {
entry:
  %retval = alloca i32
  %0 = alloca i32
  %f = alloca %struct.Foo*
  %b = alloca i32*
  %&quot;alloca point&quot; = bitcast i32 0 to i32
  %1 = call noalias i8* @malloc(i64 4) nounwind
  %2 = bitcast i8* %1 to %struct.Foo*
  store %struct.Foo* %2, %struct.Foo** %f, align 8
  %3 = call noalias i8* @malloc(i64 4) nounwind
  %4 = bitcast i8* %3 to i32*
  store i32* %4, i32** %b, align 8
  %5 = load %struct.Foo** %f, align 8
  %6 = bitcast %struct.Foo* %5 to i8*
  call void @free(i8* %6) nounwind
  %7 = load i32** %b, align 8
  %8 = bitcast i32* %7 to i8*
  call void @free(i8* %8) nounwind
  store i32 0, i32* %0, align 4
  %9 = load i32* %0, align 4
  store i32 %9, i32* %retval, align 4
  br label %return

return:                                           ; preds = %entry
  %retval1 = load i32* %retval
  ret i32 %retval1
}

declare noalias i8* @malloc(i64) nounwind

declare void @free(i8*) nounwind
&lt;/pre&gt;

&lt;p&gt;Predictably, the typedef has gone away entirely, because it
introduces no new structure. However, our singleton struct has stayed
around. This isn&apos;t surprising either, because LLVM has instructions for
accessing field members, whose semantics are affected by these
structural differences. Composite types are not just sugar for arrays of
bytes or words.&lt;/p&gt;

&lt;p&gt;This does mean that if we wanted to encode nominal types into our
LLVM bitcode, we could do it by wrapping nominally distinct types in
differing depths of layered singleton structs. This would affect the
bitcode that came out, e.g. inserting extra &lt;tt&gt;GetElementPtr&lt;/tt&gt;
operations, but shouldn&apos;t affect the optimised compiler output.&lt;/p&gt;

&lt;p&gt;Overall, we can say that LLVM&apos;s data types are an annotation
useful primarily for propagating and/or inferring
data size and encoding information contextually through load and store
operations. They are also used for checking: the bitcode is checked 
for first-order type errors. Since they are raised at the point of pointer
use (e.g. a pointer assignment without appropriate bitcast is an error),
they can catch likely first-order errors early, i.e. when a pointer is 
generated or stored, rather than later when it is dereferenced and its
target data is misinterpreted. Here by &amp;ldquo;first-order type errors&amp;rdquo;
I roughly mean those at the machine level, meaning they always concern the
misinterpretation of bit-patterns encoding primitive values (integers,
addresses, floating-point numbers). Since nominally distinct data types
are conflated when they are structurally equivalent, then without using
the encoding trick I mentioned, the bitcode will
not capture, say, that one variable encodes polar coordinates by x and
r, and another by r and theta.  Detecting violation of these
abstractions is beyond the reach of any analysis based (only) on
LLVM data types using the standard encoding.&lt;/p&gt;

&lt;p&gt;This includes dynamic analyses. Right now I&apos;m writing an
&lt;tt&gt;is_a&lt;/tt&gt; function for KLEE. KLEE is (effectively) a fancy LLVM
interpreter. Without recourse to the source code and/or hacking the C
front-end, we can only do &lt;em&gt;structural&lt;/em&gt; &lt;tt&gt;is_a&lt;/tt&gt;, which is
slightly disappointing. I should add that I&apos;m not criticising LLVM here
at all. Intermediate representations are not the place for fancy type
systems, and the structural approach works nicely. It just means more
work for me, when it looked for a moment as though I could abuse
pre-existing functionality.&lt;/p&gt;</description>
  </item>
  <item>
    <title>Pipelines (are lazy functional composition with recombination)</title>
    <pubDate>Mon, 22 Aug 2011 12:36:00 +0200</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/08/22#pipelines</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/pipelines</guid>
    <description>
&lt;p&gt;Unix pipelines are often held up as a paragon of compositional virtue.
It&apos;s amazing how much they can do, how efficiently and how (relatively)
simple to use they can be.&lt;/p&gt;

&lt;p&gt;Programming languages people especially like this sort of thing, and
functional programming clearly has some synergy with pipelines---which
are, clearly, a kind of functional composition. Microsoft&apos;s F# language
even uses the pipe to denote functional composition.&lt;/p&gt; 

&lt;p&gt;But pipes are not just compositions of functions mapped over lists. They
have two other properties that are critical. The first is well-known,
and the second less so.&lt;/p&gt;

&lt;p&gt;First is laziness. Since each process in the pipeline explicitly forces
its input,  pipelines can be used on infinite streams (or portions
thereof) just the same as with finite data.&lt;/p&gt;

&lt;p&gt;The second is what I call recombination. Each stage in the pipeline can
have radically different ideas about the structure of data. For example,
pipelines typically combine characterwise (&lt;tt&gt;tr&lt;/tt&gt;) linewise
(&lt;tt&gt;sed&lt;/tt&gt;) and whole-file (&lt;tt&gt;sort&lt;/tt&gt;) operations in one go.&lt;/p&gt; 

&lt;p&gt;This is much harder to achieve in a functional setting because you don&apos;t
have access to an underlying representation (cf. character streams on
Unix): if your part of the pipeline understands data differently than
the previous one, you have to map one abstraction to the other by
writing a function. &lt;/p&gt;

&lt;p&gt;Meanwhile, the shell programmer has a lower-level set of tools: familiar
recipes for dealing with lower-level idioms such as line-breaking and
field separation that recur across many different kinds of abstract data
but may be recombined using the same tricks in each. &lt;/p&gt;

&lt;p&gt;The upside of the abstract, functional approach is that you preserve the
meaning of your data, even in the face of some heavyweight
transformations. Meanwhile, shell programmers are often driven to
frustration by their separator-munging not working properly once things
get complex.&lt;/p&gt;

&lt;p&gt;The downside is that it&apos;s more work, and more repeated work, because you
might (in the worst case) have the quadratic problem of having to map
&lt;i&gt;n&lt;/i&gt; abstractions to &lt;i&gt;n-1&lt;/i&gt; other abstractions. By contrast,
simple pipelines can often be  quickly hacked together using a few
standard idioms. They can even be written to be robust to changes in the
underlying abstraction (such as numbers of fields), although this takes
some extra care.&lt;/p&gt;

&lt;p&gt;A middle ground might be to characterise those idioms and formalise them
as a functional abstraction, into which many higher-level abstractions
could be serialized and deserialized, but without going all the way down
to bytes. Perhaps such a system already exists... it sounds a bit like a
reflective metamodel of functional records or somesuch. Hmm... perhaps
Lispers have been doing this for decades?&lt;/p&gt;</description>
  </item>
  <item>
    <title>In praise of (good) workshops</title>
    <pubDate>Fri, 08 Jul 2011 12:28:00 +0200</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/07/08#workshops</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/workshops</guid>
    <description>
&lt;p&gt;Publishing has at least two roles in science. On the one hand, it is a
means of disseminating results, concretising the &amp;ldquo;progress&amp;rdquo;
made by completed work. On the other hand, it is a source of feedback:
it&apos;s a pillar of the peer review system that rejected papers receive
feedback. Meanwhile, the idea behind conferences and workshops is, at
least in theory, that each presentation will stimulate discussion and
further feedback.&lt;/p&gt;

&lt;p&gt;During my PhD I learnt the value of a pattern which seemed to suit my
style of work, as follows. When work is under way, write an in-progress
style of paper. This gathers early feedback. If it gets accepted (which
it usually will, if the idea is good), you also get the benefit of the
presentation and the subsequent feedback and discussion. Later, once you
have results, write a full research paper to present them. Inevitably,
you will have a lot more to say this time round. Some things will have
changed, too. You will be able to write a better paper than before,
because the earlier paper gave you some idea how to present the work and
how to address its perceived weaknesses. (I admit I&apos;ve only completed
this bit of the cycle once so far! There is more in the
pipeline....)&lt;/p&gt;

&lt;p&gt;When I first went to a conference, I was surprised at how little
conferring was going on. Many talks received only a couple of questions.
Workshops, on the other hand---at least the good ones---set aside more
time for discussion.  Smaller audiences at workshops make it more likely
that people will initiate discussion as a talk goes along. The lunch and
other break times tend to have a more discussion-heavy vibe than those
between conference sessions. This is perhaps, again, because a small
number encourages more discussion. Also. the workshop group tends to
&amp;ldquo;stick together&amp;rdquo;, rather than in a conference where people
diffuse between sessions. I guess single-track conferences are better in
this respect, but I&apos;ve only been to one of those, and I don&apos;t recall a
lot of high-quality discussion that time.&lt;/p&gt;

&lt;p&gt;(Poster sessions are not bad either, for discussion, if your poster can
grab people&apos;s attention.  But they are painful to present at... never
again, I have vowed.)&lt;/p&gt;

&lt;p&gt;Recently I had it put to me by an experienced researcher that
workshops are not worth bothering with: they&apos;re just for people who are
starting out, or for less good work, and they stop you from publishing
at a better venue. I sympathise because I&apos;ve been to some bad workshops,
and seen some decidedly poor &amp;ldquo;research&amp;rdquo; presented at them.
But that&apos;s an argument for greater workshop participation, not less.
Submitting interesting ideas to workshops, for discussion, is exactly
what&apos;s supposed to happen. The reason that they degenerate into small
conferences for mediocre-or-worse work is precisely because they don&apos;t
get enough good submissions by good people. Some workshops are
established, and get good participation, and work very well in that
form.&lt;/p&gt;

&lt;p&gt;Prior publication at workshops is a subtle thing, but in short, is
not something I worry about.  I have certainly seen workshops having
(online) digital proceedings but from which it&apos;s common to see follow-up
papers appear later at conferences.  I&apos;m not sure  whether this is
because workshop papers, being more preliminary presentations of work,
simply &amp;ldquo;don&apos;t count&amp;rdquo; (an opinion I&apos;ve heard voiced) or
because those follow-up papers present quite a large delta. For the kind
of work I do, a big delta is not hard to achieve anyhow---the
contributions of the workshop paper would mostly be in argument,
&amp;ldquo;position&amp;rdquo; or &amp;ldquo;idea&amp;rdquo;, together with perhaps some
motivating experiments and preliminary results. Implementation and
ensuing experimental work is saved for a full paper. Archival is cheap
nowadays, so the convenience of having a printed proceedings accessible
from the same place where we can find all the other papers shouldn&apos;t be
seen as giving equal contribution-weight to these papers. (Suggesting
otherwise seems to me to be endorsing a &lt;a
href=&quot;http://portal.acm.org/citation.cfm?id=1297815&quot;&gt;&amp;ldquo;numbers
game&amp;rdquo;&lt;/a&gt; approach to the evaluation of research. Heaven forbid
that we actually decide for ourselves what the contribution of some
paper is, by reading it.)&lt;/p&gt;

&lt;p&gt;I can see this split being less applicable for more theoretical work.
The more abstract the formulation of the problem, the less there is to
argue about. For practical work, discussing the problem set-up and
high-level approach is very valuable. Even when work seeks to build
big systems, the idea behind some work is often much bigger than the part
that you are actually able to implement in practice. It&apos;s nice to have
an opportunity for the bigger ideas to be discussed, reviewed and
recognised.&lt;/p&gt;

&lt;p&gt;A final reason for me to enthuse about workshops is that I&apos;m one of
the &amp;ldquo;little guys&amp;rdquo;. So far I&apos;ve worked only on my own. I
don&apos;t have big collaborative projects whose conference papers I can
parachute onto. And I don&apos;t have very many coworkers who I can discuss
my ideas in detail with. Workshops are a support infrastructure that I
particularly need---for feedback, and also, perhaps slightly cynically,
to maximise the exposure my work gets. Ultimately I want to convince
people that my research vision is worth investing in. It&apos;s important
that I take up opportunities for conveying my potential---which I
believe to be great!---as well as what I&apos;ve achieved, which will never
match up to those who are habitual collaborators. Of course I&apos;m not
opposed to collaborating---far from it, but I just can&apos;t seem to find
the right person....&lt;/p&gt;</description>
  </item>
  <item>
    <title>Functionality, not (just) reliability</title>
    <pubDate>Wed, 06 Jul 2011 20:25:00 +0200</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/07/06#functionality-versus-reliability</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/functionality-versus-reliability</guid>
    <description>
&lt;p&gt;I&apos;m still a newcomer to verification. The more reading on
verification I do, the more evident it is that most work in the area is
interested in checking fairly boring properties of programs: usually
that it doesn&apos;t crash, don&apos;t corrupt memory, or that some simple
assertions hold. In this post I&apos;ll argue that thinking of a provable
absence of these properties as &amp;ldquo;job done&amp;rdquo;, or even a primary
goal, is counterproductive: it overlooks the hidden costs of
verification, and overstates the value of such proof. There are far more
important top-level goals than verifying these properties, yet there
seems to be a real danger that research is overlooking these almost
entirely.&lt;/p&gt;

&lt;p&gt;To explain myself, I&apos;m going to highlight three distinctions I&apos;ve
come up with about different kinds of work that can loosely be called
&amp;ldquo;verification&amp;rdquo; or &amp;ldquo;formal reasoning about
programs&amp;rdquo;. None of them are commonly mentioned, and certainly not
by the names I&apos;ve given them. But they seem fairly important to me, and
in each case, one side of the divide is sorely neglected.&lt;/p&gt;

&lt;h4&gt;Positive specification versus negative specification&lt;/h4&gt;

&lt;p&gt;I call this kind of &amp;ldquo;doesn&apos;t fail&amp;rdquo; property
&amp;ldquo;negative specifications&amp;rdquo;---they say what the software
&lt;em&gt;shouldn&apos;t&lt;/em&gt; do. I&apos;m not trying to denigrate any work that
verifies against these specs. It&apos;s often more than difficult enough to
check these &amp;ldquo;boring&amp;rdquo; properties statically, without making
things any more &amp;ldquo;interesting&amp;rdquo;. Nevertheless, focusing only
on negative properties seems to neglect the classical goal of
verification, which is to check that an implementation satisfies a
specification &lt;em&gt;which captures its intended functionality&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Tackling this means addressing &amp;ldquo;positive specifications&amp;rdquo;:
what the software &lt;em&gt;should&lt;/em&gt; do. This is a similar distinction to
that between liveness properties and safety properties. But it is not
the same: specifying liveness in the sense of &amp;ldquo;not
deadlocking&amp;rdquo; or &amp;ldquo;not hanging&amp;rdquo; is still a negative
specification.  Really, what defines a positive property is that it has
something to do with functionality, and not whether it&apos;s stated in a way
that uses logical negation. We should aim to specify positive properties
that capture an isolated facet of our system&apos;s intended functionality,
expressed in application-level terms: perhaps small behaviours that a
program simulates (but doesn&apos;t bisimulate), or small functional
dependencies that a program reproduces.&lt;/p&gt;

&lt;h4&gt;Conservative versus &amp;ldquo;liberal&amp;rdquo; software construction&lt;/h4&gt;

&lt;p&gt;I had a hard time thinking of the right antonym to
&amp;ldquo;conservative&amp;rdquo;, and &amp;ldquo;liberal&amp;rdquo; will have to do
(as &amp;ldquo;reckless&amp;rdquo; was my other candidate).&lt;/p&gt;

&lt;p&gt;Some classical approaches to programming have a highly conservative
property that I call &lt;em&gt;compulsory proof&lt;/em&gt;: the programmer cannot
make progress without ensuring that some specification remains
satisfied. Static typing is the most familiar example: type-checking is,
from Curry-Howard, proving a property about your program. You can&apos;t do
much with a program that doesn&apos;t type-check. Refinement-based synthesis
methods are another example: a refinement step is only valid if it
preserves the specification, and provably so.&lt;/p&gt;

&lt;p&gt;As we scale up to larger and more complex programs, and larger and
more complex specifications, these approaches start to inhibit progress.
It&apos;s interesting how dependent types are still a &amp;ldquo;nearly
there&amp;rdquo; feature---nobody has made them usable yet. I&apos;m told that
making programs type-check becomes harder and harder under increasingly
dependent types. This is unsurprising: we&apos;re making the specifications
(a.k.a. types) more complex, so harder to prove satisfaction for. It
seems that the most pragmatic solution so far, is to relinquish the
insistence on proof at all times, a compromise adopted by Edwin Brady&apos;s
&lt;a href=&quot;http://www.cs.st-andrews.ac.uk/~eb/Idris&quot;&gt;Idris&lt;/a&gt;.&lt;/p&gt; 

&lt;p&gt;The idea of compulsory proof is flawed because programming is usually
exploratory. As a programmer, I often start coding before I fully
understand the problem. The process of programming provides necessary
illumination. So, presupposing any specification that I must doggedly
adhere to at each stage, whether from the tyranny of a type-checker or
the tyranny of a refinement procedure, is anathema---it &lt;em&gt;actively
stops&lt;/em&gt; me from acquiring the understanding I need to complete the
task. In the worst case, compulsory proof is a net loss: it slows us
down far more than it helps us. What&apos;s unfortunate is that our research
evaluation methods don&apos;t account for this. No programming research
considers the net worth to a human programmer. Instead it prefers the
mathematical orthodoxy of derivable properties such as preservation of
type safety. I suspect these are poorly correlated.&lt;/p&gt;

&lt;p&gt;The polar opposite to these conservative approaches, which I call
&amp;ldquo;liberal&amp;rdquo;, is exemplified by dynamic languages. Here no
proof of adherence to any specification (type-based or otherwise) is
statically enforced. The programmer is free to break his abstractions at
any time---even at run time. The only specifications of that are
enforced are those of pre-existing machine-level
abstractions---integers, pointers and floating-point numbers---whose
integrity is enforced by dynamic checks only.&lt;/p&gt; 

&lt;p&gt;Like most polar extremes, neither fully-conservative nor
fully-liberal approaches are often optimal in practice. I think the
consensus from mainstream languages (C, Java, C++) is that static
checking using a simple type system is a good idea (and I&apos;m sure even
most die-hard Python programmers often yearn for some basic static
checking). The jury is still out on the cost/benefit ratio of more
complex type systems, even such as Java&apos;s generics. Ken Arnold &lt;a
href=&quot;http://weblogs.java.net/blog/arnold/archive/2005/06/generics_consid.html&quot;&gt;vociferously
argues&lt;/a&gt; against Java generics , and when I first read his opinion, I
was sceptical of his view---surely more static checking can&apos;t hurt?
Nowadays I can see his points about the cost in complexity and,
particularly, in the proof burden on programmers.&lt;/p&gt;

&lt;p&gt;Meanwhile, from the liberal end of the spectrum, bug-finding tools
like &lt;a href=&quot;http://klee.llvm.org/&quot;&gt;KLEE&lt;/a&gt; are interesting: we
liberally (or recklessly) allow bugs into our program, then try to
whittle them down. It&apos;s bug-finding and not verification because we can
happily specify properties that the tool can&apos;t conclusively show are not
violated. A consequence is that in practice KLEE doesn&apos;t terminate for
most nontrivial programs. On the other hand, the space of assertions
that we can use KLEE to check is large: at least in theory it subsumes
type-safety (noting that a specification of type-safety can be encoded
by instrumenting an untyped program with assertions using a
suitably-defined &lt;tt&gt;instanceof&lt;/tt&gt;-like operator) and arbitrary
application-specific assertions. There are a few problems with KLEE: 
it&apos;s limited by what we can express as assertions (or built-in
properties); it doesn&apos;t terminate in enough cases; and it tends to find
uninteresting bugs which, while not technically false positives, might
well be if we could write a more refined input specification.
Nevertheless, I like it because it treats perfection (i.e. proof) as the
limit case, not the immediate goal. (It&apos;s no coincidence that I&apos;m
basically working on addressing these weaknesses right now, including
making it terminate for more programs---or at least, I would be if I
wasn&apos;t wrestling with LLVM bugs the whole time.)&lt;/p&gt;

&lt;h4&gt;Constructed reliability versus emergent reliability&lt;/h4&gt;

&lt;p&gt;Using any of these techniques takes time.  Writing specifications
takes time. Even if you say &amp;ldquo;my verifier requires no
annotations!&amp;rdquo; (like a lot of Dawson Engler&apos;s work, including
KLEE), you probably rely on assertions. Even if you restrict yourself to
&amp;ldquo;belief&amp;rdquo;-style latent specifications (like Engler&apos;s &lt;a
href=&quot;http://portal.acm.org/citation.cfm?id=502041&quot;&gt;2001 SOSP
paper&lt;/a&gt;), they got there by somebody writing code. If you rely on
&amp;ldquo;mined&amp;rdquo; specifications, as recovered by a bunch of work
(like &lt;a href=&quot;http://portal.acm.org/citation.cfm?id=1287632&quot;&gt;this&lt;/a&gt;
and &lt;a href=&quot;http://portal.acm.org/citation.cfm?id=1250749&quot;&gt;this&lt;/a&gt; and
&lt;a href=&quot;http://portal.acm.org/citation.cfm?id=1368107&quot;&gt;this&lt;/a&gt;) you
have to gather a corpus and run a mining algorithm and check for false
positives and then use some other technique to hunt the false
negatives.&lt;/p&gt; 

&lt;p&gt;In other words, despite half-claims to the contrary, we make our
software reliable by pouring some amount of labour into it. New,
exciting techniques are exciting because they deliver more with less
labour.&lt;/p&gt;

&lt;p&gt;But there is an appalling lack of holism here. (Aside: Thomas Ball&apos;s
&lt;a href=&quot;http://portal.acm.org/citation.cfm?id=1417077&quot;&gt;call for
holism&lt;/a&gt; is an interesting read and I applaud it; here I like to think
I&apos;m going much further!) What other approaches do we have for making
software reliable? How about making it easier to write the code, so that
we have &lt;em&gt;more&lt;/em&gt; labour to pour into the reliability side?&lt;/p&gt;

&lt;p&gt;In other words, nonfunctional concerns trade off against each other,
and also against &lt;em&gt;functional&lt;/em&gt; concerns! Time spent coding new
features is time taken away from static analysis or testing or any other
reliability-focused work, and vice-versa.  It&apos;s also time taken away
from profiling and optimisation, from refactoring and documentation, and
so on. So in other words, it all helps.  Software&apos;s value isn&apos;t a sum of
independent parts.  The parts are interdependent; what benefits one
benefits all. Reliability can be deliberately &lt;em&gt;constructed&lt;/em&gt; by
applying specific reliability-focused tools, and hacking at code until
it passes muster by these tools. But also, it can emerge from superior
development processes that made it easier for programmers to build in
reliability in the first place.&lt;/p&gt;

&lt;p&gt;Now let me lament my own position. In the research world, only a
relatively narrow selection of approaches get any funding. Reliability
is a perennially hot topic. It&apos;s unquestionedly considered sound
research motivation to trot out lines about the importance of reliable
cars or reliable trains or reliable nuclear power plants. Similarly,
it&apos;s routine to trot out analogies with civil engineering,
bridge-building and the like. Reliability is important, for sure. But
thinking holistically, that doesn&apos;t mean we have to attack these
problems by building tools with the narrow remit of making sure nothing
bad happens in whatever code they&apos;re given. Improving all parts of the
development process can contribute to these goals, and have untold other
economic benefits in the process. Too many researchers&apos; mission
statements list reliable software as top priority. But reliability is
just a means to economic (or &amp;ldquo;value&amp;rdquo;) gain. Hardly any
researchers will say their goals are &amp;ldquo;quality software&amp;rdquo;, or
&amp;ldquo;functioning software&amp;rdquo;, or &amp;ldquo;economical software
development&amp;rdquo;. Why not?&lt;/p&gt; A senior researcher here in Oxford recently
pitched his work (to industrial visitors) by saying that verification is
ensuring that &amp;ldquo;nothing happens&amp;rdquo;. I hope that was a gross
simplification for pitching purposes, because we can do a lot better
than that.&lt;/p&gt;

&lt;p&gt;To finish, let me shamelessly bring on some of my current
&amp;ldquo;background&amp;rdquo; research interest and activities. I&apos;m
interested in good ways of re-using existing code; good ways of adopting
programming language innovations without rewriting the world; good
editing tools (including refactoring and a whole lot more---I&apos;ll blog
shortly there); good dynamic analysis tools, including a good debugger
(again, I&apos;ll blog more shortly). Of course, I didn&apos;t manage to find a
job on any of these ideas. Since my PhD, days,  I&apos;ve felt as though I
was perhaps the only programming researcher in the world whose top
priority is not specifically code that is reliable, per se, but the
bigger yet seemingly more obvious goal of code that &lt;em&gt;does what you
want it to&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So, am I crazy? I took a job in verification because I thought I&apos;d
learn some program analysis skills that would be generally useful,
including (later) application to the problems nearest my heart, not just
to approaches sanctioned by the reliability orthodoxy. But it&apos;s a
draining experience to be railing against orthodoxy all the time,
especially when you feel like the only lunatic in the asylum. I&apos;m not
sure how much longer I can take it.&lt;/p&gt;</description>
  </item>
  <item>
    <title>Post post viva</title>
    <pubDate>Tue, 14 Jun 2011 13:31:00 +0200</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/06/14#post-post-viva</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/post-post-viva</guid>
    <description>
&lt;p&gt;I &lt;a href=&quot;http://www.inf.usi.ch/postdoc/kells/blog/research/post-viva.html&quot;&gt;blogged previously&lt;/a&gt; about my PhD
viva. I&apos;ve finally got the examiners&apos; reports, and was quite surprised by the difference between
the two. Suffice it to say that one was much more positive than the other, and reassuringly for me,
the more positive one was also from the examiner who is both more experienced in the role, and more
familiar with my research area.  (It&apos;s probably not hard for most readers to work out which one is
which.)&lt;/p&gt;

&lt;p&gt;I&apos;m only kicking myself since I could, given this information, perhaps have steered quite a
different path through the viva that would have resulted in far less extra work being demanded of
me. Nevertheless, the same points in favour of doing the &amp;ldquo;corrections&amp;rdquo; that I am doing
(a.k.a. self-financed development work) still stand from my last post, so I shouldn&apos;t kick myself
too hard.&lt;/p&gt;</description>
  </item>
  <item>
    <title>Memtable again</title>
    <pubDate>Wed, 01 Jun 2011 20:57:00 +0200</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/06/01#memtables-again</link>
    <category>/devel</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/devel/memtables-again</guid>
    <description>
&lt;p&gt;I&apos;ve finally got a nicely packaged implementation of memtables, the
data structure I introduced in &lt;a
href=&quot;http://www.inf.usi.ch/postdoc/kells/blog/devel/memtables.html&quot;&gt;a previous blog
post&lt;/a&gt;. It&apos;s in a single header---&lt;a
href=&quot;http://www.inf.usi.ch/postdoc/kells/software/memtable.h&quot;&gt;memtable.h&lt;/a&gt;. I&apos;ve also
fixed a couple of stupid bugs that crept into &lt;a
href=&quot;http://www.inf.usi.ch/postdoc/kells/software/malloc_hooks.c&quot;&gt;malloc_hooks.c&lt;/a&gt; just
before I released the initial version. You can see an example of
combining these two in &lt;a
href=&quot;http://www.inf.usi.ch/postdoc/kells/software/heap_index_hooks.c&quot;&gt;heap_index_hooks.c&lt;/a&gt;---which
you can compile into a simple LD_PRELOADable shared library that will
instrument the glibc malloc to keep an indexed table of allocated
chunks, keyed on address. It&apos;s pretty easy to search the memtable to
find the heap chunk for a given pointer &lt;em&gt;anywhere&lt;/em&gt; into an
object. I&apos;ll integrate this into my Cake runtime implementation soon,
and the whole lot will appear here in due course (i.e. eventually).&lt;/p&gt;

&lt;p&gt;If you use any of these files, please drop me a line to say how you
got on---I&apos;d really appreciate it.&lt;/p&gt;</description>
  </item>
  <item>
    <title>Namespace problems</title>
    <pubDate>Thu, 19 May 2011 19:41:00 +0200</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/05/19#c-namespace</link>
    <category>/devel</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/devel/c-namespace</guid>
    <description>
&lt;p&gt;It&apos;s always been a theoretical problem with C that there is no
namespacing. I&apos;d often wondered how much of a practical problem this
really was, with &amp;ldquo;nothing major&amp;rdquo; my tentative answer. I&apos;ve
finally run into my first bona-fide gotcha arising out of this problem.
In short: &lt;a href=&quot;http://trac.wxwidgets.org/ticket/10883&quot;&gt;wxWidgets
and GLib both define a GSocket&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Annoying as this is, it wouldn&apos;t be in my top ten grumbles about the
experience of programming in C. A far bigger related problem is
versioning. This doesn&apos;t get cited as a weakness of C because it&apos;s also
a weakness of most other programming languages. The very reason I ran
into the namespace problem was because I had to compile wxWidgets 2.6,
rather than using the 2.8 revision that&apos;s packaged for my distribution.
Version mismatches can be seen as namespace collisions too. Instead of
getting the version you want, the namespace has been populated with
slightly different stuff that is, despite its close relationship to
what you actually require, still incompatible, much the same as if the
namespace were polluted with random third-party stuff.&lt;/p&gt;

&lt;p&gt;Versioning issues could perhaps be brought more under the
programmer&apos;s control. Most programming languages don&apos;t have an explicit
notion of &amp;ldquo;version&amp;rdquo; when importing stuff. But when
explicitly consuming some target API, you are always assuming at least
something about its version. Having the programmer declare which
version of a set of declarations they want to import would be
straightforward. In C, it could even be done quite neatly with just the
preprocessor---say, &lt;tt&gt;#define __LIBFOO_REQUESTED_VERSION 4.2&lt;/tt&gt;)
before the relevant &lt;tt&gt;#include&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;Of course, pessimistically refusing to link across nominal mismatches of
version would be a bad solution. We want a more structural and, indeed,
behavioural or &amp;ldquo;semantic&amp;rdquo; approach. With the C preprocessor
approach I outlined, it becomes the header file author&apos;s responsibility
to embed a test about which prior API version the associated
implementation is compatible with, most likely using a simple
&lt;tt&gt;#if&lt;/tt&gt; test. This responsibility is not unreasonable I&apos;d say---the
developers are in the best place to say what has changed with a new
revision. And since it&apos;s in a header file, if the maintainers are lazy,
the client programmer can override it.&lt;/p&gt;

&lt;p&gt;One shortcoming of this approach is that the client programmer might
be too lazy to work out which is the &lt;em&gt;earliest&lt;/em&gt; library version
their code will work with, and will instead select whatever version
they are developing with. This is safe, but prevents some valid
compositions. On a different system with a slightly older version of
the library, the header might conservatively conclude that it&apos;s not
compatible with the client, even though it could work. Anyway, I don&apos;t
worry about this too much. Lots of researchers have thought about
versioning before, so there&apos;s probably some good solutions knocking
around.&lt;/p&gt;

&lt;p&gt;Back to the sockets example, it&apos;s perhaps unsurprising that the name
collision occurred when linking two chunks of infrastructure code. Name
collisions are most likely when abstracting the same domain, having the
same natural language vocabulary---namely sockets in this case. This is
much more likely to happen in infrastructure software (i.e. modelling
system resources) than application level software (modelling circles or
ellipses or airline reservations or health records and so on), simply
because you&apos;re less likely to link multiple instances of the latter
together. Whereas application-level code is at or near the top of the
software dependency graph, the infrastructure stuff is lower down so
more likely to get sucked into a program through dependency.&lt;/p&gt;

&lt;p&gt;I was interested to note Nick Nethercote&apos;s &lt;a
href=&quot;http://blog.mozilla.com/nnethercote/2011/05/12/duplicated-abstraction-layers-in-firefox/&quot;&gt;recent
blog entry&lt;/a&gt; about a problem with duplication (generally) and bloat
(specifically) associated with multiple wrapper layers for system calls
and other nonportable interfaces. He was talking about &lt;tt&gt;mmap()&lt;/tt&gt;,
but the socket abstraction is another example. I have some research
proto-ideas that might help with this problem.  Essentially I&apos;m
interested in recovering a more finer-grained style of interface
description from code, based on the idea of &amp;ldquo;relational
interfaces&amp;rdquo;. You could then use this description to infer that
two sets of functions had very similar behaviour, and factor out the
duplication (with appropriate refactoring or adaptation tools).&lt;/p&gt;

&lt;p&gt;This whole problem is another consequence of our fragile
direct-interfacing, in-order methods for constructing of software. If
we had a more flexible way of constructing software, the problem
wouldn&apos;t arise. Rather than slavishly building on predefined interfaces
that are specific to one underlying component---like one
&lt;tt&gt;mmap()&lt;/tt&gt; abstraction layer, or one socket abstraction--- we need
smarter tools for specifying our requirements abstractly and finding
customised ways of satisfying them using a range of &amp;ldquo;found&amp;rdquo;
code. This is what my &lt;a
href=&quot;http://www.inf.usi.ch/postdoc/kells/research/papers/kell09mythical.pdf&quot;&gt;Onward! &apos;09
proto-paper&lt;/a&gt; was ranting about. I guess it&apos;s good that I&apos;m still ranting.
Interface hiding is as good an idea as ever, and more work on it 
&lt;em&gt;will&lt;/em&gt; happen, when I get time....&lt;/p&gt;</description>
  </item>
  <item>
    <title>Memtables</title>
    <pubDate>Thu, 19 May 2011 19:41:00 +0200</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/05/19#memtables</link>
    <category>/devel</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/devel/memtables</guid>
    <description>
&lt;p&gt;At the &lt;a
href=&quot;http://www.dcs.gla.ac.uk/~jsinger/mmnet11.html&quot;&gt;MMNet
workshop&lt;/a&gt; in Glasgow last week, I talked about memtables. These are
an efficient associative data structure, built using virtual memory
support on modern OSes (currently implemented for Linux only), that are
useful whenever you want to key a table on addresses in memory. See &lt;a
href=&quot;http://www.inf.usi.ch/postdoc/kells/research/talks/kell11how-slides.pdf&quot;&gt;my slides&lt;/a&gt;
for more.&lt;/p&gt;

&lt;p&gt;Since entries with numerically similar keys are stored close to each
other, memtables are, like certain other associative data structures,
amenable to searching within a key range as well as exact-match
lookups. By contrast, hash tables can&apos;t do this. (That said, a hash
table supporting duplicate keys can be used to store items grouped into
small equivalence classes. This is sometimes good enough, and could be
made to work in my case. Nonuniform key duplication will mess up the
O(1) nature of hash tables though.)&lt;/p&gt;

&lt;p&gt;Memtables seem like they could be useful in lots of places. I invented
them for &lt;a href=&quot;http://www.inf.usi.ch/postdoc/kells/research/cake&quot;&gt;DwarfPython&lt;/a&gt; as a
fast way of storing and retrieving  metadata given a key that may be an
interior pointer  (hence the searching requirement). I&apos;m also (soon)
using them in &lt;a href=&quot;http://www.inf.usi.ch/postdoc/kells/research/cake/&quot;&gt;Cake&lt;/a&gt; as a
fast way of tracking what objects are associated with what other
objects.&lt;/p&gt;

&lt;p&gt;The key space doesn&apos;t have to be addresses. It&apos;s possible we could even
use memtables for free chunk binning, since large sizes are sparsely
used. I need to do some more experiments to establish this.&lt;/p&gt;

&lt;!-- 
e.g. one word of index for each size
of chunk that is free? 

first page covers sizes (0..512)&lt;&lt;3 

supposing
our largest malloc is 1GB,  we need 
(0..128MB)&lt;&lt;3 i.e. 128 * 1024 * 2
pages = 262,144 pages (2^17) 
i.e. 2^29 bytes of VAS, or 1/8 of a 32-bit VAS! So not great.

Less bad for 64-bit, and can make it 1/32 by saying max alloc is 256MB 
in 32-bit case
--&gt;

&lt;p&gt;The implementation comes in two parts:&lt;/p&gt;

&lt;ll&gt;

&lt;li&gt;&lt;strong&gt;A &lt;a href=&quot;http://www.inf.usi.ch/postdoc/kells/software/malloc_hooks.c&quot;&gt;generic set of malloc hooks&lt;/a&gt; for glibc:&lt;/strong&gt; these
hooks aree &amp;ldquo;generic&amp;rdquo; in that they&apos;re designed to be easily
specialised for various conceivable kinds of instrumentation. They&apos;re
not generic with respect to the allocator---sadly they&apos;re specific to
glibc, but most mature allocators should have some similar mechanism.
The key usefulness in these hooks is factoring the various cases of the
malloc API ---specifically the complex behaviour of realloc, but also
other annoyances including memalign and null frees--- into an
easy-to-use set of higher-level hooks. These are likely (but not
guaranteed) to be a better match for whatever your instrumentation is
doing. For example, defining a &lt;tt&gt;post_successful_alloc()&lt;/tt&gt;
function will hook all events that allocate a new heap block, whether
they originated in a &lt;tt&gt;malloc()&lt;/tt&gt;, a &lt;tt&gt;realloc()&lt;/tt&gt; or a
&lt;tt&gt;memalign()&lt;/tt&gt;.&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;a generic memtable library:&lt;/strong&gt; this will appear soon!
It&apos;s a set of hook definitions that maintain a memtable, and a lookup
function.&lt;/li&gt;

&lt;/ll&gt;

&lt;p&gt;Memtables are strictly faster than a hash table, at least for
lookups, because they are basically a hash table without the hashing.
At least for most applications of memtables, the table itself acts as
an index for a bunch of linked lists---call them bins or buckets.
Rather than mapping the key space onto a smaller hash space in order to
keep the index small, we index directly by the key, and rely on the
virtual memory trick to keep the index small. Since we can only save
page-sized chunks of space, the key-space really needs to be used in a
clustered and/or &lt;em&gt;very&lt;/em&gt; sparse fashion. Just one used key per
page of index is enough to allocate the whole table in physical memory,
which we don&apos;t want. So if your table has four-byte entries, say,
uniform key usage should be a lot less than one per thousand possible
keys---but clusters of many are okay, so long as they&apos;re thousands
apart.&lt;/p&gt;</description>
  </item>
  <item>
    <title>PhD examination</title>
    <pubDate>Wed, 13 Apr 2011 14:10:00 +0200</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/04/13#post-viva</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/post-viva</guid>
    <description>
&lt;p&gt;So I passed my PhD viva a couple of weeks ago. I do, however, have a
lot of corrections to do. In fact I have about the most corrections I
could have, in hours of work terms, without having to resubmit my
thesis. Thank God I don&apos;t have to do that. As it happens, the actual
corrections to my thesis are not very many. I have to add the odd
paragraph here and there, and collect a small amount of extra data. The
killer is the non-thesis bit. I&apos;ll talk about that in a moment.&lt;/p&gt;

&lt;p&gt;There&apos;s a lot I could say to summarise my feelings about the viva.
Here are the two words I&apos;ve been using most when people have asked me
how it went: &amp;ldquo;reasonable&amp;rdquo; and &amp;ldquo;annoying&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;For the &amp;ldquo;reasonable&amp;rdquo; part, I have to thank my examiners,
&lt;a href=&quot;http://www.cl.cam.ac.uk/~acr31/&quot;&gt;Andy Rice&lt;/a&gt; and &lt;a
href=&quot;http://www.doc.ic.ac.uk/~alw/&quot;&gt;Alex Wolf&lt;/a&gt;, who deserve credit
for the depth at which they got to grips with my thesis. I was quite
impressed with their attention to detail. Although I can (and will,
shortly) disagree with their take on what is necessary or sufficient to
substantiate my thesis, I also appreciate how my doing so is very much
challenging a norm... and the examination process isn&apos;t the right place
to do this. Examination is a pragmatic business, and when considered
less on intellectual high ground and more in terms of personal risk and
reputation, I could not reasonably have expected (at least not with high
probability) their taking a different position.&lt;/p&gt;

&lt;p&gt;For the &amp;ldquo;annoying&amp;rdquo; part, in short, I was far too
idealistic in my conception of the PhD examination process. Of course it
has some room for intellectual rigour; but virtually no research in any
practical field has such unthreatened validity that examination doesn&apos;t
fall back on &amp;ldquo;due diligence&amp;rdquo; to some extent. Another word
for &amp;ldquo;due diligence&amp;rdquo; is &amp;ldquo;hoop-jumping&amp;rdquo;, and that
really sums up why I think my thesis attracted the complaints that it
did: it didn&apos;t jump enough established hoops to make the examiners feel
comfortable rubber-stamping it. I&apos;m not saying my thesis is great; it&apos;s
fairly weak really---but it&apos;s no weaker than a lot of other theses which
seem to pass without problem. I suppose the examiners did rubber-stamp
it in the end, given that I passed---but subject to corrections which,
unsurprisingly, make it jump an additional hoop. I don&apos;t feel that
jumping this hoop substantiates the thesis any more strongly, and this
is the centre of my annoyance.&lt;/p&gt;

&lt;h4&gt;A new rant about an old problem&lt;/h4&gt;

&lt;p&gt;My problem is not a new one. Introducing a new language is a
relatively common thing for a CS researcher to do. Assuming the claimed
benefit of the language is a practical one, rather than a theoretical
one, then evaluating the language is a huge problem. PhD students don&apos;t
have the time or the budget to carry out large field studies. Anyway,
instead of this, the usual approaches are to prove something about the
language, to show that it has reasonable performance, and/or to apply it
to case studies. I&apos;m going to be bold and claim that the first two are
hoop-jumping in most cases. It&apos;s a rare case indeed where a language&apos;s
goal is actually to realise the theoretical property in question or to
&amp;ldquo;do X really fast&amp;rdquo;. (Of course, other kinds of work, in
theory and systems respectively, do have these as express goals, but I&apos;m
talking about languages here, where &amp;ldquo;language&amp;rdquo; is distinct
from &amp;ldquo;calculus&amp;rdquo;.)&lt;/p&gt;

&lt;p&gt;It&apos;s reasonable to set for your language a performance or theoretical
goals &lt;em&gt;in addition&lt;/em&gt; to your main goal, as this can be a source of
interesting problems and brings the work closer to applicability in
practice or interest in theory. However, it really annoys me when people
confuse these goals. I hate seeing papers which introduce some new
language feature that is claimed to help programmers---the usual end
goal of any language---and then evaluate it either by an irrelevant
proof or irrelevant performance measurement. This has the effect of
encouraging both a confusion between the main goal of a language and
these side-goals, and moreover, encouraging a culture where evaluating
the main goal is neglected in favour of the side-goals, or where the
side goals are seen to imply the main goals.&lt;/p&gt; 

&lt;h4&gt;Trouble with case studies&lt;/h4&gt;

&lt;p&gt;Case study evaluation is unsurprisingly the approach I chose. This
might have passed muster, except that the other hoop I didn&apos;t jump
through was producing a complete working implementation. This doesn&apos;t
mean I didn&apos;t implement anything: I did a &lt;em&gt;lot&lt;/em&gt; of implementation
work during my PhD. But for various reasons, my reach had exceeded my
grasp. I had plenty of working examples of the techniques I wrote about,
but the code generation side of my compiler had got hairy enough that I
decided that it should suffice to show &lt;em&gt;implementability&lt;/em&gt; rather
than implementation. I think I did this, and I don&apos;t think my examiners
doubted it either, although they did mince some words on the subject. In
the end, they were reluctant to accept this implementability evidence as
sufficient defence of the thesis. I couldn&apos;t put my finger on why, and I
wouldn&apos;t say they could, either. Instead, I only got some quite vague
questions, in essentially four forms.&lt;/p&gt;

&lt;p&gt;The first was: &amp;ldquo;How do you know your language features are
sufficient?&amp;rdquo; Of course, I &lt;em&gt;don&apos;t&lt;/em&gt;. Since I spent a whole
chapter talking about cases that &lt;em&gt;aren&apos;t&lt;/em&gt; handled, clearly I make
no such claim (although I do identify what needs fixing and how this
doesn&apos;t break the key abstractions of the language). I do claim that
they&apos;re sufficient for the case studies, and that since these are
representative of other code, that they will be sufficient for a wider
range of code. This is demonstrated by argument and careful analysis of
code rather than saying &amp;ldquo;we ran it&amp;rdquo;. But saying &amp;ldquo;we
ran it&amp;rdquo; is still subject to error---since realistically, how much
testing did you do, and how can you be sure it was enough? The case the
examiners seemed to worry most about was the one where, by failing to
account for some unspecified detail, some new language feature or
altered semantics would be necessary just to handle the case studies
themselves, never mind other examples to which I claimed it generalised.
I think I provided quite a weight of evidence that this wasn&apos;t going to
happen. However, even if it did, it would still a matter of error bars,
not validity.&lt;/p&gt;

&lt;p&gt;The second was: &amp;ldquo;How do you know you haven&apos;t forgotten
something in your implementation?&amp;rdquo; Again, I don&apos;t, but I have
implemented &lt;em&gt;enough&lt;/em&gt; that the &lt;em&gt;implementability&lt;/em&gt; isn&apos;t in
doubt. Even if a fully working version would turn up one or two extra
details that need addressing, this wouldn&apos;t undermine the thesis.&lt;/p&gt;

&lt;p&gt;A final question: &amp;ldquo;How do you know your language features are
necessary?&amp;rdquo; I still find this question bizarre. The language
features exist to handle common cases in a way that saves programmer
effort.  Every feature is illustrated with a plausibly common example,
and any experienced programmer would recognise its usefulness. This
doesn&apos;t mean they couldn&apos;t be eliminated, but doing so would bring a
strict degradation in what the language offers the programmer.&lt;/p&gt;

&lt;p&gt;What didn&apos;t help was that the examiners didn&apos;t ask me these questions
one at a time, but rather rotated among them with dizzying speed. It was
though they themselves hadn&apos;t yet separated them in their own heads.
Without this, I might have been able to fend them off better, along the
above lines. As it was, I can&apos;t help feel I did well not to get too put
out by it all. I nearly did lose my cool at one point where one examiner
suddenly claimed that I needed to  do a performance evaluation.  I had
very explicitly and very clearly excluded performance from any but
informal consideration very early in the dissertation, precisely in
order to prevent my task from blowing up even further than it already
had. Fortunately I managed to argue this one down, although annoyingly,
I still have to gather some (meaningless, but fairly trivial to collect)
performance data for my corrections.&lt;/p&gt;

&lt;h5&gt;The &amp;ldquo;solution&amp;rdquo;&lt;/h5&gt;

&lt;p&gt;So, how did the examiners propose that I answer their objections? In
the time-honoured hoop-jumping way: to finish the implementation, of
course, so that I can say &amp;ldquo;I ran it&amp;rdquo;! Actually I only have
to get it up to a certain level, rather than finishing everything, which
I suppose is something to be glad about. But I had failed to complete my
implementation for very good reasons: it&apos;s a ton of work, and it was
already past the point where its &lt;em&gt;feasibility&lt;/em&gt; was established.
In hindsight I could have written up this fact better. But I think it
was still clear that what remains is a matter of development---which I
wasn&apos;t prepared to spend any more of my own money to fund, given that
I&apos;d already spent 6 months living off savings and consultancy work.
Fortunately, circumstances now mean that I have a job which pays enough
that by going part-time I can get it done while remaining solvent. (It
also had to happen this way round, since if I hadn&apos;t been able to submit
my thesis without a full implementation, I wouldn&apos;t have been able to
get the job that is now, indirectly, paying for the implementation&apos;s
completion.) Of course, my financial situation is an irrelevance as far
examination goes, and it has to be that way. The moral is that there is
no safety net, and nobody who is truly responsible for your thesis than
yourself. The system is accountable to nobody, and it has no incentive
for self-improvement... except maybe to the extent that (and over the
timescales by which) PhD examinees who suffer negative experiences
become examiners who can still remember them. &amp;ldquo;It&apos;s not
fair!&amp;rdquo; as Jennifer Connolly once declaimed, &amp;ldquo;... but that&apos;s
the way it is&amp;rdquo;.&lt;/p&gt;

&lt;h5&gt;The role of empirical rigour&lt;/h5&gt;

&lt;p&gt;At the moment, and probably since time immemorial, there is a cohort
of CS researchers in the fields of programming languages and software
engineering who are &lt;a
href=&quot;http://evaluate.inf.usi.ch/letter-to-pc-chairs&quot;&gt;vociferously
advocating&lt;/a&gt; greater empirical rigour in research.  Early on in my
PhD, I thought that this movement could only be bad news for little old
me. I barely had the resources to produce an implementation within one
PhD, never mind do an empirically rigorous user study. However, now I
think that this movement is actually on my side (as well as the side of
&amp;ldquo;truth&amp;rdquo; and good science, which I didn&apos;t doubt). The
hoop-jumping that would have satisfied my examiners---producing a
working implementation and running it---doesn&apos;t actually strengthen my
thesis, and in an empirically rigorous discipline, this would be clear.
In turn, it would probably be a more &amp;ldquo;done thing&amp;rdquo; to submit
theses that don&apos;t tell a complete story---because telling a complete
story on something complex as complex as a practical programming
language, and doing so with empirical rigour, is too much work for one
PhD. Perhaps it would be more acceptable to package research
&amp;ldquo;towards&amp;rdquo; a goal,  evidence but not yet conclusive evidence,
with its outstanding threats to validity clearly explained, yet
unresolved. Instead, in our empirically immature discipline, we try to
brush these unresolved threats aside by arbitrary hoop-jumping.&lt;/p&gt;

&lt;p&gt;The downside of a more empirically rigorous discipline would of
course be that each researcher can&apos;t race ahead quite so fast. Within
the scope of one PhD, there is far less prospect of telling a neat,
complete story. In my case, this would have been both good and bad. For
empirical rigour&apos;s sake, I would have to have spent much longer on case
study, including (probably) &lt;em&gt;starting&lt;/em&gt; my thesis with an
empirical study. Perhaps &lt;em&gt;all&lt;/em&gt; implementation would have to be
left for the future, and my thesis&apos;s contribution would mostly be on
understanding the problem empirically, with a paper sketch of the
solution validated by detailed analysis of examples. Of course, this
paper sketch would have a weight of evidence behind it. The downside is
that I actually like the idea of implementing stuff, and even though I
haven&apos;t (yet) finished the job (and I am now working on it, again), I
would have found it frustrating to embark on a PhD with no intention of
completing an implementation.&lt;/p&gt; 

&lt;h5&gt;Conclusion&lt;/h5&gt;

&lt;p&gt;This post probably sounds like a lot of sour grapes, although I hope
it doesn&apos;t. It&apos;s actually a positive thing for me that circumstances
have conspired to give me a chance to finish the Cake implementation,
since it will be a useful springboard for future work and perhaps even
(gasp) impact. Previously, when I was resigned to not finishing it, it
was looking like this would become an albatross. More generally though,
I can&apos;t pretend not to be a little bit sour about the course my PhD
took. Despite making what were defensible and reasonable moves at each
stage, the whole thing turned into a bit of a mess and has caused me a
lot of pain. However, the mess of the work (which could have been
better, but I think was comfortably &amp;ldquo;good enough&amp;rdquo;) is a
different mess from that of the examination. I am now very strongly
convinced that there really is a problem with the attitudes to evidence,
rigour and the mythical &amp;ldquo;completeness&amp;rdquo; in computer science.
If I last long enough in this line of work, perhaps I can help do
something about it.&lt;/p&gt;</description>
  </item>
  <item>
    <title>How much memory could an &lt;tt&gt;mmap()&lt;/tt&gt; map...</title>
    <pubDate>Tue, 22 Mar 2011 14:07:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/03/22#how-much-memory</link>
    <category>/devel</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/devel/how-much-memory</guid>
    <description>
&lt;p&gt;...if an &lt;tt&gt;mmap()&lt;/tt&gt; could map memory? I&apos;ve had to ask this
question of Linux on 64-bit x86 platforms recently.&lt;p&gt;

&lt;p&gt;For reasons I will only hint at, I want to allocate a huge region of
virtual address space for a structure a bit like a linear page table
(called a &amp;ldquo;virtualized page table&amp;rdquo; &lt;a
href=&quot;http://en.wikipedia.org/wiki/Page_table#Virtualized_page_table&quot;&gt;on
Wikipedia&lt;/a&gt;). We rely on a particular behaviour of Linux&apos;s
&lt;tt&gt;mmap()&lt;/tt&gt;: that mapping some memory isn&apos;t the same as
&lt;em&gt;committing&lt;/em&gt; to the availability of any underlying physical
memory. Passing the &lt;tt&gt;MAP_NORESERVE&lt;/tt&gt; flag means that memory will
only be allocated when written to, hence allowing us to create a sparse
table easily.&lt;/p&gt;

&lt;p&gt;I decided my table should have one word per 4KB of memory. For
a 32-bit machine, which has 4-byte words and 2&lt;sup&gt;20&lt;/sup&gt; such
(aligned) regions, this means I need 4MB of virtual address space
for my table (i.e. about a thousandth of the VAS). If we ask
&lt;tt&gt;mmap()&lt;/tt&gt; for such a region, it will clearly oblige us. On a
64-bit machine, which has 8-byte words and 2&lt;sup&gt;52&lt;/sup&gt; such
regions, I need 2&lt;sup&gt;55&lt;/sup&gt; bytes of virtual address space for
my table---32 petabytes, or about eight billion times as much as in
the 32-bit case, but again, only a small fraction of the total
address space (in this case a 512th, because words are twice as
big).&lt;/p&gt;

&lt;p&gt;Here&apos;s a quick program you can run to test whether you can do
an &lt;tt&gt;mmap()&lt;/tt&gt; of a given size.&lt;/p&gt;

&lt;pre&gt;
#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;errno.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;sys/mman.h&amp;gt;
#include &amp;lt;assert.h&amp;gt;

int main(int argc, char **argv)
{
    assert(argc &amp;gt; 1);
    size_t mapping_size = strtol(argv[1], NULL, 0);
    assert(errno != ERANGE);
    assert(mapping_size &amp;gt; 0);
    assert(sizeof(size_t) == 8);
        
    void *ret = mmap(NULL, mapping_size, PROT_READ|PROT_WRITE, 
        MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0);

    if (ret == MAP_FAILED)
    {
        fprintf(stderr, &quot;error: %s\n&quot;, strerror(errno));
        return 1;
    }
    else 
    {
        fprintf(stderr, &quot;success!\n&quot;);
        return 0;
    }
}
&lt;/pre&gt;

&lt;p&gt;And here&apos;s a shell script to drive it with powers of two until
it fails.&lt;/p&gt;

&lt;pre&gt;
#!/bin/bash

for exp in `seq 10 50`; do
    ./test $(( 2 ** &amp;#36;exp )) || break;
    echo &quot;Succeeded for 2 ^ &amp;#36;exp&quot;
done
&lt;/pre&gt;

&lt;p&gt;I&apos;d be curious to know whether anyone on an x86-64 Linux machine
maxes out anywhere different than 2&lt;sup&gt;46&lt;/sup&gt; bytes. The kernel
source will have the answer, but I can&apos;t be bothered wading through it
right now. Interestingly, turning off the overcommit check (i.e. writing
&quot;1&quot; to &lt;tt&gt;/proc/sys/vm/overcommit_memory&lt;/tt&gt;) doesn&apos;t increase the
limit for me.&lt;/p&gt;

&lt;p&gt;By the way, I&apos;m using &lt;tt&gt;strtol&lt;/tt&gt; because &lt;tt&gt;atol&lt;/tt&gt;
seemed to be narrowing the result to 32 bits even though a
&lt;tt&gt;long&lt;/tt&gt; is 64 bits. Instead of 2&lt;sup&gt;31&lt;/sup&gt; I got
-2&lt;sup&gt;31&lt;/sup&gt;, which unsurprisingly made &lt;tt&gt;mmap()&lt;/tt&gt; fail.
This seems like a bug, but probably isn&apos;t for some reason
(possibly including a stupid mistake by me).&lt;/p&gt;

&lt;p&gt;As you might have guessed, I&apos;m using this huge region of
memory as a big flat structure to record metadata about memory.
The main trick of a linear page table is that we can use virtual
memory to encode large sparse arrays, without allocating memory
for page-sized regions of the table that are empty. This
generalises to sparse tables other than page tables. The one I&apos;m
building is for tracking allocated heap regions.&lt;/p&gt;

&lt;p&gt;[Update, 2011-3-23: thanks to &lt;a
href=&quot;http://www.cl.cam.ac.uk/~mas90/&quot;&gt;Malcolm Scott&lt;/a&gt; who pointed out
that my problem might be more tractable, because current x86-64
processors only implement a 48-bit address space. This also means that
the 46-bit limit makes more sense---my &lt;tt&gt;mmap()&lt;/tt&gt; successfully
allocated a quarter of the usable virtual address space! Now I&apos;m
wondering: are those 48 bits something I can rely on for the nominal
x86-64 architecture, or will running the same binaries on future
hardware silently issue addresses from the larger 64-bit space? For now
it doesn&apos;t really matter, but send answers if you have them (on a
postcard, if you like) please.]&lt;/p&gt;</description>
  </item>
  <item>
    <title>Everything is a somehow-interpreted file</title>
    <pubDate>Thu, 17 Mar 2011 12:34:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/03/17#everything-is-a-somehow-interpreted-file</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/everything-is-a-somehow-interpreted-file</guid>
    <description>
&lt;p&gt;My last post was ranting about the difficulty of maintaining and
debugging configuration of complex software. I somewhat naively
advocated the position of using the filesystem to the greatest degree
possible: as the structuring medium as well as a container of data.
This is good because it maximises the range of existing familiar tools
that can be used to manage configuration. But at least in some cases,
the filesystem---as an implementation, although sometimes as an
interface too---is manifestly not good enough (e.g. in terms of
space-efficiency for small files). Instead, we want to make our old
tools capable of accessing, through the filesystem interface they
already know and love, these diverse and wonderful implementations of
structured data.&lt;/p&gt; 

&lt;p&gt;I have heard many researchers claim that binary encodings of data
are bad, that XML is good, or even that revision control systems are
bad ways of storing code, for the same recurring semi-reason that good
things are things that conventional tools work with---sometimes the
phrase &amp;ldquo;human-readable&amp;rdquo; crops up instead---and bad things
are things they don&apos;t work with. You can search XML or plain source
code using &lt;tt&gt;grep&lt;/tt&gt;, or so the reasoning goes; you can&apos;t generally
do the same for binary or diffed-text or otherwise munged encodings. 
This argument is classic tail-wagging-dog material. Plain text is only
&amp;ldquo;human-readable&amp;rdquo; because there is some widely deployed
software that knows how to decode binary data representing characters
(in ASCII or UTF-8 or some other popular encoding) into glyphs that can
be displayed graphically on a screen or on a terminal.  If other
encodings of data do not have this property, it&apos;s foremost a problem
with our software and not with the encoding.&lt;/p&gt;

&lt;p&gt;Unix is arguably to blame, as it is obsessed with byte-streams and
the &lt;a
href=&quot;http://en.wikipedia.org/wiki/Unix_philosophy#McIlroy%3a_A_Quarter_Century_of_Unix&quot;&gt;bizarre
claim&lt;/a&gt; that byte streams are &amp;ldquo;universal&amp;rdquo;.  The myriad
encodings that a byte-stream might model are less often mentioned. I&apos;d
argue that a major mistake of Unix is a failure to build in any
&lt;em&gt;descriptive&lt;/em&gt; channel in its model of communication and storage.
Without this, we&apos;re left with what I call the &amp;ldquo;&lt;tt&gt;zgrep&lt;/tt&gt;
problem&amp;rdquo;: each file encoding requires its own tool, and the
system offers no help in matching files with tools. If I have a mixture
of gzipped and uncompressed text files in a directory---like
&lt;tt&gt;/usr/share/doc&lt;/tt&gt; on any Debian system---recursively searching is
a pain because for some files we need a different &lt;tt&gt;grep&lt;/tt&gt; than
for others. Some approach combining analogues of  HTTP&apos;s
&lt;tt&gt;Content-Type&lt;/tt&gt; and &lt;tt&gt;Accept-Encoding&lt;/tt&gt; with &lt;tt&gt;make&lt;/tt&gt;&apos;s
inference of multi-hop file transformations, could allow the operating
system to transparently construct the correct input filters for
searching this mixture of files from a single toplevel instance of our
plain old &lt;tt&gt;grep&lt;/tt&gt; tool. &lt;/p&gt;

&lt;p&gt;For this to work we need an actually sane way of describing data
encodings. (Call them &amp;ldquo;file formats&amp;rdquo; if you will, although
I prefer the more generic term.) Later attempts at describing the
structure of byte-streams, notably file extensions or MIME types, have
been ill-conceived and half-baked, mainly because they are based on a
simplistic model where a file has &amp;ldquo;a type&amp;rdquo; and that&apos;s that.
So we get the bizarre outcome that running &lt;tt&gt;file&lt;/tt&gt; on
&lt;tt&gt;/dev/sda1&lt;/tt&gt; says &amp;ldquo;block special&amp;rdquo; whereas taking an
image of the same disk partition and running &lt;tt&gt;file&lt;/tt&gt; on that will
say something like &amp;ldquo;ext3 filesystem data&amp;rdquo;. Doing &lt;tt&gt;file
-s&lt;/tt&gt; might be the immediate workaround, but in reality, any given
filesystem object has many different &lt;em&gt;interpretations&lt;/em&gt;, any of
which may be useful in different contexts. A zip file, say, is a bunch
of bytes; it&apos;s also a directory structure; it might also be a software
package, or a photo album, or an album of music.&lt;/p&gt;

&lt;p&gt;Another interesting observation is that these encodings layer on top
of one another: describing a way of encoding an album of music as a
directory structure needn&apos;t target a &lt;em&gt;particular&lt;/em&gt; encoding of
that structure, but presumes &lt;em&gt;some&lt;/em&gt; encoding is used---any that
conceptually models the album encoding is sufficient. So we want to
capture them in a mixin-like form, and have some tool support for
deriving different compositions of them. What would be really neat is
if a tool like &lt;tt&gt;file&lt;/tt&gt;, instead of doing relatively dumb
inode-type and magic-number analyses, actually did a &lt;em&gt;search&lt;/em&gt;
for encodings that the file (or files, or directory) could satisfy.
Each encoding is a compositional construction, so the search is through
a potentially infinite domain---but one that can usually be pruned to
something small and finite by the constraints provided by the file
data. But by giving it more mixins to play with, as configuration data,
it could find more valid interpretations of our data. This sort of
discovery process would solve the &lt;tt&gt;zgrep&lt;/tt&gt; problem in far more
complex cases than the one I described. Implementing (and, er, somehow
evaluating) these ideas might make a nice student project at some
point.&lt;/p&gt;

&lt;p&gt;These ideas have been with me right from my earliest forays into
research-like work. I&apos;ve yet to really nail them though. My bachelor&apos;s
dissertation was about a filesystem exposing arbitrary in-memory data.
And my PhD work addressed some of the problems in making software
accessible through interfaces other than the ones it exposes as
written. I&apos;ve yet to do anything with persistent data or other IPC
channels so far, but it has been on the list for a long time. (It&apos;s
become clear with hindsight that this agenda is a characteristically
postmodern one: it&apos;s one of building tools and systems that provide
room for multiple interpretations of artifacts, that don&apos;t insist on a
grand and neatly-fitting system being constructed in one go, and that
accommodate incomplete, open or partially described artifacts.)&lt;/p&gt;

&lt;p&gt;The power-management problem that provoked my previous post actually
gets worse, because even when not on AC power, closing the lid only
&lt;em&gt;usually&lt;/em&gt; makes the laptop suspend. Sometimes it just stays on,
with the lid closed, until the battery runs down. For my next trick, I
may be forced to come up with some bug-finding approaches that apply to
scripts, filesystems and the like. If we&apos;re allowed to assert that a
file has a particular abstract structure, and check that separately,
then we can probably factor out large chunks of state space from real
software. In turn, that might shift our focus away from &amp;ldquo;inputs
of death&amp;rdquo;, fuzz-testing and other crash-focussed bug-finding
techniques, and towards the harder but more interesting ground of
finding &lt;em&gt;functionality bugs&lt;/em&gt;. I&apos;ll rant about that in a
forthcoming post.&lt;/p&gt;

&lt;p&gt;[Update, 2011-3-18: I just ran into an interesting example of this same debate, where Ted Ts&apos;o
is &lt;a href=&quot;https://bugs.edge.launchpad.net/ubuntu/+source/linux/+bug/317781/comments/45&quot;&gt;actively
advocating&lt;/a&gt; using a database in preference to maintaining lots of small files, for performance
and robustness reasons, in relation to ext4&apos;s semantic differences from ext3. Understandably, he
provokes a lot of discussion, notably &lt;a href=&quot;http://lwn.net/Articles/322823/&quot;&gt;here&lt;/a&gt;, where
people complain that binary files are difficult to maintain. There is a mix of views and a wide
variance of clue level, but the real issue is that no one interface---where &amp;ldquo;interface&amp;rdquo;
includes robustness and performance characteristics--- is the globally &amp;ldquo;right&amp;rdquo; one.]</description>
  </item>
  <item>
    <title>Config filesystems, not config files</title>
    <pubDate>Wed, 16 Mar 2011 19:36:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/03/16#config-filesystems</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/config-filesystems</guid>
    <description>
&lt;p&gt;Like most computer scientists, I really hate tinkering with computers.
Actually, that&apos;s not true. Like many computer scientists, I like
tinkering with computers in a constructive way that achieves
something interesting and novel (read: practical CS research). But I
hate tinkering that is provoked by &lt;em&gt;stuff not working&lt;/em&gt;. I use a
lot of software that has episodes of the latter kind---most of it is
free software (and, erm, arguably most free software is of that kind,
but that&apos;s another story).&lt;/p&gt;

&lt;p&gt;One recurring pain is that I learn how to configure software the way I
like it, but then all that hard-learnt knowledge is eroded by change:
change in what software is &amp;ldquo;current&amp;rdquo; or
&amp;ldquo;supported&amp;rdquo;, and also change in the way any given bit of
software manages its configuration. If you like, software&apos;s
&lt;em&gt;semantics&lt;/em&gt; often change, particularly at the configuration
level.&lt;/p&gt;

&lt;p&gt;So often, I&apos;m faced with a bunch of hassle just to keep my
configuration working the way I like it. Recent examples have included:
KDE 4 clobbering my X resources when it starts up (in a way that KDE 3
didn&apos;t); Xorg forcing me now to use &lt;a
href=&quot;http://www.x.org/wiki/Projects/XRandR&quot;&gt;xrandr&lt;/a&gt; to set up
multiple monitors; wireless networks now being preferentially handled
using &lt;a href=&quot;http://www.gnome.org/projects/NetworkManager/&quot;&gt;Network
Manager&lt;/a&gt; not &lt;a
href=&quot;http://packages.qa.debian.org/i/ifupdown.html&quot;&gt;ifupdown&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In dealing with this complexity, one recurring principle has been clear
to me. The closer a configuration system stays to the Unix filesystem
abstraction, and the less abstraction it tries to re-build on top of
the filesystem, the easier it is to deal with. This is because using a
direct filesystem encoding, I can use standard tools, from a shell, to
inspect and search and modify (and even generate) my configuration, and
to debug problems.  This is also why &lt;a
href=&quot;http://projects.gnome.org/gconf/&quot;&gt;gconf&lt;/a&gt; sucks, just as the
Windows registry sucks: they represent hierarchical data using a custom
encoding layered on flat files, rather than embracing the hierarchy
already given to them by the filesystem. (This approach is even less
excusable on Unix than on Windows, because Unix filesystems are
somewhat optimised for small files in a way that Windows-land
filesystems traditionally weren&apos;t, as exemplified by FAT.)&lt;/p&gt;

&lt;p&gt;In some quarters there&apos;s been a drive to actively embrace the filesystem
as a means of capturing the structure of configuration data.
Configuration directories (like &lt;a
href=&quot;http://www.x.org/wiki/Server18Branch&quot;&gt;&lt;tt&gt;xorg.conf.d&lt;/tt&gt;&lt;/a&gt;)
are one example, although it has now gone away; symlink structures like
the traditional &lt;a
href=&quot;http://en.wikipedia.org/wiki/Init#SysV-style&quot;&gt;System V init&lt;/a&gt;
runlevel directories are another; the &lt;a
href=&quot;http://man.cx/run-parts(8)&quot;&gt;&lt;tt&gt;run-parts&lt;/tt&gt;&lt;/a&gt; idea of
directories encoding control structures is a third. Configuration is
easy to understand and modify when it&apos;s laid out transparently in the
filesystem. When it&apos;s instead recorded as opaque data in random files
somewhere, this is not true.&lt;/p&gt;

&lt;p&gt;Unfortunately this drive towards transparency is not universal.
Today I&apos;ve been debugging a configuration issue with power management
on the recent Ubuntu. When I close my laptop lid with no AC power, it
suspends to RAM. When I close the lid on AC power, it doesn&apos;t---but I
want it to. I had assumed the matter was under the control of the
scripts in &lt;tt&gt;/etc/acpi/&lt;/tt&gt;, but a quick inspection of the
&lt;tt&gt;lid.sh&lt;/tt&gt; script revealed that it didn&apos;t deal with suspending to
RAM at all. It turns out that KDE 4 has something called
&amp;ldquo;PowerDevil&amp;rdquo; and that this is responsible. I can configure
it using KDE&apos;s graphical &lt;tt&gt;systemsettings&lt;/tt&gt; application. But this
whole set-up is unsatisfactory. How does it interact with other system
settings, such as the &lt;tt&gt;/etc/acpi/&lt;/tt&gt; scripts? Why is a
KDE-specific tool replicating the functionality that is already
provided at a lower level? And now I have one more chunk of
configuration to deal with, at one more path in the filesystem, and one
more model of the settings domain to understand---squirreled away
inside its own configuration file (mercifully in plain-text
format).&lt;/p&gt;

&lt;p&gt;Now, the researcher will say that there&apos;s a problem here: why should
a simple need, such as the gconf-like desire to implement a familiar
abstraction (or something close to it) with different performance
characteristics, bring such a huge cost in terms of tool support,
convenience and integration cost? It&apos;s not really an answer, as I have
proposed, to &amp;ldquo;just use the filesystem, stupid&amp;rdquo;. For the
same reason, even filesystem-embracing approaches don&apos;t go so far as to
have one file per setting, say---there is some amount of
filesystem-opaque flat structure. I&apos;ll save some comments on this
for a (near)-future post.&lt;/p&gt;</description>
  </item>
  <item>
    <title>Writing a Part II dissertation</title>
    <pubDate>Mon, 14 Mar 2011 17:15:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/03/14#part-2-dissertations</link>
    <category>/teaching</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/teaching/part-2-dissertations</guid>
    <description>
&lt;p&gt;Not that long after I did Part II of the &lt;a href=&quot;http://www.cl.cam.ac.uk/teaching/#tripos&quot;&gt;Tripos&lt;/a&gt; in Cambridge, 
I &lt;a href=&quot;http://www.inf.usi.ch/postdoc/kells/blog/2006/10/02#projects&quot;&gt;wrote&lt;/a&gt; a piece about how to do a successful Part
II project, based on bitter experience of having done a less-than-completely successful one. Now
it&apos;s a few years later, and I&apos;ve supervised four Part II dissertations and proof-read a couple more (and now left Cambridge!).
I thought I&apos;d write down some hints about what makes a good dissertation. As before,
the &lt;a href=&quot;http://www.cl.cam.ac.uk/teaching/projects/pinkbook&quot;&gt;pink book&lt;/a&gt; is well-meaning but misses a lot of this.&lt;/p&gt;

&lt;p&gt;I should also add that this advice is not prescriptive---it&apos;s a mixture of my personal preferences
as a reader of dissertations,
and a conservative underapproximation of &amp;ldquo;known ways to write a good dissertation&amp;rdquo;
according to my experience. Not
being part of the examination process myself, I can&apos;t say it&apos;s the only way, nor that it&apos;s sufficient,
nor even that it&apos;s always correct---only that these recommendations seem to have some correlation with good marks.&lt;/p&gt;

&lt;h4&gt;Introduction&lt;/h4&gt;

&lt;p&gt;This chapter is for you to identify the problem space of the work, and what specifically your work
seeks to achieve in that space. You should outline the technical background of the work here, but
only at a high level---save details for next section. The emphasis should be on context: motivating
use-cases, and covering a selection of differing alternative approaches to the problem. Once you&apos;ve
covered that, you can give a specific taster of the one you adopted---probably in the form of 
a simplified summary, perhaps a preview-style example or two (of the work you did and its supported use-cases)
and an outline of the rest of the dissertation.&lt;/p&gt;

&lt;h4&gt;Preparation&lt;/h4&gt;

&lt;p&gt;This chapter should consist mostly of technical background, at a level deeper than the introduction.
Think of it as mirroring the preparatory reading (and perhaps experimentation) you had to do before
beginning the project work proper. You should describe the specification of the system you built, outline its
overall design, and mention any changes to proposal. It&apos;s particularly worth emphasising anything
hard that you had to learn in order to undertake the project---such as unfamiliar tools, languages,
libraries, programming styles, algorithms, bits of mathematics, and so on.&lt;/p&gt;

&lt;p&gt;For pitching your work, my rule of thumb is to assume your reader knows basic computer science (say,
an outline understanding of the first two years&apos; Tripos content) but is a bit slow to catch on. In
other words, try to make the reasoning in your write-up extremely clear and easy to follow. This is
not because the examiners &lt;em&gt;are&lt;/em&gt; slow to catch on. Rather, it&apos;s because they are probably in a hurry,
and in order to counterbalance the fact that you&apos;re almost certain to underestimate the difficulty of understanding your own write-up.&lt;/p&gt; 

&lt;p&gt;Avoid
assuming that the reader knows 
any &lt;em&gt;particular&lt;/em&gt; language, tool or detailed technique that you use.
For example, if your work is based on implementing some particular programming language, you can assume the
reader has basic degree-level knowledge about programming languages in general, but you should use this
chapter to give an outline introduction to this specific language and its peculiarities, with
references to additional material.&lt;/p&gt;

&lt;p&gt;This chapter is somewhat infamous for requiring that you write some &amp;ldquo;boring&amp;rdquo; stuff about
development practices: what tools you used, your testing strategy, how you took backups, what
development practices you followed, and so on. I say &amp;ldquo;infamous&amp;rdquo; because we researchers,
when we are proof-reading dissertations, find this all a bit incongruous---most of a dissertation reads a
bit like a research write-up, whereas this stuff doesn&apos;t. Since we&apos;re not accustomed to seeing this kind of thing written down,
it thuds a bit. 
However, it&apos;s the researcher&apos;s perspective that&apos;s at fault here. Most dissertation authors are about to go off into
industry, and from the perspective of professional software development, including this small amount of
practice- and process-oriented content is a very reasonable requirement.&lt;/p&gt;


&lt;h4&gt;Implementation&lt;/h4&gt;

&lt;p&gt;To a first approximation, this chapter should be describing the clever data structures and
algorithms that appeared in your project. Think &amp;ldquo;meaty&amp;rdquo;---a really good Implementation
chapter will come across as chock-full of interesting, nontrivial technical material, &lt;em&gt;clearly described&lt;/em&gt; and comprehensible. It should also
have reasoned discussion of how your techniques work and why they are well-suited to the
problem.&lt;/p&gt;

&lt;p&gt;When explaining how your system works, there is a question of what level of explanation is appropriate, and
how much detail you should go into. I&apos;d advise that you completely avoid descending to syntactic
code-level details (e.g. names of particular classes and methods). There could be an exception if
some class or method was so conceptually significant and pervasive that mentioning it by name is the
clearest presentation, but this is relatively rare. Think of this chapter as providing descriptions
sufficient for a reader to go away and reimplement your system algorithm-for-algorithm, but not
identifier-for-identifier. Including a UML class diagram, or similar, is okay---particularly when it&apos;s showing something
interesting!---but I&apos;d advise against going any deeper than that.&lt;/p&gt;

&lt;p&gt;Instead of code-level detail, explain your implementation using pseudocode, data-structure diagrams,
flow-charts, time-sequence diagrams, and the like. A good project will have meat here that is
outside the syllabus, or at least drawn from the more specialised end of Part II courses, so you
should make these especially clear and assume your reader is unfamiliar.&lt;/p&gt;


&lt;p&gt;You may well have used some third-party software as part of your system. You should explain how it
fits in. Moreover, it&apos;s okay (and generally good) to include a summary of how it works, even
though you didn&apos;t write it. This is to show that you could have implemented it yourself if you&apos;d had
to, but that there was no good reason to!&lt;/p&gt;

&lt;p&gt;I would personally avoid talking about evaluation harnesses, methods or support coding here. That
is best saved for the Evaluation chapter.&lt;/p&gt;

&lt;p&gt;Look at existing technical writing, perhaps research papers in reading lists of your lecture
courses, for more ideas about how to present technical content clearly and at the right level.&lt;/p&gt;

&lt;h4&gt;Evaluation&lt;/h4&gt;

&lt;p&gt;Couch your evaluation in terms of claims that your work supports, or goals that you claim your work
has fulfilled.  The chapter then becomes an exercise in substantiating these claims.&lt;/p&gt;

&lt;p&gt;Explain your method of evaluation. This requires answering at least three questions. What data are you collecting?
How will you be interpreting it? Finally, how are your claims decided by this interpretation of your
data? That final question is the trickiest to get right---usually it involves an argument that the
interpretation of the data soundly represents the abstract truth of the claim in some way. (However, you don&apos;t need
to belabour the point on that last issue---as long as your approach is not completely off-the-wall, it&apos;s generally enough
to show that show that you&apos;ve thought about the validity of your evaluation method and that it&apos;s not
obviously fatally flawed.)&lt;/p&gt;

&lt;p&gt;There should be results, or data. Since these will hopefully be quantitative, they are usually
presented as tables and/or graphs. Pay attention to precise presentation of results: units,
appropriate precision, error bars, discrete vs continuous graph conventions, etc.. For each piece of
evidence you present, say why you&apos;re interested in it (first!) and (then) what it shows and your
confidence in that.&lt;/p&gt;

&lt;p&gt;Present results so that they can be reproduced. So if you give program execution times, say what
the machine you were running on was. If you can abstract this to something of more robust meaning
than numbers relevant only to your particular experimental rig, then do so, although unless the
mapping is absolutely trivial, include the raw data too. One example: if you measure execution
times of some low-level code in CPU microseconds, say, then it might be worth abstracting that to
CPU cycles if you have the relevant data---but keep the original measurement in there too. More
importantly, explain what you are doing! One of the easiest ways to write a bad Evaluation chapter
about good work is not to explain the origin or significance of the numbers or graphs you&apos;re
presenting.&lt;/p&gt;

&lt;p&gt;Have something to compare your system against. If this really doesn&apos;t seem feasible, you can
sometimes get around this by defining your own goals up-front (e.g. &amp;ldquo;at least 70% precision...&amp;rdquo;---
including some argued justification for the number!), then showing that you satisfy them. In
this case, the goal should be mentioned in the Introduction or Preparation sections. It is
nevertheless nicer to show that your system does better than some other system or approach, even if
it&apos;s a somewhat naive or trivial one. For example, comparing a query-routing algorithm against a
random algorithm is better than no comparison at all.&lt;/p&gt;

&lt;h4&gt;Conclusions&lt;/h4&gt;

&lt;p&gt;Say what you did, in summary. It&apos;s okay to repeat yourself from earlier sections. Also, take the
opportunity to talk about future work: what you learned, what could be done better, how your system
could be extended to do new and wonderful things, or what better ideas you&apos;ve had since about how to
tackle your chosen problem and its close relatives.&lt;/p&gt;

&lt;h4&gt;Bibliography&lt;/h4&gt;

&lt;p&gt;The bibliography should consist of references to &lt;em&gt;archival&lt;/em&gt; material. There are some things you&apos;ll
want to &amp;ldquo;reference&amp;rdquo; that are not archival material. For example, you will want to
reference software packages you&apos;ve used. I personally avoid
trying to &amp;ldquo;cite&amp;rdquo; these in the bibliography, for example, although
some authors do this. So that point, and much of the following, is mostly personal advice. &lt;/p&gt;

&lt;p&gt;Since URLs are not (under current web technology) stable enough for archival use, avoid URLs except as a
last resort, when they&apos;re the only way of identifying a published document.   Unlike paper
publications, web pages are living documents, so if you use a URL, include the date on which you
looked at the content (e.g. &amp;ldquo;retrieved on 2010-07-30&amp;rdquo;) so that a reader can (hopefully) use &lt;a href=&quot;http://www.archive.org/&quot;&gt;an archiving
search engine&lt;/a&gt; to see the precise page that you saw.&lt;/p&gt;

&lt;p&gt;I prefer to use footnotes for referencing software by URL. (But generally use footnotes sparingly---only for
places where they&apos;d really interrupt the main flow of text, but are nevertheless relevant and
interesting.)&lt;/p&gt;

&lt;p&gt;This is &lt;em&gt;very&lt;/em&gt; personal advice, but I&apos;d say: in the main text, avoid using citation markers as nouns.  A lot of writers do this, but I find it
jarringly bad style. Instead, use the author&apos;s name. For example, don&apos;t write &amp;ldquo;as shown by
[42]&amp;rdquo;, but instead write &amp;ldquo;as shown by Smith et al [42]&amp;rdquo;. If you&apos;re using
author--year citation markers (which I generally prefer to plain numbers), there are usually
different citation styles you can use to avoid repeating the author&apos;s name, for example &amp;ldquo;as
shown by Smith et al [1990]&amp;rdquo; is preferable to &amp;ldquo;as shown by Smith et al [Smith
1990]&amp;rdquo;.&lt;/p&gt;

&lt;h4&gt;Style&lt;/h4&gt;

&lt;p&gt;Following are a few other pieces of advice on style that I&apos;ve had cause to dispense on the past.&lt;/p&gt;

&lt;p&gt;Don&apos;t feel the need to tell a complete, linear story. 
It&apos;s very tempting to write what you did as a narrative. However,
this usually has two problems.
Firstly, by emphasising the &lt;em&gt;what&lt;/em&gt;, it&apos;s easy to understate the &lt;em&gt;why&lt;/em&gt;, which can
make the reader baffled by a succession of sentences saying &amp;ldquo;I did this, then I did this, then I did
this...&amp;rdquo; but without much insight about the overall goal or the motivation behind each step.
Secondly, some of the twists and turns that you took are probably not interesting at all---no matter
how much of a struggle they were for you at the time---so can be left out. So, instead of a narrative,
try to write instead in what I call a &amp;ldquo;progressive encoding&amp;rdquo; or &amp;ldquo;iterative deepening&amp;rdquo; style.
Think about the most significant high-level points you want to make. As a rule of thumb, 
each of these should be stated concisely at the beginning of its own paragraph. The rest of the paragraph can fill in additional detail and back-story 
in successive sentences. This results in a structure where the fact and the explanation occur close together. Curiously, they usually turn up in reverse order (fact first, then explanation) and this is still very readable. 
It&apos;s a very common style in good scientific writing. It has the rhetorical benefit that
you keep the reader interested. Making a contentious or surprising statement, 
then delving progressively deeper into a justification of it, is a trick that can keep the reader engaged
when used judiciously.&lt;/p&gt;

&lt;p&gt;As an example, instead of saying &amp;ldquo;I
tried running the JVM with the default options, but this suffered from out-of-memory errors, so ran
with an increased heap size of 384MB&amp;ldquo;, say &amp;ldquo;the JVM was configured with the larger heap
size of 384MB. The smaller default heap size was discovered to be insufficient when constructing
the intermediate representation for larger input files.&amp;rdquo;
Again, you can hoist more significant facts sooner, and leave more peripheral matters
until later in the paragraph. Note that there will still be a temporal progression to some extent, particularly between paragraphs. Note also
that by this approach you will naturally end up leaving out the redundant twists and turns that are not interesting. If you think
something interesting has been left out unfairly by this structuring, you can always put it in a paragraph towards the end of a section or chapter, 
clearly signposted as a curiosity rather than part of the main flow.
(Sometimes, a paragraph will end with a bracketed note like this one, to further
outline the distinction between more- and less-important content.)&lt;/p&gt;

&lt;p&gt;Avoid editorialising, by which I mean expressing opinions (e.g. about particular designs,
technologies, approaches, companies, products etc.) that you don&apos;t intend to scientifically
validate. &lt;/p&gt;

&lt;p&gt;Underneath any heading in the dissertation, it&apos;s good style to include at least a summary sentence
before descending down a level of heading structure (e.g. between heading and subheading). &lt;/p&gt;

&lt;p&gt;Finally, keep your writing grammatical. Every sentence should contain a verb!&lt;/p&gt;

&lt;p&gt;That&apos;s all I have to offer---please do &lt;a href=&quot;http://www.inf.usi.ch/postdoc/kells/#contact&quot;&gt;let me know&lt;/a&gt; any suggestions,
queries, corrections, counterexamples or contrary experience you may have about anything in this post.&lt;/p&gt;

&lt;p&gt;[Update, 2011-10-13: Andrew Moore supplies &lt;a
href=&quot;http://www.cl.cam.ac.uk/~awm22/notes/2011-part2-dissertations-notes.pdf&quot;&gt;this very helpful set
of notes&lt;/a&gt; from his duties as examiner in 2011!]&lt;/p&gt;</description>
  </item>
  <item>
    <title>Program specialization (is not just partial evaluation)</title>
    <pubDate>Wed, 09 Mar 2011 19:58:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/03/09#program-specialization</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/program-specialization</guid>
    <description>
&lt;p&gt;I&apos;ve been thinking a lot about various techniques in program analysis,
transformation and verification recently. There&apos;s certainly a lot to
think about.&lt;/p&gt;

&lt;p&gt;One idea I&apos;m exploring is looking at verification problems as program
specialization exercises. There is a recurring two-stage process in
verification. First, transform your program so that a single execution
captures &lt;em&gt;all&lt;/em&gt; possible inputs. For an explicit-state model
checker like &lt;a
href=&quot;http://www.usenix.org/event/osdi02/tech/full_papers/musuvathi/musuvathi_html/index.html&quot;&gt;CMC&lt;/a&gt;,
we do this by putting our program in a harness that systematically
explores its state space. Alternatively, for approaches based on
predicate abstraction, we replace all input-dependent transitions in the
program with nondeterministic choice. The effect is the same: we now
have one program encoding all possible behaviours. The second step is
then to specialize our program for answering the question we care about,
such as &amp;ldquo;does this assertion ever fail?&amp;rdquo;. We rely on this
specialization to give us a new, simpler, faster program that we can
exhaustively check, or can check to greater depth, without exhausting
resources (time or memory).&lt;/p&gt;

&lt;p&gt;It&apos;s the specialization step I&apos;m thinking about right now. How much of
our program&apos;s computation can we throw away, while still computing the
answer to our question? CEGAR approaches work from the bottom up: we
start from a trivial abstraction and refine it compute something close
to the smallest program which finds either an absence of bugs or at
least one non-spurious bug. This process need not terminate; I&apos;m not yet
clear on its other failure modes, but am fairly sure there are some.
Meanwhile, a top-down approach also exists. CMC is a useful tool even
though it doesn&apos;t do &lt;em&gt;any&lt;/em&gt; specialization of the computation per
se. (It does support some other kinds of abstraction for reducing the
state space by defining equivalences, which have a similar effect but
are of limited applicability.) To improve on this, we could exploit the
fact that throwing away unwanted computation is something we know
something about. Compilers have been doing this since compilers began.
&amp;ldquo;Program specialization&amp;rdquo; is a term used mainly by
compiler-minded people rather than verification people. Can we apply
ideas from one world to the other?&lt;/p&gt;

&lt;p&gt;&amp;ldquo;Program specialization&amp;rdquo; in the literature is often used to
mean partial evaluation. With partial evaluation, we take a program of
&lt;i&gt;n&lt;/i&gt; inputs, say, and then produce a smaller, simpler, faster
version where some of these inputs are replaced by fixed values. This is
typical of optimisation problems, where &amp;ldquo;faster&amp;rdquo; is the key
requirement, and the input constraints have usually been derived from
some other analysis. However, there is a converse case of program
specialization which the same literature often ignores. This is where we
take a program of &lt;i&gt;n&lt;/i&gt; &lt;em&gt;outputs&lt;/em&gt;, and then produce a smaller,
simpler, faster version where we &amp;ldquo;don&apos;t care&amp;rdquo; about some of
these &lt;em&gt;outputs&lt;/em&gt;. This is typical of verification problems, where
&amp;ldquo;simpler&amp;rdquo; is the key requirement, and the selection of
don&apos;t-care outputs is a consequence of the specification being
considered.&lt;/p&gt;

&lt;p&gt;Predicate abstraction is doing this, but with some added room for
manoeuvre---since it&apos;s open to finding sound approximations rather than
precise specializations---and also with some added constraints, since
it&apos;s interested in predicates that can be input to a SAT or SMT solver
to perform the abstraction-refinement. Dave provided a valuable link in
a productive coffee break this morning, by noting that program slicing
is also an instance of specializing for don&apos;t-care outputs. What happens
if we use slicing techniques to do a top-down specialization? I&apos;m
worried the answer is &amp;ldquo;not enough&amp;rdquo; or &amp;ldquo;strictly worse
than abstraction-refinement&amp;rdquo;, but I&apos;ll keep thinking about it.&lt;/p&gt;</description>
  </item>
  <item>
    <title>Greek talk</title>
    <pubDate>Wed, 09 Mar 2011 19:57:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/03/09#greek-talk</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/greek-talk</guid>
    <description>
&lt;p&gt;One of the reasons why I&apos;m not a theoretical computer scientist is that
I am very, very averse to mathematical notation. &amp;ldquo;It&apos;s like Greek
to me!&amp;rdquo;---no applause, please. Certainly, it&apos;s common to see  very
highly abbreviated notation that takes some serious cognitive
gear-turning to decode. If I&apos;m faced with a Greek-heavy paper, I usually
skim over the symbolic stuff and look for an explanation in words.
Sometimes it&apos;s there, and sometimes it isn&apos;t. In the cases where it&apos;s
not, I rarely have the stamina to wade through the Greek.&lt;/p&gt;

&lt;p&gt;Natural language, for all its imprecision, is---unsurprisingly---more
&amp;ldquo;natural&amp;rdquo;! In fact, I&apos;ll wager that most of the infamous
imprecision found in natural language specifications could be fixed by
more precise natural language. Perhaps a semantic checker for English is
in order. Diagrams are even better than natural language, of course,
although they rarely stand alone.&lt;/p&gt; 

&lt;p&gt;It strikes me that formalism is primarily useful for avoiding mistakes.
By turning complex reasoning into simple pattern-recognition and
symbol-pushing, correctness can be checked fairly dumbly. The cost is
that although it&apos;s hard to make mistakes, it&apos;s hard to make progress:
there are reams of applicable rules, and expressing anything complex
requires a whole lot of symbols. So I&apos;m going to go out on a limb and
claim that formalism is notably not very good for acquiring
understanding. In a lecture, diagrams and examples and words have always
been far more useful to me than slides full of Greek. I&apos;m also going to
assert (without proof!) that formalism is not useful for artifact
construction, except where mistake-avoidance is paramount. We should
allow programmers to make imprecise statements, and refine them later,
because humans can be a lot more productive this way. In particular, we
can make progress before we fully understand the problem! Only when the
cost of the smallest mistake is so great that we really want to rein
things in should we resort to fully rigorous constructive methods (such
as formal refinement processes, the B method, etc.). This argument also
encompasses many of the usual arguments in favour of dynamic languages
over statically typed ones.&lt;/p&gt;

&lt;p&gt;Of course, that doesn&apos;t mean that any formal notation is to be
avoided. For whatever quirk of evolution, humans have some aptitude for
written language---and that includes more mathematical-style symbolic
notations just as well as plain old words made of letters. So
mathematical notation is fine if it stays within a particular comfort
zone. I can read basic logic and basic algebra without much cognitive
burden. Only when the formal notation passes a certain density threshold
do I suddenly hit problems. I suspect that most theoretical computer
scientists (and mathematicians) have a much higher threshold than I
do.&lt;/p&gt;</description>
  </item>
  <item>
    <title>The end-to-end razor</title>
    <pubDate>Thu, 03 Mar 2011 12:43:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/03/03#end-to-end-razor</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/end-to-end-razor</guid>
    <description>
&lt;p&gt;Most of us have heard of Occam&apos;s razor. Usually it is invoked as the principle that given two
plausible theories, explanations or solutions to a problem, we should prefer to believe the simpler
one.&lt;/p&gt;

&lt;p&gt;I&apos;ve always been a fan of &amp;ldquo;Einstein&apos;s razor&amp;rdquo;, which paraphrases a longer quotation
of Einstein by the snappy dictum &amp;ldquo;Everything should be made as simple as possible, but no
simpler.&amp;rdquo;. The appeal is in its counterbalancing: there is value in simplicity, but there is
harm in oversimplification.&lt;/p&gt;

&lt;p&gt;A third razor-like object occurs more often in system design. Most practical CS researchers will
have read the &lt;a
href=&quot;http://web.mit.edu/Saltzer/www/publications/endtoend/endtoend.pdf&quot;&gt;&amp;ldquo;End-to-end
arguments&amp;rdquo; paper&lt;/a&gt;. Usually, the end-to-end arguments are dumbly invoked to criticise any
design which pushes a feature into the lower layers of a complex system (notably the Internet) when
it could be implemented higher up. This interpretation is unfortunate. For one, it overlooks at
least two subtleties expounded in the original paper: that a key criterion is whether the feature
can be implemented &lt;em&gt;completely and correctly&lt;/em&gt; at the lower layer, and also whether doing so
brings any compulsory overheads (detrimental to applications not requiring the feature). But more
importantly, it omits a vital counterbalancing concern: by implementing features higher up, we
nearly always end up with not one but many variants of the same feature. Agreeing on which one to
use is a hopeless problem of distributed (human) consensus, so we end up with a huge mess of
interoperability problems brought on by this unnecessary diversity. So in fact, there are very real
incentives for implementing functionality at the &lt;em&gt;lowest&lt;/em&gt; sensible layer. The traditional
end-to-end arguments don&apos;t bring these incentives out.&lt;/p&gt;

&lt;p&gt;In fact we should have been paying more attention to Occam all along, because his original
statement that &lt;em&gt;entia non sunt multiplicanda praeter necessitatem&lt;/em&gt;---&amp;ldquo;entities must
not be multiplied beyond necessity&amp;rdquo;---is extremely suggestive of the cost of unnecessary
diversity. Combining this razor and Einstein&apos;s, I prefer a different formulation of the end-to-end
arguments, which I hereby name the &amp;ldquo;end-to-end-razor&amp;rdquo; (with apologies to anyone who&apos;s
used that name previously to mean something else). &amp;ldquo;Everything should be implemented at the
lowest sensible layer, but no lower.&amp;rdquo; You can argue about what&apos;s &amp;ldquo;sensible&amp;rdquo;, but
the criteria are the same as in the original end-to-end arguments. The difference is that the
counterbalancing of considerations is explicit: there may be both value and harm in building at
lower levels.&lt;/p&gt;

&lt;p&gt;Personally, as a programming researcher, I relish the challenge of working at lower levels.
Solving a general problem by building a system which is tied to one programming language, for
example, seems unsatisfying to me. Not only did the decision to make &lt;a
href=&quot;http://www.inf.usi.ch/postdoc/kells/research/cake/&quot;&gt;Cake&lt;/a&gt; target object code mean that it provides a somwhat
language-independent solution to its problem, but, for me at least, it was just a lot more fun
hacking around the OS, linker and C library than it would have been tinkering with a JVM or munging
source code. I&apos;m not entirely sure why....&lt;/p&gt;</description>
  </item>
  <item>
    <title>Why I am not (yet) a functional programming enthusiast -- part 1</title>
    <pubDate>Mon, 28 Feb 2011 13:14:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/02/28#functional-programming-not-yet-part-1</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/functional-programming-not-yet-part-1</guid>
    <description>
&lt;p&gt;I suffer from a particular disposition which, for a programming languages researcher is quite an unfortunate one. 
When I hear my fellow researchers expounding the virtues of functional programming, I start to feel grumbly. Functional programming &lt;em&gt;is&lt;/em&gt; really
neat in a lot of ways. But there are some in which I find it unpalatable. Here is my first selection of complaints. They are mostly
to do with the generally poor comprehensibility of functional code. I have more complaints in reserve,
which will follow in due course when I&apos;m feeling sufficiently grumpy.&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;&lt;strong&gt;Short identifiers make for incomprehensible code.&lt;/strong&gt; Functional code is often &amp;ldquo;concise&amp;rdquo; in part because
the prevalent style is to use ultra-short identifiers everywhere. This stands in stark contrast with Java, where a common style is
to make identifiers patronisingly verbose. The latter might make for swampy code, but the former is a great way of making code incomprehensible.
Even worse is the &amp;ldquo;primed&amp;rdquo; identifier idiom in Haskell. This is a nice way of saying &amp;ldquo;we have &lt;tt&gt;x&lt;/tt&gt;,
and then we have &lt;tt&gt;x&apos;&lt;/tt&gt; which is somehow like &lt;tt&gt;x&lt;/tt&gt; but somehow &lt;em&gt;not&lt;/em&gt; like &lt;tt&gt;x&lt;/tt&gt;, in a way that its name
completely fails to elucidate&amp;rdquo;.&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Currying is counterproductive.&lt;/strong&gt; It&apos;s neat that we can specialise functions by partially applying them. But we can
do that with lambda expressions. 
We don&apos;t need to turn all instances of multi-argument functional abstraction into the horrible multiply-indirect mess that is currying.
Currying is mathematically nice, but doesn&apos;t help the human programmer. The idea of a function from arguments to a result is fairly
easy to understand. The idea of a function from argument to function from argument to function from argument to result is not. 
In fact, lambda expressions are a strictly better solution to
partial application, because we don&apos;t rely on arguments occurring in any particular order. By contrast,
if I have &lt;tt&gt;f&amp;nbsp;x&amp;nbsp;y&amp;nbsp;z&amp;nbsp;=&amp;nbsp;...&lt;/tt&gt;, and I want to exploit the curried nature of this function
to do partial application, the first move has to specialise for &lt;tt&gt;x&lt;/tt&gt;, and only then &lt;tt&gt;y&lt;/tt&gt;, etc..&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Function application needs more signposts.&lt;/strong&gt; Too much functional code consists of 
an incomprehensible string of bracketless function applications, 
with the occasional dot operator just to confuse things. Of course there&apos;s
nothing to stop you writing brackets, but, if you&apos;ll allow me to by cynical for a moment, since most of the satisfaction gained by functional programming
is gained from being &amp;ldquo;clever&amp;rdquo; (there&apos;s some famous &lt;a href=&quot;http://en.wikiquote.org/wiki/Brian_Kernighan&quot;&gt;wisdom&lt;/a&gt; about the dangers of that),
it seems that functional programmers rarely do this.&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Bogus analogies with mathematics, #1:&lt;/strong&gt; advocates like to justify the &amp;ldquo;no brackets for function application&amp;rdquo; style 
by analogy with the role of multiplication in algebra.
We don&apos;t write an operator symbol for multiplication because it&apos;s (arguably) the &amp;ldquo;common case&amp;rdquo;. 
So, the analogy goes, we don&apos;t write anything for function application. This is nonsense. 
The more significant reason we don&apos;t write a symbol for multiplication is that it&apos;s a cognitively simple operation: 
for real numbers it is commutative, associative, and crucially,
operates within a closed domain. This means it is simple to reason about what it does,
so can be compressed notationally without making the result incomprehensible.
Function application has none of these properties: in general, it is not associative or commutative,
and relates values across distinct domains. Complex function compositions are already intrinsically hard to understand;
making them unreadable adds a ton of unnecessary incidental complexity on top. 
Tellingly, note that in cases from mathematics where a multiplication operator does &lt;em&gt;not&lt;/em&gt;
have the nice properties, such as matrix or vector algebra,
it is more common for mathematicians to write the operator explicitly, and to use more parentheses.
Perhaps they still don&apos;t use very many, but in any case,
as I&apos;ll argue in future rants, it&apos;s false (and groundless) to suppose that programming should emulate mathematics.
&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;I concede that these are all elements of style, not language features per se. It&apos;s possible to write clean
functional code which doesn&apos;t suffer from any of the problems I&apos;ve mentioned. This hints at the fact
that part of my problem is the culture among functional programmers, rather than the technology itself.
That&apos;s still a showstopper though, because in practice we are reliant on other programmers. Without other
programmers&apos; having written tools and libraries that relieve us from writing everything from scratch, and documentation
to explain them to us, then no programming language is of practical use. Accordingly, 
I&apos;ll be back later with a more concrete example
where this went wrong for me in an earlier foray into functional programming.&lt;/p&gt;</description>
  </item>
  <item>
    <title>Explaining covariance and contravariance by data flow</title>
    <pubDate>Tue, 22 Feb 2011 14:12:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2011/02/22#explanation-of-wildcard-types</link>
    <category>/teaching</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/teaching/explanation-of-wildcard-types</guid>
    <description>
&lt;p&gt;A few years ago
when I was pressed by my students
to give them a good explanation of Java&apos;s wildcard types,
like &lt;tt&gt;Stack&amp;lt;? super Circle&amp;gt;&lt;/tt&gt;
or &lt;tt&gt;List&amp;lt;? extends Ellipse&amp;gt;&lt;/tt&gt;,
I came up with a simple code example
concerning the direction of data flow. The idea seems both to be more
general than I first thought, and to apply to more wide-ranging
problems with subtyping relations than the case of Java wildcards. Since I&apos;ve never
seen it written down anywhere else, here it is.&lt;/p&gt;

&lt;p&gt;In a nutshell, the idea is that &lt;em&gt;direction of data flow&lt;/em&gt; is key.
(If that was obvious to you already, you can probably stop reading now!)  
In object-oriented programming, all interactions across object interfaces
can be seen as sending messages. In a procedural language like Java, each
interaction will in general involve &lt;em&gt;two&lt;/em&gt; messages---the call and the
return value. In a parametrically polymorphic type system
like modern Java&apos;s, one of the key roles of the type system is to check 
(conservatively, as always) that any invocation will not try to send the
wrong kind of data, in either direction.&lt;/p&gt;

&lt;p&gt;Suppose I have some code that works by pulling objects out of a queue. 
To work correctly, these objects have to be of class &lt;tt&gt;Circle&lt;/tt&gt;
&lt;em&gt;or some subclass&lt;/em&gt; thereof. So, we need a queue whose designated element
type is &lt;tt&gt;Circle&lt;/tt&gt; &lt;em&gt;or&lt;/em&gt; some subtype of &lt;tt&gt;Circle&lt;/tt&gt;, 
i.e. &lt;tt&gt;? extends Circle&lt;/tt&gt;. We say that the type of the queue here is covariant in its element type, meaning the subtyping relationships go &amp;ldquo;the same way&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;Meanwhile, suppose the same code, after it processes the &lt;tt&gt;Circle&lt;/tt&gt;,
wants to push the object onto another queue for some other code to deal with. 
We want to ensure that this queue can accept the objects we give it, which might
be &lt;tt&gt;Circle&lt;/tt&gt;s or instances of any subclass. So we need a guarantee that
it can take &lt;em&gt;any&lt;/em&gt; such objects. So, a queue of &lt;tt&gt;UnitCircle&lt;/tt&gt;, say,
would not be good enough---if we gave it a plain &lt;tt&gt;Circle&lt;/tt&gt; this would be
a type error. So our output queue has to have element type &lt;tt&gt;Circle&lt;/tt&gt; 
&lt;em&gt;or any supertype thereof&lt;/em&gt;, that is, element type &lt;tt&gt;? super Circle&lt;/tt&gt;.
Here the type of the queue is contravariant in the element type, meaning the subtyping relationships go &lt;em&gt;opposite ways&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I won&apos;t claim that this explanation covers all sane use-cases of wildcard types.
On the other hand, if you know of any that aren&apos;t in some way similar, I&apos;d
like to hear about them. 
The idea is certainly more general than just code which processes items in queues,
or just code that pushes data from one data structure to another.&lt;/p&gt;

&lt;p&gt;This is also a neat way of considering a classic problem in typed object-oriented
programming, called the &lt;a href=&quot;http://en.wikipedia.org/wiki/Circle-ellipse_problem&quot;&gt;
&amp;ldquo;Circle--Ellipse problem&amp;rdquo;&lt;/a&gt;. The question is
simple. We wish to define two &lt;em&gt;mutable&lt;/em&gt; data types: &lt;tt&gt;Circle&lt;/tt&gt; for representing circles
and &lt;tt&gt;Ellipse&lt;/tt&gt; for representing ellipses. 
Which way, if any, should the subtyping relation be between &lt;tt&gt;Circle&lt;/tt&gt; and &lt;tt&gt;Ellipse&lt;/tt&gt;?&lt;/p&gt;
 
&lt;p&gt;The trick is to remember that a mutable object is not just a value: it is a &lt;em&gt;container&lt;/em&gt;
for a value that can be retrieved and replaced. In other words, we can put data in and get data out.
The presence of these two distinct directions is the source of the problem. 
Put simply: when used in the &amp;ldquo;out&amp;rdquo; direction, for reading the parameters of the circle,
&lt;tt&gt;Circle&lt;/tt&gt; is a &lt;em&gt;subtype&lt;/em&gt; of &lt;tt&gt;Ellipse&lt;/tt&gt; (every valuation of a circle also represents an ellipse);
but in the &amp;ldquo;in&amp;rdquo; direction, for updating the parameters stored in the object,
&lt;tt&gt;Ellipse&lt;/tt&gt; is a subtype of &lt;tt&gt;Circle&lt;/tt&gt;, since we can give an ellipse any set of parameters
that we might give a circle, whereas the converse is not true--circles cannot be updated
with the parameters of ellipses having unequal minor and major radii.&lt;/p&gt;

&lt;p&gt;An even simpler case which illustrates the in/out distinction is 
the usual subtyping rule for functions,
which I will illustrate formal-style just because I can:

&lt;blockquote&gt;
&lt;pre&gt;
       s1 &lt;= t1        t2 &lt;= s2
    ------------------------------
          t1-&gt;t2  &lt;=  s1-&gt;s2 &lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;In English: a function expression&apos;s type &lt;tt&gt;t1-&gt;t2&lt;/tt&gt;
is a subtype of another function expression&apos;s type &lt;tt&gt;s1-&gt;s2&lt;/tt&gt;
if &lt;tt&gt;t2&lt;/tt&gt; (denoting the set of result values) is a subtype of its counterpart &lt;tt&gt;s2&lt;/tt&gt;,
and the type &lt;tt&gt;t1&lt;/tt&gt; (denoting the set of argument values) is a &lt;em&gt;supertype&lt;/em&gt; of its counterpart &lt;tt&gt;s1&lt;/tt&gt;.
Intuitively (or &lt;a href=&quot;http://en.wikipedia.org/wiki/Liskov_substitution_principle&quot;&gt;Liskov&lt;/a&gt;ly), this holds because to be a subtype, 
any term typed &lt;tt&gt;t1-&gt;t2&lt;/tt&gt; must be substitutable 
into any context where a term of type &lt;tt&gt;s1-&gt;s2&lt;/tt&gt; could be used,
meaning the full range of argument values denoted by &lt;tt&gt;s1&lt;/tt&gt; must be acceptable as the call&apos;s content (and, optionally, other values may also be permitted),
and the full range of return values denoted by &lt;tt&gt;t2&lt;/tt&gt; must be acceptable to the call context (and, optionally, 
(and possibly other argument values could be allowed also).
I said &amp;ldquo;if&amp;rdquo; but turning the rule upside down is also valid, so
&amp;ldquo;iff&amp;rdquo; would have been correct (but a stronger statement than the inference rule itself).&lt;/p&gt;

&lt;p&gt;I&apos;d like to add that this is the first time I&apos;ve written down an inference rule
in any of my writing.&lt;/p&gt;

&lt;p&gt;None of this says anything about how &lt;tt&gt;Circle&lt;/tt&gt; and &lt;tt&gt;Ellipse&lt;/tt&gt; should be implemented.
Abstractly, they share a lot, so in any sane implementation we would want to share whatever code
we could. In many object-oriented programming languages, &lt;em&gt;inheritance&lt;/em&gt; is provided as a
code-sharing mechanism. Which way should the inheritance relationship go? It doesn&apos;t matter,
as long we treat this as separate from the subtyping relationship.&lt;/p&gt;

&lt;p&gt;Here is the real problem. Some languages, particularly
Java, make this difficult for us by assuming that these two relationships should be the same.
Most people who know a little about object-oriented programming
will know that inheritance and subtyping are distinct concepts,
although are often conflated.  Historically, C++ can probably be blamed for 
this conflation, in that it popularised the overloading of a single mechanism (class derivation)
for both. However, in C++&apos;s defence, the fact that class inheritance is &lt;tt&gt;private&lt;/tt&gt;
by default is this way precisely because of this distinction. Sadly, 
most texts which teach the language use &lt;tt&gt;public&lt;/tt&gt;
inheritance nearly everywhere without ever explaining why this can be a bad idea. Java
made public inheritance the default, so is far more culpable in my opinion.&lt;/p&gt;

&lt;p&gt;Many people take this as an opportunity to lambast implementation inheritance.
I won&apos;t do this. Inheritance is a useful language feature for capturing commonality of implementation. 
It&apos;s great that I can write a class &lt;tt&gt;C&lt;/tt&gt; which shares a lot of implementation with a pre-existing
class &lt;tt&gt;B&lt;/tt&gt;, simply by describing what is different. It&apos;s very handy that there is no need
to write forwarding functions to the code in &lt;tt&gt;B&lt;/tt&gt; that can be used directly 
in &lt;tt&gt;C&lt;/tt&gt;. It makes for readable code and discourages copy-and-paste
code cloning.&lt;/p&gt;

&lt;p&gt;Subtyping is more subtle, because it is a semantic property. It relates to the meaning
of code, not the raw code itself. Things like direction of data flow don&apos;t turn up in
the more syntactic matter of code re-use (inheritance&apos;s territory) but, as we saw, very much do
in the semantic world of types.&lt;/p&gt;

&lt;p&gt;I said I&apos;ve never seen this explanation written down by anyone else.
but actually, a bit of Googling reveals &lt;a href=&quot;http://www.netsoc.tcd.ie/~mu/fyp/?p=100&quot;&gt;another blogger&lt;/a&gt;
has covered similar ground. You can decide whose explanation you like best!&lt;/p&gt;</description>
  </item>
  <item>
    <title>Completeness</title>
    <pubDate>Sun, 14 Nov 2010 21:47:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2010/11/14#completeness</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/completeness</guid>
    <description>
&lt;p&gt;As researchers, we are naturally wary of addressing problems which don&apos;t have a well-defined end
point. We like to be able to say, &amp;ldquo;we&apos;ve solved it&amp;rdquo;, or perhaps &amp;ldquo;we&apos;ve solved it
for the following formally-characterized subclass of problem&amp;rdquo;. In my work, that doesn&apos;t really
make sense. &lt;a href=&quot;http://www.cl.cam.ac.uk/~srk31/research/cake/&quot;&gt;Cake&lt;/a&gt; is a practical tool for
tackling interface diversity. No such tool can be complete, because for any nontrivial language, or
interface encoding scheme, there is no limit to the crazy encodings that could be dreamed up. When
Kent enumerated &lt;a href=&quot;http://www.bkent.net/Doc/manyform.htm&quot;&gt;&amp;ldquo;the many forms of a single
fact&amp;rdquo;&lt;/a&gt;, he wasn&apos;t making a complete list, which would clearly be impossible---but he was
trying to come up with a catalogue that included a reasonably high proportion of what people
&lt;em&gt;actually do in practice&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Although I could try to formally characterise the class of mismatch which my current Cake
language is capable of reconciling, I&apos;ve never seen much worth in doing so. It&apos;s hard, if not
impossible, to come up with a formal characterisation that actually has practical meaning. In any
such exercise, what tends to happen is that a bunch of practically meaningful cases are excluded,
and a bunch of practically meaningless cases are included. One reason for this is that humans brains
are messy, and don&apos;t respect the formal boundaries induced by conventional mathematical thinking.
Mathematical formalisms strive to tackle complexity primarily by purposely engineered
compositionality; human evolution has done so by a random walk. The point is that humans are full of
specialisations, resource limitations and arbitrary cut-offs. Too often, we embrace the formal
concerns and ignore the human reality. This is the formalism wagging the research, and it&apos;s
something that irritates me.&lt;/p&gt;

&lt;p&gt;One of my favourite examples of formalism-versus-reality is our use of nesting in sentences, and
in particular, what linguists call &amp;ldquo;centre-embedded&amp;rdquo; or &amp;ldquo;self-embedding&amp;rdquo;
structures. (The concepts are distinct, but the distinction is somewhat confused in the literature.)
Sentences such as &amp;ldquo;The rat the cat the dog chased ate died.&amp;rdquo; are perfectly grammatical
according to any formal grammar of English you might reasonably come up with---that is, any grammar
that could also generate the sentences we actually use in real English. If you buy that the role of
grammars is to model the languages that people actually use, then this is clearly a failure of
modelling---yet is a consequence of the recursively generative nature of grammars loved by
formalists. In practice, we humans don&apos;t work in this neatly recursive way---the complex, messy
architecture of our brains means that only &lt;em&gt;some&lt;/em&gt; kinds of embedding are easily processed,
and it turns out, as &lt;a
href=&quot;http://www.phon.ucl.ac.uk/home/PUB/WPL/96papers/abstracts/hudson.htm&quot;&gt;expounded&lt;/a&gt; by Richard
Hudson, that the actual criteria are far more complex than anyone would have thought. For example,
it appears to make a difference whether the subjects of the clauses being nested are pronouns or
not.&lt;/p&gt;

&lt;p&gt;A related and much more familiar example for most readers will be the halting problem. We know
that no tool which attempts to answer an undecidable question can be complete. Therefore, a lot of
researchers just avoid those problems. &lt;a
href=&quot;http://research.microsoft.com/en-us/um/people/bycook/&quot;&gt;Byron Cook&lt;/a&gt;, who in recent years has
been doing stellar and pioneering work on proving program termination, has been known to talk about
the variety of bafflement, disdain and ridicule which his work provoked in its inception. It&apos;s
simply anathema to conventional CS research approaches to attack problems for which it&apos;s known that
there can be no &lt;em&gt;complete&lt;/em&gt; solution. In fact, far too many self-professing computer
scientists don&apos;t even understand the distinction between a partial and total solution. We have to
get over this, simply because lots of important problems are in this class! I like to think my work
on Cake is doing its bit. The halting problem is somewhat different from Cake-like problems, in that
its&apos; a formally defined, provably-undecidable problem, whereas the incompleteness of systems like
Cake lies in that we can&apos;t even completely define the problem space in any formal way. I should add
that I&apos;m not putting my work in the same bracket as Byron&apos;s! But there is at least this small
thematic similarity in the flavour of criticism that tends to come up. Speaking of which, I could do
with remembering this argument when it&apos;s time for my viva....&lt;/p&gt;</description>
  </item>
  <item>
    <title>Making a SPLASH</title>
    <pubDate>Wed, 02 Jun 2010 20:06:00 +0200</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2010/06/02#making-a-splash</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/making-a-splash</guid>
    <description>
&lt;p&gt;So my paper about &lt;a 
href=&quot;http://www.cl.cam.ac.uk/~srk31/cake/&quot;&gt;Cake&lt;/a&gt; was accepted for 
OOPSLA at &lt;a href=&quot;http://splashcon.org/&quot;&gt;SPLASH&lt;/a&gt;---hooray! You can 
find a preprint in my &lt;a 
href=&quot;http://www.cl.cam.ac.uk/~srk31/#publications&quot;&gt;publications&lt;/a&gt; 
section.  Overall the reviews were positive, modulo a few legitimate 
grumbles about related work and evaluation. I still have implementation 
work to do, but I&apos;m hoping to make a big software release at the end of 
the summer---as well as, hopefully, submitting my dissertation. The 
acceptance is a nice vindication of my work (and, not being completely 
unvindictive, I have to say it&apos;s a welcome rebuttal to the 
naysayers!).&lt;/p&gt;
 
&lt;p&gt;This is the first full-length research paper I&apos;ve published, and has 
taken me a despairingly long time, but I finally feel as though I&apos;m 
getting the hang of it all. I&apos;m also finding that the infrastructure 
I&apos;ve built can be applied to many different problems, and I have a giant 
and growing list of ideas to pursue in future work. The one thing that 
lets me down is my ability to implement my ideas to any reasonable 
schedule! Perhaps the knack is being very careful (not to mention 
experienced) about choosing which ideas to pursue, and how. Oh, another 
thing that lets me down is not having a job lined up for after I finish 
this pesky PhD....&lt;/p&gt;
</description>
  </item>
  <item>
    <title>Multi-core madness</title>
    <pubDate>Wed, 21 Apr 2010 14:18:00 +0200</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2010/04/21#multicore-madness</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/multicore-madness</guid>
    <description>
&lt;p&gt;A while back I posted a rant to our &lt;a href=&quot;http://www.cl.cam.ac.uk/research/srg/netos/&quot;&gt;netos&lt;/a&gt;
mailing list a while ago, which I think says enough about my attitude to multi-core programming
research that I should blog it here.&lt;/p&gt;

&lt;p&gt;My rant was prompted by the following &lt;a
href=&quot;http://www.computer.org/portal/web/computingnow/swcfp1&quot;&gt;call for papers&lt;/a&gt; for a special
issue of IEEE software.&lt;/p&gt;

&lt;blockquote cite=&quot;http://www.computer.org/portal/web/computingnow/swcfp1&quot;&gt; &lt;p&gt;&amp;ldquo;Software for
the Multiprocessor Desktop: Applications, Environments, Platforms&amp;rdquo;&lt;/p&gt;

&lt;h4&gt;Guest Editors:&lt;/h4&gt;
&lt;ul&gt;&lt;li&gt;Victor Pankratius (Karlsruhe Institute of Technology)&lt;/li&gt;
&lt;li&gt;Wolfram Schulte (Microsoft Research)&lt;/li&gt;
&lt;li&gt;Kurt Keutzer (Univ. California Berkeley)&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;
Multicore processors, like Nehalem or Opteron, and manycore processors, like
Larrabee or GeForce, are becoming a de facto standard for every new desktop
PC. Exploiting the full hardware potential of these processors will require
parallel programming. Thus, many developers will need to parallelize desktop
applications, ranging from browsers and business applications to media
processors and domain-specific applications. This is likely to result in the
largest rewrite of software in the history of the desktop. To be successful,
systematic engineering principles must be applied to parallelize these
applications and environments.
&lt;/p&gt;
&lt;p&gt;[continues...]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My rant: what desktop applications  actually are there which need to take advantage of this
wonderful new  hardware? The CfP eagerly suggests rewriting a shedload of existing  software, but
that seems like a giant waste of effort -- at least in the  common case where the existing software
runs perfectly well enough on  not-so-many-core hardware. This is true of pretty much all existing 
desktop software as far as I can see.&lt;/p&gt;

&lt;p&gt;There might be new application classes out there, or new  compute-intensive features that&apos;d
benefit existing applications, but  that wouldn&apos;t be &lt;em&gt;re&lt;/em&gt;writing, and in any case the CfP
doesn&apos;t identify any....&lt;/p&gt;</description>
  </item>
  <item>
    <title>Separating computation from storage</title>
    <pubDate>Mon, 19 Apr 2010 20:22:00 +0200</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2010/04/19#computation-and-storage</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/computation-and-storage</guid>
    <description>
&lt;p&gt;One of the nice things about laziness is that it eliminates the distinction between stored and
computed values. You can write the same code without caring whether the values it manipulates were
discovered by on-demand computation or were retrieved from some storage location. In purely
functional languages, this works by throwing away all explicit notion of storage, then relying on
the runtime to come up with a sensible execution strategy which exploits the underlying machine&apos;s
storage. Experience shows that runtimes aren&apos;t yet clever enough to do especially good jobs of this:
Haskell programs tend to use lots of memory, and/or to include programmer-inserted strictness
annotations which hint at a better strategy.&lt;/p&gt;

&lt;p&gt;The distinction between computation and storage in languages is well-known to be problematic. Stored
data representations are a very change-prone design decision, hence justifying the common practice
in object-oriented code (and other!) of using getters to access remote modules&apos; state, rather than
having them expose member variables directly. The computation-oriented interface is more general in
that intervening computation can be inserted, or not---if the &amp;ldquo;got&amp;rdquo; representation
matches what&apos;s in memory, the getter can just redirect to storage. Conversely, interposing on
storage accesses, while possible using memory protection techniques (like the pairing of
&lt;tt&gt;mprotect()&lt;/tt&gt; and an appropriate &lt;tt&gt;SIGSEGV&lt;/tt&gt; handler on Unix platforms) is inefficient on
conventional hardware, violates most languages&apos; abstraction boundaries and is not easy for
user-level programmers to get working. This interposability motivation for getters and setters (and
and the change-resilience it enables) is far stronger than a purely abstraction-oriented motivation.
The argument is essentially the same as Parnas&apos;s from 1972, but this line of thinking still &lt;a
href=&quot;http://typicalprogrammer.com/?p=23&quot;&gt;evades some bloggers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Recently I&apos;ve been writing some code using &lt;tt&gt;ptrace()&lt;/tt&gt; and &lt;a
href=&quot;http://www.nongnu.org/libunwind/&quot;&gt;&lt;tt&gt;libunwind&lt;/tt&gt;&lt;/a&gt; and finding myself with a particular
requirement: implementing data structures that can work with various implementations of storage.
Specifically, one feature of &lt;tt&gt;libunwind&lt;/tt&gt; is that it can unwind the stack in your current
process, or in another, using the same interface in each case. This kind of design is a Good Thing
in much runtime infrastructure and debugging support generally, because you may or may not want a
process separation in the picture: separation is good for isolation, but badly affects performance.
Now, &lt;tt&gt;libunwind&lt;/tt&gt; abstracts storage using a read--write pair of memory access functions. This
is fine for simple reads and writes. Unfortunately I want something more demanding: I want to
traverse some data structure residing in the target process. (As it happens, this data structure is
some heap bookkeeping information that is maintained by a set of &lt;tt&gt;glibc&lt;/tt&gt; &lt;a
href=&quot;http://www.gnu.org/s/libc/manual/html_node/Hooks-for-Malloc.html&quot;&gt;&lt;tt&gt;malloc&lt;/tt&gt; hooks&lt;/a&gt; I
wrote as part of the &lt;a href=&quot;http://www.cl.cam.ac.uk/~srk31/cake/&quot;&gt;Cake&lt;/a&gt; runtime.)&lt;/p&gt;

&lt;p&gt;Generic programming &lt;em&gt;ought&lt;/em&gt; to be great for this. Unfortunately, at least in the form of
contemporary C++, it isn&apos;t enough. In C++, the notion of memory is so pervasive that it can&apos;t be
fully abstracted.  That&apos;s not to say you can&apos;t try to get &lt;em&gt;most&lt;/em&gt; of the way there, and the
STL&apos;s allocators go some way---but not far enough. Although we can alter how they &lt;em&gt;allocate&lt;/em&gt;
storage, since STL containers are not parameterised in the pointer types they use internally, we
can&apos;t make them &lt;em&gt;access&lt;/em&gt; their own implementation-specific data structures in a customised
way. (See &lt;a href=&quot;http://www.informit.com/articles/article.aspx?p=31529&amp;seqNum=6&quot;&gt;this snippet&lt;/a&gt;
about overloading the &lt;tt&gt;&amp;amp;&lt;/tt&gt; operator, from an article by Andrei Alexandrescu, for more
evidence and examples.)&lt;/p&gt;

&lt;p&gt;If we fall back on hand-coding data structures and algorithms ourselves, we can make some headway.
The first step is to define a C++ &amp;ldquo;pointer-like thing&amp;rdquo; which actually uses the accessor
functions. Here&apos;s my first attempt. Among other limitations, it can only read, not write, its
pointed-to data.&lt;/p&gt;

&lt;pre&gt;
template &amp;lt;typename Target&amp;gt;
class unw_read_ptr
{
    unw_addr_space_t as;
    Target *ptr;
    mutable Target buf; // HACK: temporary to make operator-&gt; work
public:
    typedef unw_read_ptr&amp;lt;Target&amp;gt; self_type;
    unw_read_ptr(unw_addr_space_t as, Target *ptr) : as(as), ptr(ptr) {}
    Target operator*() const 
    { 
        Target tmp; 
        assert(sizeof tmp % sizeof (unw_word_t) == 0); // simplifying assumption
        unw_word_t *tmp_base = reinterpret_cast&amp;lt;unw_word_t*&amp;gt;(&amp;amp;tmp);
        for (unw_word_t *tmp_tgt = reinterpret_cast&amp;lt;unw_word_t*&amp;gt;(&amp;amp;tmp);
            tmp_tgt - tmp_base &amp;lt; sizeof tmp / sizeof (unw_word_t);
            tmp_tgt++)
        {
            off_t byte_offset 
             = reinterpret_cast&amp;lt;char*&amp;gt;(tmp_tgt) - reinterpret_cast&amp;lt;char*&gt;(tmp_base);
            unw_get_accessors(as)-&amp;gt;access_mem(as, 
                reinterpret_cast&amp;lt;unw_word_t&amp;gt;(reinterpret_cast&amp;lt;char*&gt;(ptr) + byte_offset), 
                tmp_tgt,
                0,
                NULL);
		}            
        return tmp;
    }
    // HACK: operator-&amp;gt; brokenly demands return of a real pointer...
    // ... so use a per-object temporary. FIXME
    Target *operator-&amp;gt;() const { this-&gt;buf = this-&gt;operator*(); return &amp;amp;this-&gt;buf; } 
    self_type&amp;amp; operator++() // prefix
    { ptr++; return *this; }
    self_type  operator++(int) // postfix ++
    { Target *tmp; ptr--; return self_type(as, tmp); }
    self_type&amp;amp; operator--() // prefix
    { ptr++; return *this; }
    self_type  operator--(int) // postfix ++
    { Target *tmp; ptr--; return self_type(as, tmp); }
    
    // we have two flavours of equality comparison: against ourselves,
    // and against unadorned pointers (risky, but useful for NULL testing)
    bool operator==(const self_type arg) { 
    	return this-&amp;gt;as == arg.as
        &amp;amp;&amp; this-&amp;gt;ptr == arg.ptr; 
    }
    bool operator==(void *arg) { return this-&amp;gt;ptr == arg; }
    
    bool operator!=(const self_type arg) { return !(*this == arg); }
    bool operator!=(void *arg) { return !(this-&amp;gt;ptr == arg); }

	// default operator= and copy constructor work for us
    // but add another: assign from a raw ptr
    self_type&amp;amp; operator=(Target *ptr) { this-&amp;gt;ptr = ptr; return *this; }

    self_type operator+(int arg)
    { return self_type(as, ptr + arg); }

    self_type operator-(int arg)
    { return self_type(as, ptr - arg); }

    ptrdiff_t operator-(const self_type arg)
    { return this-&amp;gt;ptr - arg.ptr; }
    
    operator void*() { return ptr; }
};
&lt;/pre&gt;

&lt;p&gt;This has got me as far as being able to traverse a linked list residing in the target process
using the same code you&apos;d use to traverse a local one. Unfortunately, a linked list doesn&apos;t cut it
for my performance requirements: the target process heap contains many thousands of allocated
blocks, and I need to be able to resolve a heap address to a particular block quickly. So, perhaps a
hash table or a red--black tree would be a good choice. This is where the pain hits: I really don&apos;t
want to create my own implementations of either of these. I could cannibalise the source of existing
one (and I think that&apos;s just what I&apos;m going to do) but it&apos;d be nice to take an STL-like container
and just use it as-is. (I am planning to use &lt;a
href=&quot;http://code.google.com/p/google-sparsehash/&quot;&gt;&lt;tt&gt;google-sparsehash&lt;/tt&gt;&lt;/a&gt;, and create a
hacked version of the lookup function, using my special pointer class above, for the &amp;ldquo;separate
process&amp;rdquo; case.)&lt;/p&gt;

&lt;p&gt;A final conclusion is that polymorphism is all very well, but only when the programmer can be
oblivious to it. Polymorphism is after all a very low-level concept. Why &lt;em&gt;should&lt;/em&gt; we require
separate implementations of a function for operating on different kinds of data? From low-level
programming we have got used to the idea that data comes in different forms, like ints and floats
and lists and arrays and so on, and that these are treated separately unless some polymorphic
cleverness unifies them. But in a truly high-level programming language, it should be a given that
when your code is abstract with respect to your data structures&apos; representations, or with respect to
&lt;em&gt;any other underlying logic&lt;/em&gt; (such as memory access, in my example), then you can
mix-and-match any implementation you like for that underlying logic.&lt;/p&gt;

&lt;p&gt;Under this criterion, ML-style parametric polymorphism wins nicely, because type inference means
that the programmer doesn&apos;t need to care about the machinery surrounding polymorphism. In languages
where programmer anticipation is required---such as by adding particular type parameters in the case
of C++ templates, or by writing particular type annotations as one might in Haskell---then we are
forcing the programmer to be aware of these low-level distinctions, so have not yet delivered
obliviousness. (I distinguish Haskell from ML because idiomatically, my limited experience suggests
that Haskell programs seem to contain an awful lot more type annotations than ML programs do. I will
stand corrected if this turns out not so or not important!) Even ML inflicts polymorphism on the
programmer in its indecipherable compile-time type errors, but maybe someone can write a compiler
which makes things comprehensible.&lt;/p&gt;</description>
  </item>
  <item>
    <title>Where the time goes</title>
    <pubDate>Fri, 02 Apr 2010 17:25:00 +0200</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2010/04/02#where-the-time-goes</link>
    <category>/meta</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/meta/where-the-time-goes</guid>
    <description>
&lt;p&gt;At 2pm today I finished making some comments on a print-out on a draft undergraduate dissertation
of one of my students. He&apos;s out of town at the moment, so I scanned in my scribblings and prepared
to send them. I&apos;d printed the 68-page draft 2-up to save paper. We have a nifty scanner that can
sheet-feed, so scanning 34 pages was very quick and easy, except for one problem: for some reason
the pages came out in reverse. I later discover that the reason the pages came out reversed is that
although I placed the pages face-down in the feeder, as the markings on the feeder suggested I
should, the software has a very helpful option called &amp;ldquo;scan facing forward&amp;ldquo; (or
somesuch) which reverses this logic. More annoyingly, this is turned on by default! Unfortunately
the scanner software has no facility to re-order pages (except during scanning). No problem, I
thought -- I&apos;ll go back to my desk and re-order them in my familiar Unix tools, rather than spending
more time down at the scanner.&lt;/p&gt;

&lt;p&gt;It should be simple: split the PDF into pages using &lt;tt&gt;gs -sDEVICE=pdfwrite
-sOutputFile=page%d&lt;/tt&gt;, reorder the pages using &lt;tt&gt;ls | tac&lt;/tt&gt;, and &lt;tt&gt;pdfjoin&lt;/tt&gt;. Problem
one: I couldn&apos;t seem to get &lt;tt&gt;page%d&lt;/tt&gt; working with Ghostscript&apos;s &lt;tt&gt;pdfwrite&lt;/tt&gt; driver, so
had to use &lt;tt&gt;psrgb&lt;/tt&gt; and then convert the Postscript output to PDF using &lt;tt&gt;ps2pdf&lt;/tt&gt;. This
should work, surely? No. Problem two: neither &lt;tt&gt;ps2pdf&lt;/tt&gt; nor Ghostscript understands page
orientation properly, so what I get is a portrait-orientation window onto my landscape-oriented
pages, with the right-hand side cut off. &lt;a
href=&quot;http://pages.cs.wisc.edu/~ghost/doc/cvs/Ps2pdf.htm&quot;&gt;This web page&lt;/a&gt; reveals that it&apos;s a
limitation of both Ghostscript and its &lt;tt&gt;pdfwrite&lt;/tt&gt; driver. &lt;a
href=&quot;http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=503191&quot;&gt;This bug report&lt;/a&gt; shows that the
problem has been around for years and hasn&apos;t gone away. None of the suggested Ghostscript
incantations on &lt;a href=&quot;http://www.troubleshooters.com/linux/gs.htm&quot;&gt;this web page&lt;/a&gt; has any
effect for me, but I waste an hour trying them and various other combinations of options.&lt;/p&gt;

&lt;p&gt;It&apos;s now 4.22pm, and I&apos;ve just tried using Adobe Acrobat to perform the same feat. It has exactly
the same problem!  As my time gets more contended, it gets more and more annoying to spend it
fighting crappy software. I could probably optimise this by developing the judgement not to pursue
the &amp;ldquo;should work&amp;rdquo; way, and instead cut straight to the &amp;ldquo;ugly, but definitely
works&amp;rdquo; way. I&apos;m about to go down and re-scan the document.&lt;/p&gt;

</description>
  </item>
  <item>
    <title>C++ Gotme number 4: constant surprise</title>
    <pubDate>Fri, 19 Feb 2010 23:47:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2010/02/19#c%2B%2B-gotme-4</link>
    <category>/devel</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/devel/c%2B%2B-gotme-4</guid>
    <description>
&lt;p&gt;When I was less experienced with C++, I would avoid creating any sort of &lt;tt&gt;const&lt;/tt&gt;ness in my
code because it invariably led to headaches. When I&apos;d tried, all too often I&apos;d found myself trawling
through the source code either adding or removing &lt;tt&gt;const&lt;/tt&gt;ness all over the place in order to
make things compile. It&apos;s certainly true that &lt;tt&gt;const&lt;/tt&gt;ness has to be done right or not at all.
Like a lot of C++, it&apos;s not resilient either to mistakes or to change.&lt;/p&gt;

&lt;p&gt;These days I usually make a reasonable job. I&apos;ve found the best way to understand constness is as
follows. Every object in a C++ program exposes exactly two variants of its interface: the
&amp;ldquo;full&amp;rdquo; one and the &lt;tt&gt;const&lt;/tt&gt; one. The actual boundary between these, at least in
the case of user-defined types, is somewhat flexible (as witnessed by &lt;tt&gt;mutable&lt;/tt&gt;, and by your
forgetfulness to add &lt;tt&gt;const&lt;/tt&gt; to method definitions!).&lt;/p&gt;

&lt;p&gt;Grokking the difference between a const pointer and pointer-to-const is of course a rite of
passage in C and C++ programming. A more obscure subtlety about &lt;tt&gt;const&lt;/tt&gt; in C++ is that
&lt;tt&gt;const&lt;/tt&gt; references let you pass around temporaries&apos; lvalues, but you can&apos;t do this in a
non-const fashion. It&apos;s not clear why not, except that it&apos;s something you&apos;d rarely want to do
---unless, of course, you had omitted to add the &lt;tt&gt;const&lt;/tt&gt; annotation in the signature of
whatever function you wanted to pass the lvalue to. That&apos;s one reason why getting &lt;tt&gt;const&lt;/tt&gt;
right is something you can&apos;t really opt out of.&lt;/p&gt;

&lt;p&gt;Today I was wrestling with an unfortunate side of &lt;tt&gt;const&lt;/tt&gt;---untraceable compilation
errors. I&apos;m using the &lt;a href=&quot;http://www.boost.org/&quot;&gt;boost&lt;/a&gt; graph library so I can run graph
algorithms over my &lt;a href=&quot;http://www.dwarfstd.org/&quot;&gt;DWARF&lt;/a&gt; data structure. Since all my
&amp;ldquo;nodes&amp;rdquo; live in a &lt;tt&gt;std::map&lt;/tt&gt;, I was specialising the &lt;tt&gt;graph_traits&lt;/tt&gt; giving
the &lt;tt&gt;map&lt;/tt&gt;&apos;s &lt;tt&gt;value_type&lt;/tt&gt; as the node type. Here&apos;s what the compiler said.&lt;/p&gt;

&lt;pre&gt;
/local/scratch/srk31/opt/bin/../lib/gcc/i686-pc-linux-gnu/4.4.3/../../../../incl
ude/c++/4.4.3/bits/stl_pair.h: In member function ?std::pair&amp;lt;const long long uns
igned int, boost::shared_ptr&amp;lt;dwarf::encap::die&amp;gt; &gt;&amp;amp; std::pair&amp;lt;const long long uns
igned int, boost::shared_ptr&amp;lt;dwarf::encap::die&amp;gt; &gt;::operator=(const std::pair&amp;lt;con
st long long unsigned int, boost::shared_ptr&amp;lt;dwarf::encap::die&amp;gt; &gt;&amp;amp;)?:
/local/scratch/srk31/opt/bin/../lib/gcc/i686-pc-linux-gnu/4.4.3/../../../../incl
ude/c++/4.4.3/bits/stl_pair.h:68:   instantiated from ?boost::concepts::VertexLi
stGraph&amp;lt;G&amp;gt;::~VertexListGraph() [with G = dwarf::encap::dieset]?
/home/srk31/opt/include/boost/graph/graph_concepts.hpp:166:   instantiated from 
?static void boost::concept::requirement&amp;lt;Model&amp;gt;::failed() [with Model = boost::c
oncepts::VertexListGraphConcept&amp;lt;dwarf::encap::dieset&amp;gt;]?
/home/srk31/opt/include/boost/concept_check.hpp:43:   instantiated from ?void bo
ost::function_requires(Model*) [with Model = boost::concepts::VertexListGraphCon
cept&amp;lt;dwarf::encap::dieset&amp;gt;]?
test-6.cpp:8:   instantiated from here
/local/scratch/srk31/opt/bin/../lib/gcc/i686-pc-linux-gnu/4.4.3/../../../../incl
ude/c++/4.4.3/bits/stl_pair.h:68: error: non-static const member ?const long lon
g unsigned int std::pair&amp;lt;const long long unsigned int, boost::shared_ptr&amp;lt;dwarf::
encap::die&amp;gt; &gt;::first?, can&apos;t use default assignment operator
In file included from test-6.cpp:1:
/home/srk31/opt/include/boost/graph/graph_concepts.hpp: In destructor ?boost::co
ncepts::VertexListGraph&amp;lt;G&amp;gt;::~VertexListGraph() [with G = dwarf::encap::dieset]?:
/home/srk31/opt/include/boost/graph/graph_concepts.hpp:166:   instantiated from 
?static void boost::concept::requirement&amp;lt;Model&amp;gt;::failed() [with Model = boost::c
oncepts::VertexListGraphConcept&amp;lt;dwarf::encap::dieset&amp;gt;]?
/home/srk31/opt/include/boost/concept_check.hpp:43:   instantiated from ?void bo
ost::function_requires(Model*) [with Model = boost::concepts::VertexListGraphCon
cept&amp;lt;dwarf::encap::dieset&amp;gt;]?
test-6.cpp:8:   instantiated from here
/home/srk31/opt/include/boost/graph/graph_concepts.hpp:188: note: synthesized me
thod ?std::pair&amp;lt;const long long unsigned int, boost::shared_ptr&amp;lt;dwarf::encap::di
e&amp;gt; &gt;&amp;amp; std::pair&amp;lt;const long long unsigned int, boost::shared_ptr&amp;lt;dwarf::encap::di
e&amp;gt; &gt;::operator=(const std::pair&amp;lt;const long long unsigned int, boost::shared_ptr&amp;lt;
dwarf::encap::die&amp;gt; &gt;&amp;amp;)? first required here 
make: *** [test-6.o] Error 1
&lt;/pre&gt;

&lt;p&gt;The bottom error refers to line 188 of &lt;tt&gt;graph_concepts.hpp&lt;/tt&gt;, which is doing an innocuous
assignment from a vertex iterator &lt;tt&gt;v = *p.first;&lt;/tt&gt;. The variable &lt;tt&gt;v&lt;/tt&gt; is an instance of
my map entry type. Somehow, the compiler can&apos;t synthesise a copy constructor for the pointed-to
vertex. This was incredibly difficult to track down because it wasn&apos;t due to any use of
&lt;tt&gt;const&lt;/tt&gt; in my code directly. I scoured my code for suspicious &lt;tt&gt;const&lt;/tt&gt;, but to no
avail. What had escaped me is that the &lt;tt&gt;value_type&lt;/tt&gt; in a &lt;tt&gt;std::map&lt;/tt&gt; is as follows
(from Stroustrup C++PL section 17.4.1.1).&lt;/p&gt;

&lt;pre&gt;typedef pair&amp;lt;const Key, T&amp;gt; value_type;
&lt;/pre&gt;

&lt;p&gt;In other words, maps are designed so that you can&apos;t update the key of an entry once they&apos;re
created. This is very sane, because to do so might violate some invariant of the containing
structure (imagining the popular red-black tree implementation). I hadn&apos;t noticed this limitation
before because although it&apos;s common to initialise new &lt;tt&gt;pair&lt;/tt&gt; objects, it&apos;s rare to update an
existing one. Even though I had purposely avoided making the whole pair &lt;tt&gt;const&lt;/tt&gt; in my code,
there was already a &lt;tt&gt;const&lt;/tt&gt; lurking in the header.&lt;/p&gt;

&lt;p&gt;That the compiler couldn&apos;t give me a better error message (i.e. one actually pointing to the code
at fault) is certainly disappointing, and will be fixed in a better compiler. Whether all this
fiddling &lt;tt&gt;const&lt;/tt&gt;ness is a weakness with the C++ language I&apos;m not sure. It&apos;s certainly
self-consistent and well-motivated. Other languages might not have me worrying about &lt;tt&gt;const&lt;/tt&gt;,
but they also might not catch certain errors. Is C++&apos;s trade-off good value? It&apos;s also not clear
whether a better definition of &lt;tt&gt;map&lt;/tt&gt; might not have lifted the &lt;tt&gt;const&lt;/tt&gt; into individual
references to the &lt;tt&gt;value_type&lt;/tt&gt;... or not. I&apos;d like to be able to rail and propose some better
language design, but part of me suspects that sometimes in programming, the devil really is
inescapably in the details.&lt;/p&gt;</description>
  </item>
  <item>
    <title>Smart pointers: smart pointers (C++ Gotme number 3)</title>
    <pubDate>Tue, 02 Feb 2010 00:45:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2010/02/02#c%2B%2B-gotme-3</link>
    <category>/devel</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/devel/c%2B%2B-gotme-3</guid>
    <description>
&lt;p&gt;I&apos;ve been writing some C++ code using &lt;a href=&quot;http://www.boost.org/&quot;&gt;boost&lt;/a&gt;&apos;s smart pointers
recently. Naturally, I tripped myself up. Memory corruption appeared, and I noticed that my shared
objects were the problem. They were getting destructed even though I had a &lt;tt&gt;shared_ptr&lt;/tt&gt;
pointing to them the whole time. Here&apos;s how it happened.&lt;/p&gt;

&lt;pre&gt;boost::shared_ptr&amp;lt;Die_encap_subprogram&amp;gt;
create_subprogram(Die_encap_base&amp;amp; parent, boost::optional&amp;lt;const std::string&amp;&amp;gt; name)
{
    return boost::shared_ptr&amp;lt;Die_encap_subprogram&amp;gt;(new Die_encap_subprogram(parent, name));
}
&lt;/pre&gt;

&lt;/p&gt;The return statement is evaluated as follows.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;construct a &lt;tt&gt;Die_encap_subprogram&lt;/tt&gt;&lt;/li&gt;

&lt;li&gt;create a temporary pointing to that &lt;tt&gt;Die_encap_subprogram&lt;/tt&gt;&lt;/li&gt;

&lt;li&gt;construct a temporary &lt;tt&gt;boost::shared_ptr&amp;lt;Die_encap_subprogram&amp;gt;&lt;/tt&gt;, passing the temp pointer&lt;/li&gt;

&lt;li&gt;return a copy of that temporary&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;So far, so good. Here&apos;s the calling code.&lt;/p&gt;

&lt;pre&gt;
	std::cerr &lt;&lt; &quot;dies size before: &quot; &lt;&lt; ds().size();
	abstract::factory::get_factory&lt;die&gt;(get_spec()).create_subprogram(
		(**all_cus.compile_units_begin()),
		std::string(symname));
	std::cerr &lt;&lt; &quot;dies size after: &quot; &lt;&lt; ds().size();
&lt;/pre&gt;

&lt;p&gt;Although my factory method &amp;ldquo;helpfully&amp;rdquo; returns a shared pointer, we discard the return
value of the factory method. So, for the object to stay alive, we are relying on there being a copy
of the &lt;tt&gt;boost::shared_ptr&amp;lt;Die_encap_base&amp;gt;&lt;/tt&gt; somewhere. The code I&apos;ve shown doesn&apos;t take
a copy, so where could one come from? Well, one is created inside the object constructor, where it
registers itself with a containing data structure. Here&apos;s the code which creates that second shared
pointer.&lt;/p&gt;

&lt;pre&gt;Die_encap_base(Dwarf_Half tag,
        Die_encap_base&amp;amp; parent, 
        boost::optional&amp;lt;const std::string&amp;amp;&amp;gt; name)
     :	die(parent.m_ds, parent.m_offset, tag, parent.m_ds.next_free_offset(), 0, attribute_map(), die_off_list()) // FIXME
    {
        m_ds.insert(std::make_pair(m_offset, boost::shared_ptr&amp;lt;dwarf::encap::die&amp;gt;(this)));
        parent.m_children.push_back(m_offset);
        m_attrs.insert(std::make_pair(DW_AT_name, dwarf::encap::attribute_value(
            std::string(*name))));
	}
&lt;/pre&gt;  


&lt;p&gt;If this second shared pointer is going to be sufficient to keep the object alive, we require some
&amp;ldquo;action at a distance&amp;rdquo;: the first shared pointer must somehow become aware that we have
just created another shared pointer to its object. How might this work? The shared_ptr
implementation would have to keep its reference counts in a shared table, accessible to all shared
pointers, so that they can look up the relevant refcount by from the pointer. The table must be
shared between &lt;em&gt;all&lt;/em&gt; shared pointer instances, not just those of a given type parameter, to
allow upcasting and downcasting---notice how the target type is different in this snippet than in
the earlier one, because we&apos;re in the base class. For this reason, our hypothetical table
implementation would have to catch pointers-to-subobjects, probably by storing &lt;em&gt;address
ranges&lt;/em&gt; not just object start addresses. Even this is tricky if the shared pointer was created
from an imprecisely-typed pointer (i.e. one whose static type is a supertype) because we might be
oblivious to some larger enclosing allocation (i.e. the superobject actually allocated). This is
doable, albeit not portably, given &lt;tt&gt;boost::shared_ptr&lt;/tt&gt;&apos;s caveat that it only applies to
pointers that were returned by &lt;tt&gt;new&lt;/tt&gt;---so we could get the full address range using the heap
metadata.&lt;/p&gt;

&lt;p&gt;Instead of all this table business, &lt;tt&gt;boost::shared_ptr&lt;/tt&gt; just uses a shared count
&lt;em&gt;created when constructing a smart pointer from a non-smart pointer&lt;/em&gt;. Each pointer carries
the address of a separate object holding the shared refcount. When you copy the shared pointer, it
increments the count and propagates the shared count&apos;s address into the new copy of the pointer.
Naturally, since it relies on continuity of propagation through shared pointers, it doesn&apos;t work
when that chain is broken---you end up with multiple counts for the same object. My code suffers
exactly that problem: it creates a completely separate shared pointer to what is
&amp;ldquo;coincidentally&amp;rdquo; the same object referenced by some shared_ptr (i.e. communicated one or
more intervening &lt;em&gt;non&lt;/em&gt;-shared pointers, in my case the &lt;tt&gt;this&lt;/tt&gt; pointer in the
constructor call).&lt;/p&gt;

&lt;p&gt;The fix is simple enough: have the factory return a regular pointer or reference to the
constructed object. Of course, what if some client code innocently wants to use &lt;tt&gt;shared_ptr&lt;/tt&gt;
on that object? That&apos;s not necessarily a problem, but it won&apos;t magically extend the life of objects
that would otherwise be reclaimed according to the object lifetime policies which my own code&apos;s use
of &lt;tt&gt;shared_ptr&lt;/tt&gt; creates. This ability to create, out of innocuous-looking code, multiple
conflicting policies about when an object should reclaimed, is a limitation of the smart pointer
approach, and is stronger than simply &amp;ldquo;&lt;tt&gt;shared_ptr&lt;/tt&gt; won&apos;t collect cycles&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;Slogan-wise, this is perhaps an argument in favour of &amp;ldquo;smart objects, not smart
pointers&amp;rdquo;. True per-object reference counts can be implemented in at least two ways: either a
Python-like in-band solution, where each object has a refcount built-in, or else the unconventional
out-of-band table solution I outlined above. The former isn&apos;t an option for C++, because we can&apos;t
retroactively add a count field to an object, and don&apos;t want all instances of all classes to pay the
overhead. However, the latter solution is quite appealing to me. Keeping object descriptions
out-of-band is a powerful technique for retaining binary compatibility while adding run-time
facilities, and is the basis of my proposed implementation of Python, which I might just outline in
a future post.&lt;/p&gt;</description>
  </item>
  <item>
    <title>Thinking time</title>
    <pubDate>Tue, 12 Jan 2010 17:08:00 +0100</pubDate>
    <link>http://www.inf.usi.ch/postdoc/kells/blog/2010/01/12#thinking-time</link>
    <category>/research</category>
    <guid isPermaLink="false">http://www.inf.usi.ch/postdoc/kells/blog/research/thinking-time</guid>
    <description>
&lt;p&gt;A few years ago I attended an excellent seminar by &lt;a 
href=&quot;http://www.cs.ucl.ac.uk/staff/B.Karp/&quot;&gt;Brad Karp&lt;/a&gt; about how to do a 
(successful) PhD. I really should have listened more carefully. However, 
one of the things I do remember was a quotation from his advisor, &lt;a 
href=&quot;http://www.eecs.harvard.edu/~htk/&quot;&gt;H.T. Kung&lt;/a&gt;, which in paraphrase was 
&amp;ldquo;if you can make time for two hours&apos; thinking each day, your 
career is made&amp;rdquo;. It&apos;s a nice quotation.&lt;/p&gt;

&lt;p&gt;Of course what I didn&apos;t notice then is that the statement is 
ambiguous. I thought it meant that if you make a point of reserving two 
hours&apos; thinking time each day, you&apos;d be certain to have a successful 
career. Now that I know how impossible it is to schedule two hours&apos; 
thinking per day, I am forced into the converse interpretation: if you 
can afford two hours&apos; thinking time per day, you must already have job 
security.&lt;/p&gt;

&lt;p&gt;Okay, so I&apos;m somewhat embittered by my career&apos;s non-starting (and the 
remaining 10% of me is joking). Like I said, I should have listened more 
carefully....&lt;/p&gt;</description>
  </item>
  </channel>
</rss>
