nuthole.com "above us only ''Bob''"
contact:email
subscribe:feed
follow me on twitter:twitter
compute / programming / jack.expressiveness
Powered by Blosxom
Get Firefox!
geourl
subgenius
spampoison hosting rails

huge volumes of pointless syntax

posted by jack at 09:22 CET in / compute / programming feed

It's high time for the next installment in my irregular series of C++ rants. This time I'm going to talk about expressiveness (or rather, C++'s lack thereof)

Expressiveness indicates a capability to accurately and briefly express something. A human being is considered to be expressive if they are able to speak in such a way that someone listening to them can quickly understand the person's message. A computer language's expressiveness is a measure of how quickly a programmer can write code that is unambiguous and a correct reflection of the design in the programmer's mind.

Let's illustrate this with an example. Imagine we've got a class with an instance variable containing an array (or list, or vector, or what have you) of some other type. We want to give our class a method that takes another array, iterates through all the objects in it, and adds them to its own array. Obviously this is a contrived example, since nearly all container classes in all languages must include functionality for adding the contents of one array to another, but the point here is to demonstrate how a simple iteration is done.

Let's start off with the C++ version, something like this:


class ValueContainer
{
    // a vector containing Value objects
    std::vector<boost::shared_ptr<Value> > m_values;

    void addValues(std::vector<boost::shared_ptr<Value> >values)
    {
        // an iterator pointing at the first value
        std::vector<boost::shared_ptr<Value> >::const_iterator it = values.begin();
        // an iterator pointing at the special "end" value indicating we've reached the end
        std::vector<boost::shared_ptr<Value> >::const_iterator endIt = values.end();

        // step through the entire array
        for (; it != endIt; ++it)
        {
            // add the value to our array
            m_values.push_back(*it);
        }
    }
};

Some of you may be unfamiliar with the boost::shared_ptr stuff in there. The boost project is a sort of proving ground for classes that are probably destined for the standard c++ library in the future, and shared pointers are a very valuable concept that make c++ development a little more do-able, by helping you manage object ownership.

Anyway, that's quite a pile of code, isn't it? All we're doing is walking through a list of things!

Some may balk at this, saying that the boost shared pointers are overkill here. OK, fine, let's take those away, and take away the comments, and stuff all we can into the for, getting this down as tight as we can:


class ValueContainer
{
    std::vector<Value> m_values;

    void addValues(std::vector<Value> values)
    {
        for (std::vector<Value >::const_iterator it = values.begin(); it != values.end(); ++it)
        {
            m_values.push_back(*it);
        }
    }
};

Now let's see how a similar class might look in python:


class ValueContainer:
    def __init__(self):
        self.values = []

    def addValues(self, values):
        for v in values:
            self.values.append(v)

Unlike C++, Python has no free-standing declarations of instance variables--they're defined only as they're referenced inside of methods, and the best practice is typically to provide an initial definition inside the initilializer method __init__ as I've done here.

There are several nice things about Python that this highlights:

  • the syntactic indicator that we're dealing with an instance variable by always prepending self.
  • the more sensible method names in Python's array class compared to C++'s std::vector class (append vs push_back)
  • the values parameter isn't statically typed, so it doesn't need to actually be a standard python array, but can be any class that implements the methods required for iteration
but the big win I want to point out here is really the difference in the for constructs.

Look at the mass of ugliness in the C++ for construct. To start off with, you're forced to declare a variable with a bizarre iterator type. Why should I have to care about that? I'm not using it in any way; that type is completely irrelevant to my code. Later, to iterate I have to use it++, which may not be pointer arithmetic, but at least looks like pointer arithmetic, and that is just so 1985.

Then, take a look at the simplicity of the Python for construct. The designers of Python built iteration right into the language! You simply give for the name of the variable that should be used to hold a value from the array, and the array itself, and off it goes. Behind the scenes, iteration occurs through well-defined methods, and if you're making your own collection class you can define your own iteration scheme, but all of that is completely invisible to a user of the class.

IMHO, this sort of thing is really one of the biggest wins for languages like Python. You get to leave out all sorts of meaningless busy-work, since the language includes useful mechanisms that C-based languages don't, and you are left with the job of programming the actual functionality you're after.

permalink | digg this | slashdot this | add to del.icio.us |
Comments
Re: huge volumes of pointless syntax
AngryMike wrote on Thu, 15 Jun 2006 06:59

Preach it brotha!


[ reply to this ]
Re: huge volumes of pointless syntax
C++ Nazi wrote on Sun, 16 Jul 2006 07:23

Soon death will come to you...


[ reply to this ]
Re: huge volumes of pointless syntax
Ben Pope wrote on Tue, 29 Aug 2006 05:22

Actually, I would prefer the following in C++:

class ValueContainer {
    std::vector<Value> m_values;
    void addValues(const std::vector<Value>& values) {
        std::copy (values.begin(), values.end(), std::back_inserter(m_values));
    }
};

But that's just me.

Don't get me wrong, python has it's advantages, but when you write C++ like C++, and not like C, then you will realise that these simple things can be done just as well, if not better, in C++


[ reply to this ]
Re: huge volumes of pointless syntax
Jack wrote on Tue, 29 Aug 2006 07:18

Fair enough! However, I must point out again that this is a contrived example. The preferred method for python, in fact, would be something like this:

    def addValues(self, values):
        self.values.extend(values)

For any more complex task (doing more than just copying the values as in your code) requiring iteration, you end up needing the exceedingly convoluted iterator in C++.

I did recently see an article where B.S. himself proposed some new features for the next major revision of the C++ language, including the ability to eschew the nasty iterator declaration, effectively replacing this:

        for (std::vector<Value >::const_iterator it = values.begin(); it != values.end(); ++it)

with this:

        for (auto it = values.begin(); it != values.end(); ++it)

That's clearly an improvement, but... well, it's a bit like putting makeup on a pig. It *might* look marginally better, but underneath it's still not a creature you want to spend too much time with. ;)


[ reply to this ]
Re: huge volumes of pointless syntax
Ben Pope wrote on Tue, 29 Aug 2006 11:45

auto has been accepted into TR1, it's coming and it's genuinely useful in this situation.

There are lots of algorithms, adaptors and binders that make loops much easier, but often you end up needing to create a functor just to do some simple task. This is where things like boost::lambda come in, allowing you to create unnamed functions at the call site.

With the exressiveness of boost::lambda, I can think of many examples where large amounts of C++ code and loops can be reduced in size. This code starts to get a little easier to read though, until you're used to it.

The classic example, shamelessly stolen from: http://www.boost.org/doc/html/lambda.html#introduction

is: for_each(a.begin(), a.end(), std::cout << _1 << ' ');

Which doesn't involve any iterator nastiness at all (neither did my previous example).

By embracing the STL, sequences and templates, you can often get away from instantiating specific iterator types in your code.

Some people consider (classic) for loops in C++ almost as bad as goto :)


