rss

C# vs. Python

2

Category : C#, Design, English

That post isn’t a in-depth comparison of the two languages because it would require lot of time and, in the end, I don’t find that sort of thing particularly pertinent. It’s just a side-by-side presentation of the same script, written in both languages, assorted with my « it’s just my opinion »-type of comments.

Without further introduction, here is the Python version :

#!/usr/bin/env python

import dbus, gobject, dbus.glib

NICK = "Kiri"
CHAN = "#riverotte"

bus = dbus.SessionBus()

obj = bus.get_object("im.pidgin.purple.PurpleService", "/im/pidgin/purple/PurpleObject")
purple = dbus.Interface(obj, "im.pidgin.purple.PurpleInterface")

obj = bus.get_object ("org.xchat.service", "/org/xchat/Remote")
xchat = dbus.Interface(obj, "org.xchat.plugin")

away = False

def statuschangementCallback(acctID, old, new):
	global away
	cur_status = purple.PurpleSavedstatusGetCurrent()
	message = purple.PurpleSavedstatusGetMessage(cur_status)

	if (purple.PurpleSavedstatusIsIdleaway() == 1):
		message = "aw"

	message = message.replace(" ", "_")
	if (len(message) > 8):
		return
	serv_id = xchat.FindContext("", CHAN)
	xchat.SetContext(serv_id)
	xchat.Command("nick "+NICK+"`"+message)
	if (purple.PurpleSavedstatusGetType(cur_status) == 5):
		xchat.Command("away")
		away = True
	elif (away):
		xchat.Command("back")
		away = False

bus.add_signal_receiver(statuschangementCallback, dbus_interface="im.pidgin.purple.PurpleInterface", signal_name="AccountStatusChanged")

gobject.MainLoop().run()

And here is the C# version :

using System;
using GLib;
using NDesk.DBus;

[Interface("im.pidgin.purple.PurpleInterface")]
public interface PurpleInterface
{
int PurpleSavedstatusIsIdleaway();
int PurpleSavedstatusGetCurrent();
string PurpleSavedstatusGetMessage(int status);
int PurpleSavedstatusGetType(int status);
event StatusChangedEventHandler AccountStatusChanged;
}

[Interface("org.xchat.plugin")]
public interface XChatInterface
{
uint FindContext(string serv, string channel);
void SetContext(uint cont);
void Command(string cmd);
}

public delegate void StatusChangedEventHandler();

