Sunday, April 15, 2012

New programming languages and barriers to entry

So, the last blog post got me thinking (musing, if you will) on mission creep for languages. If we look at the modern history of programming languages - that is from Java onward - we find that most popular languages have started off in a niche and crept into the mainstream. E.g., Java from applets, C# from GUI Windows programs, Javascript from client-side scripting, Perl from server-side scripting, Python and Ruby from small scripts, and so forth.

This is a source of many bad things! Languages are often designed well for their niche, but end up causing problems for other tasks. A prime example is dynamic typing, which is great for short scripts but makes comprehending large systems extremely difficult to comprehend.

This problem is made worse because there has been no successful language designed for mainstream programming since C++. Unfortunately this is a political and commercial problem, rather than a technical one. It is hard to promote a language to wide-spread use, and it is expensive to develop one, and no-one has really found a way to make money out of an actual language.

Another cause of this problem is the high barrier to entry for creating a new language. It is much easier for even large and rich organisations to use an imperfect off-the-shelf language than to make and use their own. This is partly a business problem also, but it might have a (mostly) technical solution too.

Why is it hard to make a new language? One reason is that, because a new language is a lot of work, it has to be really good; if languages were more disposable, then we would have to put less effort into making them perfect, i.e., dealing with edge cases. The next big reason is that a language is only as good as its tools and libraries, and non-library code that it ties into. This is kind of a network effect. It actually takes a smart person only a few months to write a commercial strength compiler for a small language. For a bigger language and a good, optimising compiler, you are still only looking at a small team for less than a year. But a language needs more than a compiler, it needs libraries for doing everything from list and string manipulation to network access to running a GUI to IO and on and on. It needs an IDE, it needs a debugger, a profiler. It must inter-operate with local and remote programs in a variety of languages. And all of that takes time and testing.

Some moves have been made on the tools front: we can leverage the likes of GCC and LLVM to make writing the compiler easier, numerous parser generators to make the front end easier, and extensible IDEs like Eclipse. But, we could do much better, it would be nice to be able to quickly and easily generate an IDE without having to develop a new skill set (see Eclipse), even if the result was not quite as fully featured. It would be nice to get a debugger up and running without too much fuss, we need tools for this kind of thing! We really need some kind of language-neutral libraries which can be used quickly and easily by a new programming language (and without having to run on the JVM). And we need a standard, platform-independent way to communicate between languages, and which is efficient, not just inter-process message passing.

I think there are huge technical and non-technical problems to doing this, but how cool would it be if we could quickly and easily use languages without having to worry about mission creep or dedicating a huge team to it and then getting slammed on Slashdot because it doesn't do what everyone wants.

Tuesday, April 10, 2012

A musing on language design - transparency v. readability