[ reply to this ]
Re: huge volumes of pointless syntax
Jack wrote on Wed, 30 Aug 2006 04:43

OK, I can see where that's going. I have great respect for the boost project. They have accomplished some amazing things considering what they have to work with (the C++ standard). This is the first time I've looked at the boost::lambda stuff and I have to say I'm pleasantly surprised at what they've enabled.

Yes, they're able to do proper lambda expressions, etc, but at the expense of some frightful syntax. It's not boost's fault, it just accentuates what a poor language lies at the core (quite ironic that C++, which adds such a *huge* amount of stuff to C, doesn't add minimal functionality that would make life easier for programmers in this millenium). We may scoff at things like object-oriented extensions to COBOL, but this is not far-removed. The fact that all these things are *possible* in C++ doesn't mean that C++ is a good language with which to use them, especially when there are plenty of decent languages that have such functionality built-in, and let you work with a syntax that doesn't make the Baby Jesus cry ;)


[ reply to this ]
Re: huge volumes of pointless syntax
Ben Pope wrote on Thu, 31 Aug 2006 03:35

Well I suppose that leads us to another nice library in boost, that will bring us full circle:

You can build your libraries in C++ (with all the advantages the lower level coding brings), and then wrap them with boost.python, enabling you to use a higher level language (guess which one!) to bring together the parts you need, creating applications quickly, but whilst minimising the overhead of a scripting language.

If you haven't seen the following article and are interested in both C++ and Python, then it is a must read: http://www.boost-consulting.com/writing/bpl.html


[ reply to this ]

Your Comment

 
Name:
URL/Email: [http://... or mailto:you@wherever] (optional)
Title: (optional)
Comment:
Save my Name and URL/Email for next time

Looking for programming talent that doesn't make you say "WTF!"? Try the hidden network.