class Plugin
{
const string Nick = « Kiri »;
const string Chan = « #riverotte »;

static bool away;

public static void Main()
{
MainLoop ml = new MainLoop();
BusG.Init();

XChatInterface xchat = Bus.Session.GetObject(« org.xchat.service », new ObjectPath(« /org/xchat/Remote »));
PurpleInterface purple = Bus.Session.GetObject (« im.pidgin.purple.PurpleService », new ObjectPath(« /im/pidgin/purple/PurpleObject »));

purple.AccountStatusChanged += delegate {
int cur_status = purple.PurpleSavedstatusGetCurrent();
string message = purple.PurpleSavedstatusGetMessage(cur_status);

if (purple.PurpleSavedstatusIsIdleaway() == 1) {
message = « aw »;
}

message = message.Replace( » « , « _ »);
if (message.Length > 8) return;

xchat.SetContext(xchat.FindContext(«  », Chan));
xchat.Command(« nick  » + Nick + « ` » + message);

if (purple.PurpleSavedstatusGetType(cur_status) == 5) {
xchat.Command(« away »);
away = true;
} else if (away) {
xchat.Command(« back »);
away = false;
}
};

ml.Run();
}
}

Preliminary

First of all, one may find that the Python code is shorter. But if you remove the boilerplate code (the interfaces and delegate), which could be both autogenerated with a future release of D-Bus Explorer anyway (ad inside ;) ), the overhead is about 3-4 lines ({ } included). So no real advantage there.

Readability != Conciseness

Now for readability. Python has always been praised for being concise and all. Why do I say ‘concise’ there ? Because IMHO conciseness and readability aren’t the same things at all.

When friends show me a OCaml sexy hack, the first thing I reply is « and what does it do ? ». Don’t mistake me, I don’t use OCaml that much and sure these things come with habit, but nonetheless, I’m not completely alien to the programming style and, even with that knowledge, I can’t tell what a « concise » 20 lines OCaml program do. You can call me dumbass but I’m pretty sure I’m not the only one in this case. Anyway, all of this to illustrate that, at least for some people (which I’m part of), these two concepts of readability and conciseness are not equivalent.

Returning to our matter, I think the previous story illustrate the case of the C# example. Indeed, it may not be shorter at first sight but (and I’m convinced about that) even if you never programmed in C#, you know, with a quick glance, what it does. Verbosity is not a bad thing if it’s not extreme (read, VB). Complain about that in comments, with arguments, if you disagree.

Of course, it can hold true for the Python snippet too. This first part was just to clear the idea that conciseness ⇔ readability.

Tackling the binding problems

Now there is another important aspect to take care (in my sense) : language integration. I won’t talk about the ‘global away’ line and the inherent block semantic which I find strange in a « Python is the C programmer best friend » context as it’s more a personal preference. However, since we are talking about C, I just can’t see the design difference between the Python snippet and an equivalent C one coded with libdbus so what’s the advantage to use Python over C for D-Bus ? In fact, what I want to point out is that having binding is good and all, but, IMHO, having integrated binding is better. What do I mean by integrated ? Well, look at the C# code and you will see several things which make Managed D-Bus « integrated » compared to dbus-python :

  • Real polymorphism with interface and genericity (What GetObject is doing ? I don’t care, I have my interface definition for reference purpose).
  • No dbus.Interface, everything is handled thanks to attribute and reflection.
  • Integrated events, not a silly bus.add_signal_receiver() C-ism.

All of that allow D-Bus specific calls to blend more nicely in the rest of the application. To the contrary, I often see Python scripts which look more like a patchwork of different paradigm and convention style.

Having an interface-based way to access DBus’ methods also provides type safety (provided that you don’t fight with your keyboard or that you use the kind of autogenerating tool I described before) and I’m pretty sure your computer who-doesn’t-like-runtime-error will also be happier. And with a tool like D-Bus Explorer you don’t have to search tons of docs for type informations (still ad inside).

This last point is more debatable since it touches the more general philosophy of dynamic typing against static typing. My general stance on that is that, even if dynamic typing simplifies the process of writing the first code, it’s very damageable at the end for several points (which are also valid in our test case) :

  • Type information is « volatile » meaning that, even if you know what that function of yours is supposed to return when you write it down, chances are that you will have to re-read the whole thing (or check the doc, or take a look at the unit testsn or something else time-consuming) later to remember what it does because, well, time and coffee do their job. Whereas in static typing langage, if the API is well made and if you have some sort of auto-completion, you can pretty most always deduce things from the full prototype.
  • Continuing from point 1, it’s even worse for those guys who have to understand what you did before writing their own code.
  • It’s not robust by default : you have to write unit tests to make sure no one is going to screw that part of the code with type mismatch (who said shortness ?).

Conclusion

So, to conclude, even if this post looks like a monologue against Python, it’s not. I understand Python advantages over traditional typed language and, as the first script shows, I even use it to test my ideas. What I wanted to highlight is that I consider Python *not* suited to large applications where several people have to collaborate (especially if there are no strong policy or rigor inside the team). Python as a powerful Bash replacement, yes. Python as a nice framework for testing and prototyping ideas, good, why not. Python as en embeddable scripting language, sure, it’s made for that in a sense. But Python for a large and maintainable application ? No, not for me.

NB: this post is what some might call a (badly hidden) troll. Instead of that, I would like to present this post as an invitation to discuss in comments, so feel free to drop your thoughts.