People who spend a lot of time thinking about programming languages (and, I think, even just programming) inevitably end up thinking about language design. There is some truism/quote floating around (which I couldn't be bothered to find) about every language theorist having a pet language design secretly hidden in their deepest thoughts. Sometimes that pet language emerges, for better or worse. I admit to having such a pet, but also realise my imagination of a language is nowhere near a real language and the amount of work required to make it real is immense. Also I think real language design is difficult and not very exciting -- too many 'little' decisions about whether an int should convert into a float, or how to handle data transfer between big-endian and little-endian systems, which make me want to bleed from my eyes.

ANYWAY, my musing was on transparency v. readability, which is a much more interesting design decision for a language, at the philosophical/fundamental level. At some point a language designer must aim for readability or 'write-ability'. Generally speaking, 'serious' programming languages (e.g., Java, C#) go for the former, scripting languages go for the latter. Of course everyone wants both, but there are some fundamental trade-offs and you have to privilege one or the other.

One place that this decision manifests is in the 'transparency' (I'm sure there's better word for this) of entities in your language. At one end of the spectrum is Java, where everything must be spelt out, arrays are very different from array-like objects (e.g., ArrayLists), primitives (e.g., int) are very different from primitive-like objects (e.g., BigDecimal), there is no operator overloading, but there are no surprises. C# makes things a little easier with delegates and getters and setters, but basically subscribes to the Java philosophy.

C++ is an interesting case, transparency is much more important here, operator overloading is very flexible and allows user-defined objects to be used (almost) exactly like built-in types, such as ints, arrays, and pointers. Unfortunately, there are a lot of rough edges and it is rare that the programmer can actually use objects like built-in types without having to think about it. Also, being allowed to override assignment etc. can lead to some really evil bugs.

There is a tradition, starting with Smalltalk, and present in most OO-languages to some extent, of "everything is an object". In practice this means there are no built-in types and instead one has object versions of things like arrays, coupled with some form of trickiness to make them easier to use, ideally as easy to use as built-in types should be. Such trickiness is often used to replace things like loops and other control structures with objects too. In theory it means the language can be transparently extended with new control structures. In practice, the trickiness is often difficult to understand, means there are multiple ways to get the same result, and makes the language more complex. Java uses a similar idea to support for each loops.

Scripting languages often take a similar approach, see Python and Javascript. Here many things (e.g., arrays, dictionaries) are ordinary objects, but not quite - the trickiness rears its head so that arrays can be used like a programmer might expect, and you end up with layers of hidden methods and meta-methods, and so forth, which make the language easy to use for casual programmers and allow lots of tricksy programming for those willing to get their hands dirty. This might be a good approach, but this kind of transparency is hardly elegant (well, I guess it kind of is, or neat at least), and the languages are far from simple, or easy to understand in an holistic way.

These scripting languages and those in the Smalltalk tradition (Self, Grace) kind of fill the other end of the spectrum. However, as you can see, it is not really a linear scale from readability to transparency, more different approaches to the same problem, on some multi-dimensional axes.

Is there an optimal solution? Probably not, after all, different languages are used for different purposes. As scripting languages are more and more used for large programs and not just small scripts, I think that a focus on transparency might turn out to have been a poor decision. But there are many other decisions in scripting language design which will turn out to be poor in this situation too.

Perhaps a good question to ask is, is there a problem? Do we really need elegant languages? Could we have a language which was not elegant, i.e., many special cases, lots of different classes of entities, little unification, perhaps that lacked certain kins of transparency, but that was pleasant to write programs in and to read? (Is this in fact, Java or C++) Possibly not, having universal concepts make a language fundamentally easier to understand, but it is also possible that we have gone too far (I'm not definitely saying we have). Are there corpus studies that have investigated how often programmers actually need to mimic built-in types? Is there some compromise level of operator overloading that makes things easier than any of the current positions?

Sunday, April 01, 2012

Memory management, reference counting, and ownership in the Mozilla codebase

Memory management is always an issue in large C++ programs. In small programs with a single programmer, manual memory management is fine (and fast). But in large programs, it is doomed to failure. Garbage collection is the usual solution, and, usually, a good one. But it has disadvantages, namely pauses and slow down, which is not acceptable in system software, such as a web browser (frankly, I would have thought you could do this cleverly and sneak garbage collection in when the browser is quiescent, which happens quite often. But, as browsers are used more and more as software platforms, this becomes less and less practical).

In Mozilla, we use reference counting for memory management. This is a compromise between safety, complexity, and speed. It is fast and there are no pauses, not as fast as manual memory management, but close enough. It is safer than manual memory management, but leaks can still be a problem. And it is much less complex than manual memory management, but an order of magnitude more complex than garbage collected 'fire and forget'.

C++ operator overloading allows for semi-transparent use of reference counting, but logically, you have to keep in mind that objects are reference counted. Transparency doesn't really work. Key to the way reference counting in Firefox works is the idea of object ownership. Object ownership is a subject close to my heart because lots of my research has been around ownership types, which statically enforce the ownership hierarchy which is implicit in the Mozilla system.

OK, now for some details, we'll get back to speculation later...

A reference counted pointer uses the nsRefPtr class, so for a pointer to an object of class C, you would use nsRefPtr. nsRefPtrs are quite clever, they do the bulk of the ref counting goodness, when you copy one the reference count goes up, and when one goes out of scope, the ref count goes down. nsRefPtrs are used to represent owning references, for example, a Layer object owners it's mask layer, so has a field with type nsRefPtr (well, there is no MaskLayer class, but you get the idea). Raw pointers are used for non-owning references, for example, if the mask layer keeps a reference to it's owner, then it would have a field of type Layer*. This is important because it means you can have reference cycles, but indicate which are counted (owning) references and which aren't so the aggregate will still get destroyed when it ought to. We also need ownership transfer, and this is done using already_AddRefed. These are temporary references, where, conceptually, the reference count is not incremented, but the refered to object is kept alive. Or, equivalently, a reference where the reference count is not increased by copying. Note that, when we copy the reference into an nsRefPtr, then the count is increased. So if we have a nsRefPtr field and it is the only reference to an object, then the ref count is one. A geter which returns an already_AddRefed reference to the field does not increase this count, but when we store that reference in another nsRefPtr, the count is bumped to two. However, if we store the reference in a raw pointer, the reference count stays at one. Ownership transfer happens by calling the forget() method on an nsRefPtr, this decrements the ref count and returns an already_AddRefed to the object. Note that if the ref count drops to 0, then the object will not be destroyed until the already_AddRefed also goes out of scope (which is why you should often use nsRefPtrs locally, even if it is just a temporary reference).

There are also getter_AddRefs references for use as 'out' parameters, and dont_AddRef references, which I have no idea about, but I won't go into them here.

So, in summary, we use a fairly sophisticated reference counting scheme which has at its core the concept of object ownership. For this kind of programming, could ownership types help? Well first, you'd actually have to motivate people to get over the extra syntactic overhead of ownership types, and for that you would probably need more benefit than improving reference counting. On the other hand, you only need a pretty lightweight system to help with reference counting. If you could statically enforce an ownership hierarchy, then, together with the system described above, you could be sure to avoid reference cycles and thus many memory leaks. This would be great. I would also hope that you could use the types to simplify the reference counting system, possibly making it more transparent, certainly reducing the number of reference types. But the challenge is that the implicit ownership described above is very unlike most ownership types systems, it is dynamic, supports multiple ownership and lightweight ownership transfer. So this is a non-trivial problem.

So, here is a challenge to language research people - can you come up with an ownership type system that simplifies this style of coding and reduces memory leaks without too much syntactic overhead? This is a great project because there is a huge corpus of real-world code that is constantly expanding and is all ready cross referenced (MXR, DXR) and is all open source, and lots of friendly people have experience applying all kinds of tools to it (unfortunately it will take some Google-fu to track down all the various blog posts about various things, but hey). The Rust language has some concepts for improving pointers, but I hope that we could do better with ownership types. There is real motivation within Mozilla to start using Rust to rework much of the project, so if you are quick, there is opportunity for any research to see real-world use. Anyone keen?

Footnote: if you are interested in finding out more about nsRefPtr look at the nsComPtr docs, they are almost identical, but nsComPtrs are used for XUL objects. The documentation doesn't seem to have been updated to reflect the widespread use of nsRefPtr.

Saturday, March 10, 2012

I was wrong

about syntax - semicolons and curly braces are a good idea.

I used to prefer line breaks to delimit lines of code and indentation to delimit blocks (as in Python, but without the colons, or Haskell). I've changed my mind.

Semicolons are a good idea, because logical lines of code should not be forced to be physical lines of code. It is nice to limit physical lines of code to a certain number of characters, say 80, this is useful for doing side by side diffs, etc. But often a logical line of code will be much longer than 80 chars, especially if you are using descriptive names for functions and variables, which is usually a good idea. Thus, you need to break a logical line into several physical lines, and this means you need a delimiter - enter the semicolon. Also, frankly, it is not much effort to type a semicolon, it is so far down my list of daily worries it barely registers.

My argument for curly braces over indented blocks is much more intuitive, after working on a large-ish Python project, I simply found indented blocks (for large methods/classes) too hard to read. Braced blocks are not perfect either, and can easily be abused, but the make reading easier for me. Perhaps this is just down to habit, after all, I am much more used to reading braced code, but I did a fair amount of Python programming and reading indented code never got easier.

Bonus thing I was wrong about - you will always need style guidelines, you can't hope to always codify such things in the compiler, see combining indentation with braces. But, this is something your IDE should really be doing anyway.

Tuesday, March 06, 2012

Bad langauge features

As a programming languages researcher I put a lot of thought in to what makes a good language, or even what would make the best lanaguge. I have a lot of strong opinions about this (there is a blog post about some of the things, but of the top of my head: optional types, virtual classes, ownership types, first class funtions and an emphasis on functional style programming are a good start), but unfortunately so does everyone else, so it seems unlikely we'll ever see the best language (i.e., the one I think is the best).

The last few days I've been thinking about what would make a really bad language. I don't mean bad for a purpose, some great languages can be really bad if used for the wrong thing (think dynamically typed languages for very large projects, C for high level programming, Javascript as the assembly language of the web). But more, which language features are inherently bad choices in every (or nearly every) situation, and which features interact really badly when put together.

Goto (or it's ridiculous cousin, comefrom) must be near to the top of the list, especially when it's combined with properly scoped features like closures. There has also been some really poor syntactic choices such as sticking a dollar sign in front of variables in Basic or the extreme overloading of symbols in C++. Also Lisp.

More generally any PL behaviour that is surprising is probably a bad choice, such as Java wildcards, non-reifed generics, nearly everything about pointers, static method overloading, some operator overloading, scoping of switch statements, the behaviour of nested classes in Java. Prioritising writability over readability is also a bad idea, although this is more debatable, and not thinking of tools, such as requiring type information to parse C++.

Any nominations for truly terrible language features?

Thursday, February 09, 2012

Tools and the Mozilla shark tank

I've been at Mozilla for a month now, though it hardly seems like it - time has flown by. I've been too busy to blog, although I'm really only starting to get to grips with things, so I don't have much to blog about.

This is my first time working on large-scale software, and on open source software, so there has been a really steep learning curve. One area where I've been learning a lot is tools. A lot of the tools I'm using I've used on small scale projects, but using them on Firefox is a completely different game (Visual Studio, Mercurial, the debugger, IRC). Other tools are totally new to me (patch queues, shell scripts, make) and/or Mozilla-specific (MXR/DXR, try servers, Mochitests, Reftests, Mozilla build system, Bugzilla, Firefox web-dev tools, nevermind a whole bunch of Firefox debugging/testing stuff).

Coding on Firefox is different from anything I've done before. At the moment, the biggest difference is my level of output - I write far less code then I'm used to, and spend a lot more time reading and comprehending existing code. I quite like it, I feel like I'm doing detective work, rather than software development :-) Hopefully, I'll get more productive as I know the code better. Getting to grips with the code-base is made easier by having some really knowledgeable and helpful people in the office and on IRC. On the other hand, there is no formal training/introduction to the code-base or company (yet, apparently). To be fair, I knew what I was letting my self in for: I asked about it at the interview and was told that Mozilla has a 'shark tank' approach to new hires - throw 'em in and see who survives - as Mozilla expands, they are trying to change this.

Sunday, January 15, 2012

Mozilla

I started a new job as a software developer at Mozilla on Monday. My first week was interesting and exhausting - lots of work, but lots of fun too! I am working on porting bits of the graphics back end to use graphics hardware, specifically clipping - at present this is done for rectangle clipping, but we want to support rounded rectangles and general clipping paths. I'll write more about that as I actually do it.

So far, I have mostly been trying to get to terms with the Firefox code-base - it is huge and complex, although surprisingly well-written and organised (not that I expected it to be badly written, but with large, long-running projects, you expect a certain amount of code degradation). It has been quite good fun trying to get a grasp on how it all works (or at least the layout/graphics bits of it I'm working with) - kind of like being a detective. Although I felt like I was drowning in code the first few days, and still whenever I think I understand something, it turns out to be more complicated than I thought most of the time...

I've also been experimenting a bit with writing shaders, OpenGL/GLSL so far, DirectX/HLSL soon. Writing graphics code is fun - pretty pictures!

One of the best things about working at Mozilla so far, is working with smart, enthusiastic, and dedicated people. It feels like a very positive environment. Makes it much easier getting to grips with new code and new techniques, tools, etc.

Wednesday, December 28, 2011

The Kiwi Rule

Driving in NZ is pretty sweet, the only thing that catches out new arrivals is the `give way to the right' rule, aka the Kiwi rule. Simply described, if you are turning left, you must give way to anyone turning right. They are actually getting rid of this rule next year, and I expect it to be carnage, but in the mean time, I find the rule really interesting, for a number of vaguely computer science related reasons.

First of all, assuming people do everything right, it shouldn't matter whether you give way to the right or left, as long as there is a protocol, then everything should work out. Which is our first computer science lesson (or rather software engineering) - you have to design for the error cases too...

When it works, the Kiwi rule is good as it improves overall contention at a junction, although it is a little counter-intuitive why. With give way to the left (the UK/Aus convention), you often get queues where someone wants to turn right, but there is a steady stream of cars coming in the opposite direction, either straight on or turning left (I'm assuming its just a turn off a main road). The car turning right has to wait for a gap in the traffic, which may not come for some time. In the give way to the right system, the car only has to wait until someone wants to go left, which occurs more often than a gap (well, a gap will suffice also). You might think this just means you get a queue on the other side of the road, but the car turning left only has to wait for no cars in the opposite direction turning right, which is actually the common case. So, wait times, and thus queues, are reduced. In comp sci terms, you adopt a clever scheduling algorithm to reduce contention.

Of course, there is no free lunch. Contrary to most road rules, signalling is essential to the Kiwi rule functioning. If someone accidently leaves on their left indicator, when they are actually going straight on, they can cause a crash if someone else coming from the opposite direction thinks they can turn right. Likewise, if the car turning right forgets to indicate and the car turning left therefore doesn't give way. So, for the Kiwi rule, signalling changes the semantics of the protocol, and this means incorrect signalling can lead to crashes, kind of like an unsound type system, or possibly a language where the type system affects the semantics.

So, for the sake of safety over speed, it's probably a good thing it is being scrapped; but I will be sad to see it go, it seems to me like a formalisation of politeness in driving, and fits nicely with the NZ attitude to life.

Tuesday, December 20, 2011

Things not to like about NZ

I seem to spend a lot of time telling friends and family how awesome New Zealand is, so this blog post is meant to be a counterpoint, where I vent my spleen about a few of the things that are bad about living in NZ. Don't get me wrong though, the list of things that are good would be way too long for a post, and moving here was one of the better life decisions I've made.

Sandstone (most important) - a nice sandstone bouldering area would be nice. God I miss sandstone.

It's a long way from anywhere - this is the biggie for me, it's a pain to get anywhere, and especially anywhere interesting. Doing the long weekend in Europe or a few weeks in the Middle East or North Africa, etc. would be really nice.

Tea - we pretty much solved this one by bringing over 500 tea bags whenever we go to the UK, but still, what is the point of Kiwi tea, you can barely taste it, more like a cup of hot water that dreams of being tea when it grows up. I tried using two or three tea bags at once, but it's still not right.

Beer - proper beer, not lager (Kiwi lager is excellent, some of the best I've tasted). Why can't you get a proper ale or bitter in this country?

The climbing walls are all crap - why? I don't know, there are some largish ones, but still they don't seem to be able to get it together properly, surely it's not that hard?

Horrific child abuse - not funny this one. Not sure if its because there's no other crime to report, but torturing your children to death seems a little too common.

Stuff is expensive - I know it's a small market and all, but if I can international mail order stuff retail and pay the postage and tax and it's still 30% cheaper than in the shops, then something is wrong.

Muesli - yet to find a brand I like.

Slow and expensive internet - and not having free wireless everywhere like in a proper country.

Public transport - it doesn't go where you want it to go, and it doesn't go there very often. Airports seem to be particularly poorly served.

The pollen - I really suffer with the hayfever, especially in Christchurch.

Pumpkin - I like pumpkin as much as the next man (probably more in fact), but it would be nice to just once find a vegetarian dish in a restaurant that ddoesn't include pumpkin.

Ozone hole - it would be nice to be able to go out in the sun without feeling like you are being x-rayed.

Sunday, December 18, 2011

Compiling Firefox

A few posts back I described my slightly painful experience compiling Cairo. It was thus with some trepidation that I approached compiling Firefox (which includes Cairo), also on Windows. As it turns out it was a breeze, the only slightly tricky bit being finding the executable at the end. Instructions are here, and they are pretty accurate.

Check out Firefox from the repository of you choice using Mercurial.

Download the Mozilla Build Environment.

Run the Build Environment from the Visual Studio command prompt.

Make Firefox ("make -f client.mk" in your Firefox source directory).

Wait for some time (I left it running over night, not sure how long it actually took, but at least a few hours).

The executable is in the obj.../dist/bin directory, which is nested inside your Firefox source directory.

Easy-peasy huh? Why couldn't Cairo be that easy?