Syntax Matters? (2012)
I agree that semantics are usually more important than syntax in a programming language, but surely syntax can still make a huge difference to both productivity and reliability. Let’s consider a simple example: taking a sequence of integers, and printing out those which are less than 5.<p>Here is how we might do that in Python, a language well known for its clean and simple syntax:<p><pre><code>    xs = [1, 2, 3, 4, 5, 6, 7]
    ys = filter(lambda x: x &lt; 5, xs)
    for y in ys:
        print y
</code></pre>
That seems pretty straightforward to me, though the lambda expression is a little clumsy compared to a language like Haskell that specialises in combining functions neatly:<p><pre><code>    main :: IO ()
    main = do
        let xs = [1, 2, 3, 4, 5, 6, 7]
        let ys = filter (&lt;5) xs
        sequence_ $ map (putStrLn . show) ys
</code></pre>
The output step in Haskell is a little awkward, as we have to be explicit about sequencing the effects, but this is more of a semantic issue than a syntactic one.<p>Now, let’s look at a C++ version. The C++ standard library has provided built-in filtering algorithms ever since its first standard back in the ’90s, but the syntax if you tried to actually use them was so bad that it took me about 15 minutes to even get this example to work:<p><pre><code>    #include &lt;algorithm&gt;
    #include &lt;functional&gt;
    #include &lt;iterator&gt;
    #include &lt;vector&gt;
    #include &lt;iostream&gt;
    
    #define ARRAY_LENGTH(x) (sizeof(x) &#x2F; sizeof(*x))
    
    int main()
    {
        const int xs[] = {1, 2, 3, 4, 5, 6, 7};
        std::vector&lt;int&gt; ys;
        std::remove_copy_if(xs, xs + ARRAY_LENGTH(xs),
            std::back_inserter(ys),
            std::not1(std::bind2nd(std::less&lt;int&gt;(), 5)));
        std::copy(ys.begin(), ys.end(), std::ostream_iterator&lt;int&gt;(std::cout, &quot;\n&quot;));
    }
</code></pre>
This was an attempt to show a like-for-like comparison, though it’s a little unfair because it also shows the semantic problem of distinguishing between built-in arrays and the vector container, and it needs a lot of explicit headers where Python and Haskell both happen to make their filter algorithms available as standard. Still, just look at that remove_copy_if mess. Unsurprisingly, approximately no-one ever actually wrote C++ like this for real.<p>We could tidy that up with a few of the more recent improvements, but C++ is still hopelessly clumsy when it comes to employing standard library algorithms:<p><pre><code>    #include &lt;algorithm&gt;
    #include &lt;iterator&gt;
    #include &lt;vector&gt;
    #include &lt;iostream&gt;
    
    int main()
    {
        const std::vector&lt;int&gt; xs = {1, 2, 3, 4, 5, 6, 7};
        std::vector&lt;int&gt; ys;
        std::copy_if(xs.begin(), xs.end(),
            std::back_inserter(ys),
            [](int x){ return x &lt; 5; });
        std::copy(ys.begin(), ys.end(), std::ostream_iterator&lt;int&gt;(std::cout, &quot;\n&quot;));
    }
</code></pre>
In reality, I suspect many C++ programmers are still just going to write C-style for loops instead for simple tasks like these, and who could blame them? The syntax for the other tools is so bad that programmers will avoid using them, even though the underlying semantics of that copy_if are no different to the clean one-liners in Python and Haskell.