On code style guide

When I write code I follow a very relaxed style guide. The ultimate principle is that every word in your program must serve a purpose. Even consistency is not considered a good thing if it doesn't make code more readable or safe.

1. Comments are not (always) good.

Quite the opposite. The very necessity to write comments means that there is something
wrong with the code (or the language). Don't write comments, write code. If an algorithm is unclear, rewrite it.
If it's too large, decompose it. If it's unclear what a function does, come up with a better name.
If there is a constraint that function parameters need to meet, write this constraint in the language you're using.
As a last resort, write a comment, but remember: your compiler won't read it.

2. Program should be const-correct, but you don't have to use const whenever an object is constant.

If a function parameter points to a constant, it make sense to use const, but it is OK to leave the pointer itself non-const even if it's not modified inside the function: it doesn't really make code more safe, but adds one (useless) word to your program.

If a function argument points to a constant, but it is a simple utility function used only inside one compilation unit, it is OK to omit const. Especially if you would have to write two functions (constant and non-constant) with the same semantics otherwise. You will easily fix this once you really need two separate functions.

3. Inconsistent but right is better than consistent and wrong.

People tend to prefer following a meaningless rule to changing it even if it's clear to everyone that the rule is no longer relevant. This results in ugly code that everyone is afraid to change, because "who knows why it was written like that? I don't believe it was for nothing. The author knew better." and so on.

For new languages it's not that bad, but for languages like C or C++ it's overwhelming how much of so called conventional wisdom there is, that's been irrelevant for decades but still used by programmers of big companies all over the world.

4. There is nothing more valuable than common sense.

You are allowed (and encouraged) to ignore the rule if you see that it's not applicable to your problem. But remember, you are responsible for the code you write. If you don't really know why the rule is there, you shouldn't just ignore it, better be safe than sorry. Having said that, I think it's better if you do find out why and decide whether it applicable or not, don't use this "better be safe than sorry" as an excuse for replicating meaningless garbage.

Common Lisp-style macros in Racket

Today I put myself together and read a couple of sections of Racket documentation. Now I finally know how to implement Common Lisp-style macros in Racket. I'm still not 100% sure it will work exactly as expected but common cases work right.

Here it is:

(define-syntax define-macro
  (syntax-rules ()
   ((_ name fn)
    (define-syntax (name stx)
      (datum->syntax stx (apply fn (cdr (syntax->datum stx))))))))

(define-macro mac
  (lambda (sig . body)
    (cond ((symbol? sig) `(define-macro ,sig ,@body))
          ((pair? sig)   `(define-macro ,(car sig) (lambda ,(cdr sig) ,@body)))
          (else           (error "wrong use of mac")))))

This will give you macro-defining macro mac as in Paul Graham's Arc, except that I defined it in a Scheme way. You will easily figure out how to use it from this example:

(mac (with var exp . body)
    `((lambda (,var) ,@body) ,exp))

(with a 2 (+ a  4)) ; => 6

UPD: In case you want to write a macro that makes use of a function defined in the same file this will not work. But it can easily be fixed by defining this function with define-with-syntax as described here.

Rvalue reference in C++11

Everything I'm gonna say is probably well known or at least it should be. However, when I encountered this, I was very surprised. Enough to be willing to write a post about it.

Look at that piece of code:

template<class T> void append(vector<T> &v, const T &x) { v.push_back(x); }

template <class T> void append(vector<T> &v, T &&x) { v.push_back(move(x)); }

vector<string> v;

string s = "a magic string";

append(v, s);

What do you think s will be after append(v, s)? Well, there is no surprise here yet, it's "a magic string".

But if we change the code so that append would add x to a global vector:
vector<string> v;
template<class T> void append(const T &x) { v.push_back(x); }
template <class T> void append(T &&x) { v.push_back(move(x)); }
Then a magical thing will happen. In this case type T in the expression append(s) will be deduced as the rvalue reference to string, not const reference to string. So s will be no longer valid after the call to append(s).

If you want to be sure, that s is moved only when you write move(s), or when you call append with a temporary, you must write another version of append, that doesn't do anything except calls append(const T &): 

template<class T> void append(T &s) { append<const T &>(s); }

The more I learn about C++11, the more I love it!