Monthly Archives: January 2015

Emacs as a Python 3 IDE: at last!

Emacs is my editor of choice, I use it to write nearly everything. I have to write Python at work, which I’m ok with since I’m generally a fan of the language. For that I use ropemacs, (with jedi, flycheck and flake8) which makes it possible to use the rope refactoring library from Emacs. Mostly I use it for “go to definition” but its refactoring features are obviously also super useful.

Now, I like new and shiny tech. I run Arch Linux for a reason. I jumped on the C++11 and C++14 bandwagons as soon as I heard about them. So in the Python version debate, if I have a choice I’d go with Python 3 which has been the default on Arch for a while now anyway.

Imagine my dismay when nothing worked anymore in Python 3. My awesome editing environment gone. Rope has a Python 3 version, but ropemacs and ropemode (which ropemacs depends on) don’t. Sadness.

But wait, open source to the rescue! I forked both ropemode and ropemacs and after some porting and much debugging got to something that works: ropemacs_py3k. Enjoy! I know I will.

Type-safety and time intervals in D and Go

My favourite language is now, by far, D. It’s not just not even close. I’ve also been known
to make my opinion on Go be publicly known as “I really don’t like it.”. My work buddy Jeff
is nuts over Go though, and I try not to hold it against him. We keep arguing for “our”
language and disparaging the other guy’s, and it’s all in good fun.

As part of that banter, he sent me a blog post link on Google Plus about flaky tests and what they
tell you about your code. It’s a good read, and exemplifies some of the real-world
engineering problems that happen when developing software. As I read it though, my eyes
roll a bit when I encounter this bit of code:

var Timeout time.Duration
Timeout = time.Duration(conf("timeout", 100)) * time.Millisecond
cache := memcache.New(Servers...)
cache.Timeout = Timeout * time.Millisecond

The first thing I didn’t like about it is that the multiplication by
time.Millisecond looks like C. It’s not that different from
multiplying by a preprocessor macro, with all that entails. Don’t we
know better now? std::chrono from C++ is ugly, but it’s still better
than this.

Related to the C-ness of it, and much more importantly, the second time the code
multiplies by time.Millisecond is the cause of the bug the blog post is about.
And immediately I think: that shouldn’t compile. Maybe it’s my physicist background,
but multiplying time by a time unit shouldn’t work. Or at least you shouldn’t be
able to pass that value to a function expecting a time unit (instead of time squared).

I immediately wrote some D code to make sure I didn’t embarass myself by stating
that in D that would be a compilation error, and to my joy the following code
didn’t compile:

import std.datetime;
void main() {
    auto time = 2.seconds;
    auto oops = time * 3.seconds;
}
foo.d(5): Error: 'time' is not of arithmetic type, it is a Duration
foo.d(5): Error: 'dur(3L)' is not of arithmetic type, it is a Duration

Multiplying time by a scalar works as expected, though, which is what should happen. I showed him the code and he seemed really interested in it, and also wondered
which design decisions led to the current state of affairs. According to him the Go
team likes type-safety, so it seems odd. He also asked me if it would be a compilation
error in Haskell, to which the answer was obviously, in Barney Stinson style, “please!”.

I have to admit letting out a rather childish “sucks to be you” at Jeff today in
the office and basking in my elevated sense of self-worth and computer language choice.

Go D! Pun half-intended.

Haskell monads for C++ programmers

I’m not going to get into the monad tutorial fallacy. Also, I think this blog about another monad fallacy sums it up nicely: the problem isn’t understanding what monads are, but rather understanding how they can be used. Understanding the monad laws isn’t hard. Understanding how to use the Maybe monad isn’t hard either. But things get tricky pretty fast and there’ s a kind of monads that are similar to each other that took me a while to understand how to use. That is, until I recognised what they actually were: C++ template metaprogramming. I guess it’s the opposite realisation that Bartoz Milewski had.

The analogy is only valid for a few monads. The ones I’ve seen that this applies to are IO, State, and Get from Data.Binary. These are the monads that are referred to as computations, which sounds really abstract, but really functions that return these monads return mini-programs. These mini-programs don’t immediately do anything, they need to be executed first. In IO’s case that’s done by the runtime system, for State the runState does that for you (I’m stretching here – only IO really does anything, even runState is pure).

It’s similar to template metaprogramming in C++: at compile-time the programmer has access to a functional language with no side-effects that returns a function that at runtime (i.e. when executed) actually does something. After that realisation I got a lot better at understanding how and why to use them.

The monad issue doesn’t end there, unfortunately. There are many other monads that aren’t like C++ templates at all. But the ones that are – well, at least you’ll be able to recognise them now.

Tagged , , ,

Unit-tested, acceptance-tested, type-checked and yet still buggy

So I wrote an MQTT broker once (twice really, but I never really finished the second version). It’s now my go-to way of learning a new computer language. Once Rust finally makes it to version 1.0, I’ll write an MQTT broker in it as well. It’s a problem I know well now, it tackles the hairy problems of networking and concurrency, and it’s small enough to not become a huge time sink. So that’s how I decided to try and learn Haskell.

With the immense paradigm shift that came with learning Haskell came a much longer development time. I’m ok with that, especially given that the code is so much shorter. This time I decided to BDD the whole thing, using Cucumber to drive the acceptance tests and writing unit tests for the rest.

After much toiling and trying to wrap my head around monads (I finally understand them! It only took months of reading multiple different blog posts and using them…), I got a version that compiled and passed all tests. A working MQTT broker! So let’s run Jeff’s benchmark on it to see how it compares with the implementations in other languages and… oops.

The program hangs. I try again with 10 messages and 2 connections. It still hangs. How can this be? I did my due dilligence, didn’t I? Aren’t Haskell programs just supposed to work if they compile? I mean, I had to jump around hoops to write a function to convert character literals into Word8 values so write my tests! After a lot of “printf” debugging (the Haskell debugging experience is not ideal) I find what’s causing the bug, and as always, it seems obvious in hindsight.

Networking is dirty, ugly and variable. Not the kind of thing that lends itself well to being unit-tested. So I cheated a bit. The part that dealt with client connections and whether or not the server should disconnect went into the main loop and wasn’t unit tested at all. I felt bad about it at the time but let it go on one of those “it’s ok, I know what I’m doing” feelings. And as usual, I break my own rules at my own peril.

I had an acceptance test for it, and it passed. It just wasn’t comprehensive enough. The TCP traffic has to be just so to trigger the bug, and it’s actually hard to craft packets that look like real-world usage scenarios. Who wants to have a list of bytes 512 bytes long in their test code, much less several of them?

My conclusion of the error of my ways? Not enough unit-testing. Too much code outside the nice, warm and fuzzy pure core. The feeling I shook off about the dirty networking code not being unit tested? I’m never doing that again. The fix is going to be relatively simple: purify as much of the code as I can so it’s trivially unit-testable and have the “real” code be a thin wrapper over the pure code.

The worst is that was already my belief of how to develop robust software. I just didn’t follow my own advice.

Tagged , , ,