-
Recent Posts
Links
Archives
- May 2012
- April 2012
- March 2012
- January 2012
- November 2011
- October 2011
- September 2011
- August 2011
- July 2011
- June 2011
- May 2011
- April 2011
- March 2011
- January 2011
- December 2010
- November 2010
- October 2010
- September 2010
- August 2010
- July 2010
- June 2010
- April 2010
- March 2010
- February 2010
- January 2010
- December 2009
- November 2009
- September 2009
Author Archives: Jim Nelson
The 100,000 line question
Clinton Rogers (Yorba developer and all-pro Telestrations master) pointed out something interesting yesterday. Ohloh now lists Shotwell as having achieved an odd milestone just ten days shy of its third birthday: Shotwell has reached 100,000 lines of code. That number represents the work of 51 code contributors and 89 translators. (It also represents blanks and comments — 100,000 lines of pure code is a ways off.)
It’s an odd milestone because there’s a rosy tradition in computer programming of honoring tight code and efficient algorithms. The code placed on pedestals are not thousands of lines long, they’re short and sweet, like a witty joke or a clever haiku. Duff’s Device is my favorite example; you probably have your own. (Tom Duff’s history of his Device is a great short read and offers a basketful of concise observations on code optimization.)
Which is why reaching the 100,000 mark makes me simultaneously proud and a little uncomfortable. Shotwell has grown quite a bit in three years — but is it really doing the work of 100,000 lines of code? Ur-spreadsheet VisiCalc was also 100,000 lines of code, pretty lean compared to the Macbeth that knocked it off its throne, Lotus 1-2-3 (clocking in at 400,000 lines). Compare that to the original Colossal Cave game, which was (gulp) 700 lines of FORTRAN and 700 lines of data. It later grew to a whopping 4,800 lines of code and data that ran entirely in memory. 100,000 lines of code feels downright luxurious, even bourgeois, in comparison.
(I’m not claiming Shotwell should be placed alongside these landmarks. It’s just interesting to consider what 100,000 lines of code represents. I’m also aware that there’s a number of people who think line count is a misleading, or even useless, metric. I do think lines of code provides some scale of complexity and size. I’ve never seen a program grow in size and get simpler.)
There’s probably no reason to duck my head in shame. Sure, there’s plenty of features we want to add and bugs we want to squash, but those 100,000 lines of code we have today are pulling a lot of collective weight. They include the basic organizer, a nondestructive photo editor, a standalone image viewer (which also includes an editor), hierarchical tagging, stored searches, ten plug-ins, and plenty more. Could we scrape away 1,000 lines of code and still have the same functionality? Almost certainly. 10,000? I can think of a few places where fat could be trimmed, but I don’t think it’s excessive.
Note that Ohloh is counting lines of Vala code, not the C generated by valac. Although valac does not exactly produce sparse output, it’s worth mentioning that sloccount reports over 720,000 lines of C code generated by Vala. If Vala is producing on average six times more C code than a competent human programmer (and I’m not asserting it does), that’s 120,000 extra lines. Reducing that by the magic factor of six means Vala saved us from writing 20,000 lines of C code, a victory worth popping open a can of beer and celebrating over.
A few of my favorite Vala things: interfaces
In my prior post on Vala’s language features, I discussed enums and how I appreciated Vala’s implementation of them. I feel that Vala’s enums straddle an interesting line of utility and pragmatism. It took me a while to learn about their features, partially because documentation has been sparse (but is getting better) and partially because as a C / C++ / Java programmer, I’d had hammered into me a set of expectations about enums that Vala didn’t quite adhere to. (I had a similar learning curve, for many of the same reasons, about Vala’s lock keyword.)
Learning interface in Vala was a similar experience. Consider the Java Language Specification’s opening statement about interfaces, which Vala’s interfaces look to be a descendant of:
An interface declaration introduces a new reference type whose members are classes, interfaces, constants and abstract methods. This type has no implementation, but otherwise unrelated classes can implement it by providing implementations for its abstract methods.
Compare to this statement in the C# Programmer’s Guide:
Interfaces consist of methods, properties, events, indexers, or any combination of those four member types. An interface cannot contain constants, fields, operators, instance constructors, destructors, or types. It cannot contain static members. Interfaces members are automatically public, and they cannot include any access modifiers. … The interface itself provides no functionality that a class or struct can inherit in the way that base class functionality can be inherited.
What’s interesting about Java and C# interfaces is what they can’t provide: implementation. Interfaces are often touted as a sane solution to the problems surrounding multiple inheritance, but it always struck me as odd (and a bit of a blind-spot on the part of their boosters) that interfaces provide no reusable code. After all, isn’t that the name of the game? Especially for a technique that’s replacing a form of inheritance, which is all about reusable code?
(I have a pet theory that if one was to study the history of the development of software development technologies — languages, tools, paradigms, all of it — it’s primarily a history of reusable code. How much money and manpower has been dumped into this holiest of Holy Grails: write once, debug a bit more, reuse a billion times.)
Like enum and lock, Vala offers an interesting interpretation of interface with a couple of surprises. I’m not sure how much of it is due to the mechanics of GTypeInterface, Vala’s influences from Eiffel, or simply a reflection of Jürg’s vision, but it’s cool all the same.
Let’s start with a simple Vala interface that looks familiar to any Java or C# programmer:
interface Agreeable {
public abstract bool concur();
}
In-the-know Java programmers will say that the public and abstract keywords are allowed but not required; in C#, they’re simply not allowed. But in Vala, neither are optional:
interface Agreeable {
bool concur();
}
produces this compiler output:
error: Non-abstract, non-extern methods must have bodies
That seems to suggest that non-abstract, non-extern methods in interfaces can have bodies (“must implies can”, kind of a programmer’s variant of Kant’s argument from morality).
And sure enough, this will compile:
interface Agreeable {
public bool concur() {
return true;
}
}
What’s going on here? Simple: reusable code.
Vala interfaces are much more than hollow declarations of required methods. Interfaces are full-fledged members of the object hierarchy, able to provide code to inheriting classes. The reason an interface is not an abstract class is that an interface has no storage of its own, including a vtable. Only when an interface is bound to a class (abstract or concrete) is storage allocated and a vtable is declared. In other words, while the above is legal, this is not:
interface Agreeable {
bool yep = true;
public bool concur() {
return yep;
}
}
gets you this:
error: Interfaces may not have instance fields
Bingo. That boolean is a member instance, which requires instance storage, which an interface does not have by itself.
So what good is allowing an interface to provide reusable code if it has no fields of its own? There’s a number of patterns of use, in particular Facade-style methods. For example, an interface could declare a handful of abstract primitive methods and offer a helper method that uses them in concert according to contract:
interface Agreeable {
public abstract bool concur(int i);
public abstract string explanation(bool concurred);
public void process(int i) {
if (concur(i))
stdout.printf("Accepted: %d %s\n", i, explanation(true));
else
stdout.printf("Not accepted: %d %s\n", i, explanation(false));
}
}
class OnlyOdds : Agreeable {
public bool concur(int i) {
return (i & 0x01) == 0x01;
}
public string explanation(bool concurred) {
return concurred ? "is odd" : "is not odd";
}
}
class OnlyMultiplesOfTen : Agreeable {
public bool concur(int i) {
return (i % 10) == 0;
}
public string explanation(bool concurred) {
return concurred ? "is a multiple of ten" : "is not a multiple of ten";
}
}
First, note that the implementations of concur() and explanation() in the classes don’t use the override keyword even though you must use the abstract keyword in the interface. I’m not sure of the reasoning, but so it goes.
Also know that virtual methods, signals, and virtual signals have their own peculiarities with interfaces. I’ll deal with them in another post.
So, a pretty contrived and very silly example, but notice how process() understands Agreeable’s interface and contract and hides those details behind a single method call. This is useful.
Going back to those language specifications earlier, remember that Java and C#’s interfaces cannot contain static methods. In Vala they can:
interface Agreeable {
/* ... */
public static void process_many(Agreeable[] list, int i) {
foreach (Agreeable a in list)
a.process(i);
}
}
This allows for binding aggregator-style code with the interface itself, rather than building utility namespaces or classes. Again, this is useful.
However, if the following code is written:
Agreeable[] list = new Agreeable[2]; list[0] = new OnlyOdds(); list[1] = new OnlyMultiplesOfTen(); Agreeable.process_many(list, 10);
you get this compiler error:
error: missing class prerequisite for interface `Agreeable', add GLib.Object to interface declaration if unsure
What’s this about?
It’s due to another freedom in Vala that is lacking in Java and C#. Vala classes don’t have to descend from a single master class (i.e. Object). Unlike the other two languages, if a Vala class is declared without a parent, there is no implicit parent; Vala registers the class with GType as a fundamental type. If you don’t know what that means, read this. You probably still won’t know what that means, however.
Because Agreeable is declared without a prerequisite class, Vala can’t produce the appropriate code to store it in a tangible data structure, in this case, an array. (Update: As Luca Bruno explains in the comments, this is because of Vala’s memory management features.) This solves the problem:
interface Agreeable : Object {
What this means is that any class that implements Agreeable must descend from Object (i.e. GObject), meaning we need to change two other lines in the code:
class OnlyOdds : Object, Agreeable {
class OnlyMultiplesOfTen : Object, Agreeable {
Although Agreeable now looks to descend from Object, it does not. It merely requires an implementing class to descend from Object. (A subtle difference.) Interfaces can also require other interfaces, and like classes, it can require any number of them:
interface Agreeable : Object, Insultable, Laughable {
Like requiring Object, this means that any class implementing Agreeable must also implement the other interfaces listed (Insultable, Laughable). This does not mean that Agreeable must implement those interfaces’ abstract methods. In fact, it can’t, one place where code reuse can’t occur.
Prerequisites also mean that Agreeable’s code can rely on those interfaces in its own code, and therefore can do things like this:
interface Agreeable : Object, Insultable, Laughable {
/* ... */
public void punish(int i) {
if (concur(i))
laugh_at();
else
insult();
}
}
… where laugh_at() is an abstract member of Laughable, insult() is an abstract member of Insultable, and of course concur() is its own abstract member. In other words, because Agreeable knows it’s also Insultable and Laughable, it can treat itself as one of them.
It’s easy to go crazy with interfaces, prerequisites, and helper methods, but most great languages have their danger zones of excess and abuse — features that are the hammer that makes everything look like a nail. Still, I think code reuse is the most important goal of any programming technology — language, tool, or paradigm — and I’m glad Vala has given it some thought in terms of interface.
The “I use Shotwell as a photo manager” Flickr pool
One tangible reward with writing software is to see your hard work put to practical use. A great place to see Shotwell put to work by “average” users is at the “I use Shotwell as a photo manager” Flickr photostream. I put quotes around “average” because these photos were not produced by average users in any way — whether or not they’re sophisticated computer users, they certainly have an above-average command of light and lens. The next time someone says open-source software hasn’t produced anything useful for the “average” user, send them to this Flickr group’s page.
Browse the entire collection when you get a chance, there are some great ones. I’ve embedded below a few that caught my eye, but there’s plenty more to admire in the almost 400 photos (and counting) in the pool. I can’t say with any certainty how involved Shotwell was in the process of producing these fantastic images, but I like to believe it was more than a little…
New RSS feed
Some time back we moved to WordPress and didn’t create a redirect from our old RSS feed to the new one. I just created that redirect. Subscribers to our old feed should now start seeing posts.
However, the best thing to do is change your RSS subscription to our new feed address: http://blog.yorba.org/feed Thanks!
Why I Like GNOME 3 Shell
Friday night at the c-base pre-registration party Karen Sandler asked me what I thought of GNOME 3, and in particular, the GNOME 3 Shell. Although I’m generally impressed with it and enjoy using it daily, I couldn’t enumerate for her solid, tangible reasons. (It probably had something to do with the bottle of Berliner I was holding.) She asked me if I would blog my thoughts.
Here they are, for whatever they’re worth.
Stability – Considering this is an initial release, I’ve found the Shell to be remarkably stable. I’ve had no freezes or crashes. While that seems like a low bar to overcome, this is essentially an 0.1 release. Not much 0.1 code can make the claim that it’s stable. Most 0.1 code is just happy it compiles.
Performance – When I heard in Gran Canaria that Javascript was a key technology behind the Shell, my thoughts immediately went to scalability — both in terms of performance (the common use of the term) and of code manageability (which is how I use that term some times). I can’t speak to the latter point because I’ve not dived into the Shell source, but in terms of the former, I find the Shell to be speedy and brisk. The only stalls I’ve experienced were when the machine was under load.
Productivity – I should list this first, but I decided to save the best for last. My productivity has jumped since I switched to GNOME 3 Shell. This might be a highly subjective evaluation. I suspect I’m not alone.
I suffer from a common malady, Easily Distracted Syndrome (EDS). Flashy lights, running gauges, televisions tuned to static — anything blinking or back-lit steals my attention away from what’s in front of me. GNOME 3 Shell’s minimal and colorless chrome keeps me focused on the work at hand. This is a good thing. Windows is by far the worst offender, but all desktops are culpable. Jeffrey McIntyre at Slate wrote about this problem in 2008, noting that “Our desktops are now a thick impasto of tabbed windows, pull-down menus, dashboard widgets, and application alerts. No possible distraction gets left behind, no link, feed, IM, twitter, or poke unheeded.” Since computers are supposed to help productivity, changing this state of affairs should be a high priority for any desktop designer.
I like that GNOME 3 Shell doesn’t have a lot of widgets to play with. The Tweak Tool is about is far as it goes, and I’m happy with that decision. With GNOME 2 Shell, whenever I created an account on a new machine, I was in for at least an hour’s worth of work rearranging the desktop to my liking. When I sit down to a GNOME 3 desktop, there really isn’t much to do — but I do twiddle with it. The following are changes I wish would be made to the out-of-box experience:
(Note: I’m sure all of these have been debated ad infinitum in chat rooms and on mailing lists. I’m still going to list them. Think of these as a kind of late vote — open-source hanging chad):
Power Off… – I understand the impulse to stay as minimal as possible, but requiring me to log out in order to power off the machine is frustrating. I use a GNOME Shell extension to add Power Off… and Suspend to the system menu (it also adds Hibernate, which I could live without). I can’t believe I’m the only one grumbling about having to find and install this extension. One of the big guffaws over UNIX’s predecessor Multics was that you had to log in in order to log out. (The myth came about because of a feature that could lock the console, much like screensavers today.) Unlike this bit of Multics lore, make no mistake: with out-of-the-box GNOME 3, you have to log out in order to turn off the machine.
Weather indicator – This is the one distraction from the GNOME 2 Shell I wish was moved to GNOME 3. Yes, there’s a couple of weather indicator extensions out there (here’s the one I’m using), but they’re rough around the edges, hard to configure, and have to be installed separately. If the new Shell can support calendaring in the clock drop-down, certainly it’s not a stretch to have a weather indicator in the top bar as well.
Desktop – Some people never use ~/Desktop for anything. Others store their entire lives in it. I more or less fall in the former camp, but I do keep a few documents on my desktop now and then. Beyond my personal habits, it’s an odd state of affairs that to the user the entire desktop background is an inactive, inaccessible void. Fortunately the GNOME Tweak Tool allows for Nautilus to manage the desktop much as it did in the past. That was the first switch I threw to ON when I ran the tool.
None of this is particularly damning, and in all I think the GNOME 3 Shell designers have done a great job. Certainly I wouldn’t call it an “unholy mess” and then demand that the designers add features back, as though the way to clean a room is to toss more stuff on the rug. With a few careful additions here and there, the experience would be just right.
I keep going back to the productivity gains I mentioned earlier. Perhaps that’s the best compliment I can pay to the group: Your creation stays out of my way, which is exactly what I want.
Yorba at Desktop Summit in Berlin
The entire Yorba crew is now in Berlin gearing up for the Desktop Summit at historic Humboldt University (a name which means something a bit different to us Californians). If you’re here as well, please be sure to say hi. We always look forward to making new acquaintances and catching up with old ones. Hope to see you around!
Shotwell in Linux Format’s Top 50 Apps
It was a pleasant surprise last week to receive our office copy of Linux Format magazine and discover that Shotwell was named a Top 50 App by LF‘s readership. The editors called Shotwell “a super stable, feature-rich photo manager.” Thanks to everyone who voted for us!
On Novacut
What follows is my opinion alone and does not represent the views of the Yorba Foundation or its employees.
There’s been some noise in the Gnomish blogosphere about Novacut and their recent (and second) attempt at fundraising via Kickstarter. Probably the most slicing criticism I’ve seen yet comes from Danny Piccirillo at The Silent Number, who opens his complaint with this:
I am writing to say that the only way for the ideas behind Novacut to be realized is to stop pretending that throwing $25K worth of funding at it could possibly save the project. …
What Novacut is doing is harmful to free software, especially existing video editors.
I met the Novacut crew at the Orlando UDS last year. They seemed like decent and motivated people who believed in both the power of open source and independent filmmaking. It never crossed my mind that they were somehow, in any way, “harmful” to free software.
I’m not going to delve into my opinions of the Novacut editor or their dmedia project or even open source video editing in general (although I should point out that Yorba has some skin in that game). I do want to express opinions on some larger points, however.
First, if the open source movement can really be so damaged by a few folks trying to raise $25,000 — which in the software industry is pennies in the couch cushions — then open source is doomed. I don’t buy that argument for a minute. One of the professed strengths of open source is its distributed nature, that no project can be shut down or washed out of existence (or do likewise to others, although it might overshadow them due to its success). It’s particularly ludicrous to think that trying to raise a little money is somehow besmirching the name of open source video editors everywhere.
Second, I’ve grown tired of the “Never start a new project!” line of argument:
For the video editor, Jason needs to just swallow his pride and join forces with PiTiVi, as he has been invited to again and again. … PiTiVi has just implemented audio sync and multi-camera alignment, and surely the rest of Jason’s revolutionary ideas can be implemented as well.
My problem with the above statement comes down to one word: needs. If open source is freedom, then it follows that contributors should join projects out of desire — out of freedom — and not due to some perceived imperative.
Of course, it’s easy to dismiss my opinion here because of my involvement with Shotwell, a program I’ve put a lot of hard work into in spite of the viable alternatives out there. This is not a new or convenient opinion for me, though. I’ve felt this way for years now. I could name any number of open source projects that prove my point; you may be using a few of them right now, as you read this. Sometimes starting afresh — tossing out old assumptions, letting go of aging technologies, focusing on new ideas or techniques — results in something useful, interesting, wonderful, or even revolutionary. Alternatives also create healthy competition, which can be even more motivating than $25,000.
Does that mean everyone should simply start their own project whenever they feel the itch? Of course not, but the threshold line between join forces and start afresh is not for me to dictate either. Each contributor should get informed, weigh the alternatives, and then proceed with the decision they’re comfortable with. And, as an informed individual myself, I need to accept that decision — the only imperative need I’m comfortable with in a free society.
Shotwell and GNOME 3
Earlier today I created a new branch in the Shotwell git repository called “gtk3″. This branch holds a version of Shotwell that builds successfully under GTK+/GDK 3.
Due to time and resource constraints, we don’t have plans to have a GNOME 3 version of Shotwell ready for its 0.11 release. The gtk3 branch will be maintained and updated through the 0.11 cycle to keep it from straying too far from the trunk. At some point (most likely during 0.12 development) we’ll merge it back into trunk. At that point, Shotwell will be a GNOME 3 application.
Although Shotwell compiles and runs under GNOME 3, there are some notable outstanding bugs. The ticket title is prefixed with [gtk3] to distinguish them from bugs that cross both versions. The GTK+3-specific issues include:
http://redmine.yorba.org/
http://redmine.yorba.org/
http://redmine.yorba.org/
http://redmine.yorba.org/
http://redmine.yorba.org/
http://redmine.yorba.org/
http://redmine.yorba.org/
We encourage anyone who’s interested in the future of Shotwell under GNOME 3 to try out this git branch. To download from our repository:
$ git clone git://yorba.org/shotwell
$ cd shotwell
$ git checkout gtk3
$ ./configure
$ make
You can run Shotwell from the build directory or “make install” to run from its installed location.
To reiterate, this branch is under active development and not slated for the 0.11 release. In other words, use at your own risk. It’s worth taking the time to back up your Shotwell database before use:
http://redmine.yorba.org/
If you do find a bug or an issue, please let us know by reporting it to our Redmine server:
http://redmine.yorba.org/
If the bug seems to be GTK+3-specific, please prefix the ticket title with [gtk3]. Thanks!
A few of my favorite Vala things: enums
Working with Vala for over two years now, I’ve come to admire more and more of its language features. Some of them were quite surprising when I discovered them, making me wonder why exactly they were implemented this way or that. Once I dug through the learning curve, I came to understand and appreciate their power. One of those language features is enum.
Enumerated types, of course, have been around for quite a while. In many languages they’re little more than auto-generated constant int’s (<cough> C </cough>) while in others they have more type safety and correctness surrounding them (such as Java’s approach, which takes enums to the extreme). Vala takes an interesting middle ground in this field.
On one hand, enums in Vala are much like C’s enums; they can be treated as ints, plain as day, and convert back and forth with amazing ease:
enum Suit {
SPADE,
HEART,
DIAMOND,
CLUB
}
void main() {
Suit suit = Suit.SPADE;
int i = suit;
stdout.printf("suit=%d i=%d\n", suit, i);
}
Personally, I’d prefer it if at least a cast was required, but that’s a nit.
What’s useful about enums is that Vala provides an automatic to_string() method for them, just like int, but with a twist:
stdout.printf("suit=%s i=%s\n", suit.to_string(), i.to_string());
Produces:
suit=SUIT_SPADE i=0
Very handy for debugging! Unfortunately, SUIT_SPADE is not such a great text label for your soon-to-be-famous GTK+ War! card game. It turns out you can override the to_string() method by providing your own:
enum Suit {
SPADE,
HEART,
DIAMOND,
CLUB;
public string to_string() {
switch (this) {
case SPADE:
return "Spade";
case HEART:
return "Heart";
case DIAMOND:
return "Diamond";
case CLUB:
return "Club";
default:
assert_not_reached();
}
}
}
Note some important things here:
- The semicolon must be used to end the list of enumerated values;
- although you’re “overriding” Vala’s built-in to_string() method, you don’t use the override keyword (unlike Java, enums are not a class nor derived from one);
- use assert_not_reached() (or some debugging/logging action) in the default case, as Vala allows for transparent casting of bare ints to enums.
That said, this is pretty slick now. enum now looks more like it’s object-oriented brethren than a third cousin twice-removed. And Vala goes all the way with this, allowing any number of methods (member and static) be added to an enumeration:
enum Suit {
SPADE,
HEART,
DIAMOND,
CLUB;
public string to_string() {
switch (this) {
case SPADE:
return "Spade";
case HEART:
return "Heart";
case DIAMOND:
return "Diamond";
case CLUB:
return "Club";
default:
assert_not_reached();
}
}
public bool is_higher_than(Suit suit) {
return this < suit;
}
public static Suit[] all() {
return { SPADE, HEART, DIAMOND, CLUB };
}
}
void main() {
stdout.printf("%s > %s? %s.\n", Suit.SPADE.to_string(),
Suit.HEART.to_string(),
Suit.SPADE.is_higher_than(Suit.HEART).to_string());
foreach (Suit suit in Suit.all())
stdout.printf("%s\n", suit.to_string());
}
Produces:
Spade > Heart? true. Spade Heart Diamond Club
By riding this middle ground (enums really just ints under the covers, but extensible with methods) Vala offers some of the power and flexibility that a Java-like language has while still producing C code compatible with other languages (useful when building a library). In fact, the automatic to_string() method works even with enums from non-Vala libraries (i.e. GLib, GTK, etc.); valac generates the function for you (that is, the library doesn’t have to supply one, although if it does, you can patch it in via its VAPI).
The above code sample points to the other item I would throw on the enum wishlist: either an automatic method (like to_string()) that returns an array of all enumerated values, or simply make the type name iterable:
foreach (Suit suit in Suit)
stdout.printf("%s\n", suit.to_string());
I realize this looks wrong in so many ways, but so does switch(this) when you first encounter it. Whatever the syntax, iterating over all the values of an enumerated type is a common task, and manually maintaining an array (as in the above example) is error-prone.
Addendum: Eric ran into a bug with enums and to_string() that’s worth mentioning: if you call an implicit (i.e. auto-generated) to_string() from within an enum method, you currently have to use this, that is, this.to_string(). The bug is reported here.
Update: There is an outstanding Vala ticket for allowing foreach to iterate over all enums. A patch was recently submitted, so it’s possible this will be coming soon.











