Having it all: Pythy syntax for C++

This entry is part of a series, Having It All»

As I’ve been dreaming about the future of C++, I’ve started to ask myself, “what if we could have it all?” What if we could write C++ code with the agility of Python programmers, and still have all the static checking we really want, when we want it?

I’ll be honest with you; I haven’t been all that excited about the future of C++ recently, in large part because of the ever-growing weight of syntax that we use to describe our interfaces. Today it’s rvalue references and noexcept. Tomorrow it’ll be concept constraints and who-knows-what-else? It’s a drag.

At the same time, I love static checking. I’ve never been able to refactor fearlessly in any Python program of substantial size, because everything is “too squishy:” there’s no way to describe interfaces and constraints to the compiler, so it never complains. I need a solid type system against which to pivot in order to feel like I am in control. (No, runtime tests, as important as they are, don’t really do it for me).

Well, I think there’s a path to having it all. Won’t you come with me on a ramble through some ideas for the next version of C++?

A Simple Example

People love writing in dynamically-typed languages because they don’t have to deal with type information when the implementation of a function often makes what it’s doing patently obvious. For example, check out this Python method:

def min(x, y):
    return x if x < y else y

This two-liner returns the minimum of any two objects. It’s completely generic. Now let’s look at the same function in C++03:

template <class T, class U>
return_type min(T x, U y)
{ return x < y ? x : y; }

Hmm, now we already have a problem: what’s return_type? Given a common_type trait (now standard in C++11), maybe we could use that:

template <class T, class U>
typename common_type<T,U>::type min(T x, U y)
{ return x < y ? x : y; }

This is already getting quite difficult. C++11 core language features appear at first to make this marginally simpler:

template <class T, class U>
auto min(T x, U y)->decltype(x < y ? x : y)
{ return x < y ? x : y; }

Unfortunately, as Daveed points out in his comment, it’s even worse than that: because decltype is operating on an lvalue, the version above returns a reference to a temporary! So we’d actually need this:

#include <type_traits>
 
template <class T, class U>
auto min(T x, U y)
    -> typename std::remove_reference< decltype(x < y ? x : y) >::type
{ return x < y ? x : y; }

Q: What is all that syntax buying us, as programmers?

A: Nothing. We can see how to crank it out by inspecting the python program; it’s just boilerplate. Frankly, the compiler ought to be able to do that for us.

How About Lambdas?

We can actually get a little closer to Python by using a C++11 lambda expresion:

auto min = [](int x, int y)
{ return x < y ? x : y }
 
int three = min(3, 5);           

Now we’re in the right ballpark. Even though it’s not really a function (lambdas create callable “function objects”), we can use it like one.
Unfortunately, there’s one glaring deficiency in that version: it only works for ints. As a matter of fact, it’s only one character shorter than the corresponding inline function:

inline int min(int x, int y)
{ return x < y ? x : y }

The problem, of course, is that a lambda can’t declare a templated function call operator.

What, No Polymorphic Lambdas?

That’s right, in C++11, a lambda expression has to declare its argument types. Seems crazy, doesn’t it? Contrary to reports elsewhere, there’s an honest-to-goodness technical reason that we don’t have them: nobody could figure out how to integrate polymorphic lambdas with concepts (see section 5.1 of N1968), which were at the time to be a flagship feature of C++11.

But, but, but… concepts didn’t make it into C++11, so surely we can have our polymorphic lambdas, now? Not so fast. There are still a lot of people who want the concepts feature, and none of us want to add anything to the language that might be incompatible with concepts. Fortunately, I think we’ve had a little breakthrough on that front, which I’ll get into in detail in my next article. For now, please imagine that the incompatibility with concepts has been solved, and there’s no technical obstacle to a polymorphic lambda expression in some future version of C++.

OK, polymorphic lambdas!

So if the door is open for polymorphic lambdas, we could get rid of the type declarations and write min this way:

auto min = [](x, y)
{ return x < y ? x : y }

Hmm, but this isn’t quite what we were after. Because it’s what lambdas do, this min is a function object equivalent to:

struct anonymous
{
    template <class T, class U>
    auto operator()(T x, U y) const->decltype(x < y ? x : y)
    { return x < y ? x : y; }
} const min;

That’s great as far as it goes, but it’s not the same as a function template. For one thing, you can’t overload it. What we really wanted was something equivalent to:

template <class T, class U>
auto min(T x, U y)->decltype(x < y ? x : y)
{ return x < y ? x : y; }

Well, if we can write lambdas that way, why not regular function templates? We can make this a legal syntax:

[]min(x, y)
{ return x < y ? x : y }

Whoa; that’s shorter than the Python!

More Details

If you’re nervous about the copies this min function could create, you might want to pass references instead. The syntax handles that:

[]min(const& x, const& y)
{ return x < y ? x : y }

If you’re bothered by the increased bulk implied by seeing const& everywhere, just hang on. We’ll talk about “compile-time copy-on-write” soon.

Can We Really Do That?

Of course, getting it done in standard C++ depends on a lot of things (like convincing the committee to vote for it), but from a technical standpoint the answer is “yes.” First of all, it fits right into the grammar. When we came up with this idea at the Bloomington meeting, one of the core language wizards, James Widman, sat down with us and figured out the few necessary changes. Syntactically, this declaration is a C++11 lambda, but with a name inserted after [], and no type specifiers. Second of all, we believe this can be made to work. I’ve started a project to implement this syntax in Clang (offers of help most welcome).

Next up, we’ll talk about how to make polymorphic lambdas work with concepts.

Entries in this series:
  1. Having it all: Pythy syntax for C++
  2. A Breakthrough for Concepts
Powered by Hackadelic Sliding Notes 1.6.5
Posted Friday, November 4th, 2011 under Uncategorized.

97 Responses to “Having it all: Pythy syntax for C++”

  1. Paul says:

    Actually, Ive found a way to emuluate this type of syntax in C++11. See here: http://pfultz2.github.com/Pythy/

    This is really nice. It now lets you use lambdas inside templated functions. The only thing is, it relies on the fact that non-capturing lambda closures are usually implemented as a class with no members. Otherwise, it could lead to undefined behaviour. Or perhaps, someone else knows a better way to accomplish this in C++11?

      Quote
      1. Whoa. This is really cool!

      2. Why not handle your concern with a static_assert, at least until you find a better answer?

      3. How about deducing noexcept, per https://github.com/dabrahams/mpl11/blob/master/include/returns.hpp ?

      4. How about labelling everything constexpr?

      5. I can’t get this simple program to compile with g++4.7, but clang++3.1 accepts it

      #include <utility>
      #include "pythy.h"
       
      PYTHY(min, x, y) ( return x < y ? x : y; )
       
      int main()
      {
          return min(0, 1);
      }
        Quote
      • I too am having some trouble compiling Pythy-based code. I’m happy to take this offline guys, I’m aaronmcdaid@gmail.com.

        g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3

        I’ve stripped it down a little; the following compiles and I can make a working program with it:

        struct Struct {
            constexpr static auto member = false ?
                   addr([](int x, int y) { return x<y ? x : y; })  : nullptr;
        };

        But if I change it into a struct template, I get error messages

        template<typename T>
        struct Struct { .... same definition as before ... };
        template struct Struct<void>;
         
        error: declaration of ‘constexpr const auto Struct<void>::member’ has no initializer

        For me, clang is worse. I get compilation errors in both cases, and it often crashes the compiler. Bug logged here: http://llvm.org/bugs/show_bug.cgi?id=13752

        Ubuntu clang version 3.0-6ubuntu3 (tags/RELEASE_30/final) (based on LLVM 3.0)
         
        error: use of undeclared identifier 'x'
            constexpr static auto member = true ? nullptr : addr([](int x, int y) { return x<y ? x : y; })
          Quote
        • Paul says:

          You need to use at least clang 3.1.

            Quote
          • So, clang 3.1 is required. And it doesn’t work with any version of g++, correct?

            I did my own experiments, after recompiling g++-4.6 to allow it to accept lambdas inside ‘typeof’ – I simply deleted the lines that emit the error ‘error: lambda-expression in unevaluated context’. I was able to get pythy-style logic with g++-4.6. It’s not pretty, but it shows that that simple error message might be overzealous. I’d prefer if it issued a warning instead of an error – but maybe that would open a can of worms! http://www.aaronmcdaid.com/2012/09/typeof-or-c-please-stop-holding-my-hand.html

              Quote
          • alfC says:

            I have clang version 3.2 (trunk) (llvm/trunk 162891). Dave’s code gives this error:

            $ clang++ -std=c++11 -Wfatal-errors -DBOOST_PP_VARIADICS=1 pythy.cpp

            pythy.cpp:4:1: fatal error: too few arguments provided to function-like macro invocation PYTHY(min, x, y) ( return x < y ? x : y; ) /home/user/usr/include/pythy.h:126:10: note: expanded from macro ‘PYTHY_HEADER’ template<PYTHY_TEMPLATE_ARGS(args)> \ …

              Quote
          • Paul says:

            If you can file issues with this on the github, it will make it easier to discuss them, thanks.

            First, I compiled it with: clang version 3.2 (trunk 161214), with no problems, i’ll try to update my version of clang from the trunk.

            Second, try to compile with these flags:

            clang++ -DBOOST_PP_VARIADICS=1 -std=c++11 -fmacro-backtrace-limit=0 pythy.cpp

            If you can post the full backtrace on github, that would be great.

              Quote
          • alfC says:
            Paul: If you can post the full backtrace on github, that would be great.

            I opened an issue in github: https://github.com/pfultz2/Pythy/issues/2, i think also that github tried to reformat the error messages. Let me know if I can do something about it.

              Quote
          • alfC says:

            @Aaron McDaid, I have a poor’s man implementation of pythy syntax, that works for member functions. However it fails for expressions with lamba functions. In clang I get “fatal error: lambda expression in an unevaluated operand”, so the same error you were getting with gcc 4.6. Do you know of a workaround that works with clang?

              Quote
          • Aaron McDaid says:
            alfC: …. Do you know of a workaround that works with clang?

            Sorry no. I have no real knowledge of clang.

              Quote
      • Paul says:

        Whoa. This is really cool!

        Thanks

        Why not handle your concern with a static_assert, at least until you find a better answer?

        This was something I was actually thinking about putting in.

        How about deducing noexcept, per https://github.com/dabrahams/mpl11/blob/master/include/returns.hpp ?

        Seems like a good idea, I’ll try to add that.

        How about labelling everything constexpr?

        I believe this won’t matter since the function has to dereference a pointer. I believe that can’t be a constexpr since it can lead to undefined behaviour, or am I wrong?

        I can’t get this simple program to compile with g++4.7, but clang++3.1 accepts it.

        Well, gcc treats the constexpr line as just a declaration and wants a definition for it. So it needs to be initialized outside of the class. Unfortunatly, it considers a templated definition to be a redeclaration, so therefore it won’t work in gcc(I think this is a bug). In pythy, I just ignore the problems with gcc, and I treat it as being initialized at declaration(the way clang accepts it). Ultimately, Im not sure which is correct according to the standard. Does a static member require a initilization outside of the class? Clang treats it as being initialized at declaration.

          Quote
    • Paul, I’m visually inspecting your code (don’t have a C+11 compiler around) and fail to see one thing: how are you really supporting return type inference for multi-statement functions? If I write

      PYTHY(foo, x) ( if(x<0)return -1; return 1; ) the thing seems to expand to: ... template<typename T> struct pithy_foo_523 { constexpr static auto *p = false ? pythy::addr() + [] (T x){ if(x<0)return -1; return 1; } : nullptr; }; But the constructed lambda expression [] (T x){ if(x<0)return -1; return 1; } is invalid since it does not explicitly state the return type, and this is only allowed for single-statement lambdas. I'm sure I'm missing something here. Thank you!
        Quote
  2. Paul says:

    I really hope this gets added to C++ soon. This would fix so many problems with lambdas. Currently, lambdas in C++, trap you in a monomorphic box that you can’t get out. So, in C++11, I have to use named functions and Boost.Phoenix, just like I did in C++03.

    I know Bjarne Stroustrup had mentioned adding one new language feature for TR2(which it seems is no longer called TR2). However, polymorphic lambdas is not just a language feature, its more like a “bug” fix. At least, if the committee doesn’t want to add polymorphic lambdas yet, they could at least improve type deduction for lambdas and the use of lambdas as class members, since polymorphic lambdas would open the door to local templates.

    Finally, I think that adding your proposed syntax for functions first, could be a nice transition into polymorphic lambdas.

      Quote
  3. Aaron McDaid says:

    Will these new structures be allowed to call themselves? I say a related question on stackoverflow: http://stackoverflow.com/questions/8595061/is-it-valid-for-a-lambda-to-essentially-close-over-itself

    For example, will this be possible?:

    []fact(n) { return n==0 ? 1 : n * fact(n-1) }

    Also, do you envisage allowing anything to appear inside the []. Will these ‘named lambdas’ be allowed full access to everything outside itself, equivalent to a [&] ? The reason I ask is that the stackoverflow question made me think of [&fact]fact(n) { return n==0 ? 1 : n * fact(n-1) }

      Quote
    • The idea is that these are an exact equivalent to templates written today: there’s a mechanical translation from the pythy syntax to plain ol’ templates. So what you wrote above should be equivalent to

      template <class T>
      auto fact(T n) -> decltype(n == 0 ? 1 : n* fact(n-1))
      {
          return n == 0 ? 1 : n* fact(n-1); 
      }  

      which works today (provided you forward declare fact, but I consider that a bug in the standard that I’m working on having fixed).

      As for things appearing inside [], I guess only if we can find a use for it, and if it’s reasonably consistent with the existing meaning for lambdas. To answer the question about access for yourself, just go back to the mechanical translation.

        Quote
  4. Riccardo M says:

    Interesting article, Dave.

    In C++11, what I find odd is that the return type can be omitted from a lambda function if it is of the form “return expression” whereas this is not case for regular functions.

    The auto keyword should live up to its name and automatically deduce the return type of a regular function if it is of the form “return expression” :) . Consistency is great.

    The following function would then just “work”.

    template < class T, class U > auto min(T x, U y) { return x < y ? x : y; }

      Quote
  5. Daveed says:

    The min template that uses decltype in its return type specification doesn’t work: It returns a reference (because the argument is an lvalue) that ends up referring to a local variable in most common uses.

      Quote
    • Thanks for pointing that out; it only makes the case stronger! Fix applied.

        Quote
    • jameswidman says:

      The library could use some convenience templates to indicate the desired value category in a decltype:

      template<class T>
          typename std::remove_reference<T>::type
          PRV( const T& ); // Yields a PRvalue
      
      template <class T, class U>
      auto min(T x, U y)->decltype(PRV(x < y ? x : y))
      { return x < y ? x : y; }
      

      Another issue: the dependent type decltype(PRV(x < y ? x : y)) is distinct from all other dependent types ([temp.type] p2). Therefore it’s not the same type as the one that would be deduced from the return statement ([expr.prim.lambda] p4). So we would need to make an adjustment somewhere such that it would be possible for a pithy function template definition (with a deduced return type) to match a previous forward-declaration (which would have an explicit return type).

      It’s either that or require a user to type out the return type (rather than having it deduced from the return statement) in every definition that was preceded by a forward-declararation (one that is intended to declare the same entity being defined).

        Quote
      • Or else we could say that if you need a forward declaration for some reason, you can forego pithy syntax. As these are actually templates, the need for a forward declaration should be rare.

          Quote
      • Andy Morris says:

        Additionally, why does the lambda have to be one-line? There is no technical reason it couldn’t in at least unambiguous cases. Just use the same logic as the ternary operator.

        [](int x) {return x < 3 ? 0 : 1;}
        
        [](int x) /* why is a return type required? */
        {
            if (x < 3)
                return 0;
            else
                return 1;
        }
        

          Quote
    • litb says:

      I asked on Stackoverflow for details: http://stackoverflow.com/questions/8195150/why-is-this-min-template-of-cpp-next-at-fault

      Would be glad if some of you could participate!

        Quote
  6. Jason says:

    I just noticed you finally got a favicon. My bookmark bar can now hold more links, because of your efforts :) .

      Quote
  7. Robert Ramey says:

    quote:

    For example, check out this Python method:

    def min(x, y):
        return x if x < y else y
    

    This two-liner returns the minimum of any two objects. It’s completely generic. Now let’s look at the same function in C++03:

    template 
    return_type min(T x, U y){
        return x < y ? x : y; 
    }
    

    end quote

    I’m wondering if this is the best example. To me, the idea of comparing values of two different types would almost surely be a logical error. A more realistic C++ usage example would be:

    template
    T min(T x, T y){
        return x < y ? x, y;
    }
    

    or better yet

    template
    inline const T & min(const T & x, const T & y){
        return x < y ? x, y;
    }
    

    And truth be told – I don’t seen anything particularly burdensome in that. In fact, I see it as extremely efficient. It’s function and operation is transparently obvious without learning anything other than the most basic C programming syntax. It just a typesafe version of the traditional C macro for min. It also makes obvious and explicit certain implementation details – inline and const. Given that C++ automatically will promote a reference to a derived class to a base class, it will also handle sensible conversions. Also it will trap a compile time any usages which are likely to be errors such as

    .. min(apples, oranges) // compile time error – this is a good thing!

    Note that this obvious error would not be detected in either the python or more elaborate C++ examples here.

    So I think this example steers the discussion on the wrong track. When I have to go to elaborate lengths to get what I want and end up without something which isn’t transparent, I have to wonder if I’m really asking for something that I shouldn’t be asking for. That is, instead of reacting with:

    damn ! the system won't let me do this

    it’s time ask myself

    damn ! - is this what I really want to do?

    Of course we’re all enamored with really clever stuff – but at what point does cleverness become an end in itself?

    In terms of the original example: Python makes it easy to do something which likely fails to make any sense in many cases. C++ makes harder to do that something. And C++ makes it more likely that the obvious/simple way to do something is more likely correct in most cases and is more likely to trap a conceptual error at compile time.

      Quote
    • Seth says:
      Robert Ramey: I’m wondering if this is the best example. To me, the idea of comparing values of two different types would almost surely be a logical error

       

      You’d be surprised at the elaborate history of, and the current definition of std::iter_swap, then.

      Especially read [17.6.3.2 Swappable requirements] for fun. It has some good examples too (basically, you should be allowed to swap a straight bool value with one hidden behind a vector proxy. These types, needless to say aren’t identical by any stretch.

      I’d imagine the same kind of genericity is very welcome for our current example min. (In fact, otherwise it wouldn’t be the strong typed version of the min macro, it would be the reduced-functionality version :) )

        Quote
  8. Mark Ramirez says:

    Don’t like the way lambdas are implemented. It was better to skip it in the standard, until a better syntax arrive, and work with templates, the way developers wanted.

    It seems that the lambda “fashion” affected c++ comite.

      Quote
  9. Giovanni Deretta says:

    I’m tired to typing the template<…> boilerplate over and over, so I really love the simplified function syntax + polymorphic lambda extension (even better with the possibility of omitting the ‘return’ keyword);

    Unfortunately there is still an usability difference between lambdas/function objects and plain functions.

    auto min1 = [](x,y) { return x < y ? x : y }
     
    []min2(x, y) { return x < y ? x : y }
    min1 will retain its polymorphic behaviour when passed as to an higher order function, while min2 need to be monomorphised (via an ugly cast):
    [] hof(f, x, y) { return f(x, y); }
     
    hof(min1, 0, 1); // compiles
    hof(min2, 0, 1); // does not compile
    This wouldn’t happen if the named ‘[]‘ was just syntatic sugar for the unnamed lambdas, but as you already described it is not viable.

    I thus propose the following new syntax for passing functions to higher order functions:

    hof([]min2, 0, 1); // compiles
    hof([]min1, 0, 1); // also works, redundant []
     
    template<class T> T min3(T x, T y) {...}
     
    hof([]min3, 0, 1); // also compiles
    the []<identifier> syntax would simply be translated to:
    [](x...) { return <identifier>(std::forward<delctype(x)>(x)...); }
    Or whatever the syntax for variadic lambdas would be.

    Note that, as lambdas can decay to function pointers, the same []<identifier> syntax could be used for arguments to functions taking plain old function pointers: new books could teach the new ‘[]‘ syntax instead of the old ‘&’ for making function pointers/references.

    As a crazier idea, the syntax also opens the option to streamline the handling of member/member-functions:

    struct X {
       int foo;
       float bar();
       long baz(int);
    } x;
     
    ([]X::foo)(x) ; // same as ([](x) { return x.*X::foo; })(x);
    ([]X::bar)(x) ; // same as ([](x) { return x.*X::bar(); })(x);
    ([]X::baz)(x, 0) ; // same as ([](x, y) { return x.*X::baz(y); })(x, 0);
    something which IIRC was considered for C++0x plain member functions but discarded because of compatibility concerns.

    I’m not sure how viable grammar-wise these syntax changes would be , but I can’t see any obvious problems.

    These changes are really orthogonal with your new proposed syntax, but I think it would fit well in a framework of making plain C++ functions more usable/useful.

    More crazy ideas like python-style function decorators in the next episode.

      Quote
    • So… if I understand your idea correctly, []id-expression is essentially a way of capturing an overload set. I actually like this a lot. People have been talking about ways to represent an overload set for a while, but there were never any specific proposals that I can recall. The only thing I don’t like about it is that the variadic template wrapper interface will probably make it harder to add a feature that does introspection about the specific overloads in the set. We can probably cross that bridge when we come to it, though.

      More crazy ideas like python-style function decorators in the next episode

      Is that a request, a promise, or…?

        Quote
      • Giovanni Deretta says:

        Dave Abrahams: So… if I understand your idea correctly, []id-expression is essentially a way of capturing an overload set. [...] The only thing I don’t like about it is that the variadic template wrapper interface will probably make it harder to add a feature that does introspection about the specific overloads in the set.We can probably cross that bridge when we come to it, though.

        Pretty much yes. I expressed it as a transformation to polymorphic lambda+variadic template because it was a simple transformation to convey the intent, but a smarter implementation is of course possible.

        Regarding the []<class>::<member> syntax, after thinking about it more, it should be probably folded in the general []id-expression; syntax. I.e:

        ([]id-expression)(x);
        should map to the first compilable of the following
        x.id-expression;
        x.id-expression();
        id-expression(x);
        thus unyfying (ADL-discoverable) functions, member functions and plain members.

        Is that a request, a promise, or…?

        I promise I guess :)

          Quote
  10. Robert Frunzke says:

    Nice idea, but I can not help myself, the syntax feels so wrong.

    Re-purposing the lambdas here, and then even discarding the types from parameter lists feels wrong. Sorry, wrong on any level I can imagine. Lambdas were not designed to become like this, and the “auto” keyword was purposed for automatic type deduction – instead of “nothing”. … So, … just no …

    From a users (C++ coders) perspective, the objective should be simpler, straightforward, and syntactically composed of things that the “average” or even beginner coder could come up with on its own, e.g.:

    auto min( const auto &x, const auto &y ) { return x < y ? x : y }

    I am very certain, that many beginners will just try to write code like this, it feels worth a try! And it feels like the perfect place for that shiny “auto” keyword ;-) Though we know that its not so easy, much more complicated. But C++ should strive more into directions that seems obvious… syntactically.

    And the trick could be: the compiler treats functions that have at least one “auto” in its parameter list like function templates. Some magic that makes sense, while still being comprehensible.

    It would enable users to write seemingly dynamically-typed functions, the pythy way, and the compiler automatically translates them into function templates. Well, I have no nice solution yet for deducing a return type (decltype also feels so wrong.. but that’s a different issue).

    What do you think about this idea? Maybe a new keyword instead of “auto” would be required. But in the end, lambda syntax is not suited here, even if it makes it seemingly easy to declare dynamically-typed stuff. It will be a confusing and unexpected syntax. IMHO it is better to use the good-old function syntax, because it is a function, not a lambda.

    Or, maybe something that reflects the template-ish character of such a construct, with a new simplified template syntax:

    type min( const type &x, const type &y ) { return x < y ? x : y }

    Just, please not abusing that innocent lambdas.

      Quote
    • Hi Robert,

      Thanks for your post. I guess my feeling is that initial reactions to unfamiliar syntax are important but fleeting. What’s unfamiliar to us will be lingua franca to the next generation of programmers. I’m not sure auto const& x has any lasting advantages over const& x, and over billions of functions, the extra characters add up. More to write, more to read, more to maintain. But in principle, you and I are proposing the same thing, and if writing auto everywhere was required in order to attain community and/or committee acceptance, I could live with that.

        Quote
  11. Pongba says:

    Awesome. Looking forward to c++15

      Quote
  12. dude says:

    Well, it doesn’t quite have the features of C++, but if you want a static typed, native, C’ish language that feels like Python with a couple extra niceties, check out golang.org.

      Quote
    • Yeah, but no value semantics, right? I guess I really need to write that article about what I mean by value semantics…

        Quote
      • Giovanni Deretta says:

        Rust[1], a language from Mozilla fundation, does have value semantics (including destructors) and generics which are missing in Go. The design is till in flux, but a working compiler is already available, so it is more than vaporware.

        [1] http://marijnhaverbeke.nl/rust_tutorial/test.html

          Quote
        • Other important features of C++ that these others don’t have to the same degree: momentum and users. When feeling burdened by the legacy of existing code, It’s always tempting to start over from scratch, but I suddenly am seeing new opportunities for C++ evolution. More on that in an upcoming post.

            Quote
  13. Raindog says:

    Talking about these things is fine and all, but one thing I see C++ suffering from is the amount of time it takes to ratify a standard. Look at the evolution of Java or especially C#. C++ is widely viewed as a dying language because it appears antiquated and the turn around time for even the most minor language features is measured in decades whereas all so called “modern” languages (C#, Java, Python, Ruby, etc) have much shorter turn around cycles. C# is something like 2-3 years for major language features, which, if MS didn’t control it, IMO would have replaced Java quite a while ago.

      Quote
    • Actually, speeding up the standardization cycle is on the committee’s agenda, so stay tuned…

        Quote
    • Seth says:

      Also, Java seems to be an exceptionally bad example over the last few years. Sun/Oracle has been all but rolling over the floor fighting about how to do lambdas right for Java 67 (has it got them now??!) only to do a very very poor job: things appear to have been borked in the area of simple method overloading (yep) creating breaking changes (yep) that are undocumented (yep) and having a reference implementation that doesn’t do what the specs say (yep) and specs that are hopefully wrong seeing how many problems they would bring along.[1]

      I’d pick the C++ standards committee any day!

      [1] See Java Method Overriding Is FUBAR Part 1-5 of ∞: http://weblog.ikvm.net/PermaLink.aspx?guid=f58b4ef6-4077-4f23-a840-b784d28db586

        Quote
  14. If you like type safety, type inference, and lambdas, try Haskell.

    http://haskell.org/

      Quote
    • Yeah, but not if you like mutable value semantics, algorithm specialization, and compiling down to the tightest possible code. I truly admire Haskell, but there’s a reason I blog about C++ :-) . Lot’s of ‘em, actually.

        Quote
      • Warren Harris says:

        All these things are there in haskell (you just have to dig a little deeper for them sometimes). As far as achieving the tightest possible code, that’s possible too. Check out the article on the Mighttpd web server in http://themonadreader.files.wordpress.com/2011/10/issue19.pdf for an excellent case study.

          Quote
        • No, mutable value semantics are definitely not there in Haskell no matter how deep you dig. Haskell—like all good pure-functional languages—goes out of its way to make mutation next to impossible. You can do it, but you have to hide mutation inside a special monad, and it can never appear as a fundamental part of the language the way operator= is part of C++. This choice moves the language sufficiently far from the underlying machine model that it makes some things exceedingly difficult to do efficiently. I’m sure you’ve seen Melissa O’Neill’s excellent paper about implementing the sieve of Eratothsenes.

            Quote
          • Aaron McDaid says:

            I too am a fan of Haskell, in theory, but I do all my real work in C++. (Im)mutability is indeed the big issue. I suspect that C++ could be changed a little to embrace a little immutability.

            (This isn’t a serious proposal, I’m just thinking about some ways to bring some more a Haskell ‘feel’ into C++.)

            Imagine a const method ‘modify()’ that returns a modified version of an immutable object. This would allows us to write this C++ code which is loosely inspired by functional programming.

            auto new_x = x.modify(args);

            If the C++ compiler can prove that x is the only reference to the object (unique_ptr and rvalue_refs come to mind), then it can permit the programmer to write this code, which recycles the variable name x:

            auto x = x.modify(args);

            (Under the hood it might move the old x temporarily to somewhere else, and then call modify on it to copy the result back to where x was.) Some new syntax might be allowed to more efficiently record what is happening here:

            x=.modify(args);

            I think I’d like to see = appearing everywhere a change can occur, to highlight this to the reader of the code.

            For high-level programming this might work well, but when it comes to optimization we will of course want to allow real in-place mutability. For each such ‘immutable’ method, the programmer will be permitted to write one of these optimizing methods.

            This would allow us to give ourselves the illusion of immutability along with efficiency, but it depends on the compiler being able to prove that references are unique.

              Quote
          • Thanks for posting, Aaron.

            =. is a neat idea! That said, I program in a functional style in C++ quite often, and I think it supports that paradigm pretty well already.

            There are two problems with immutability: there’s the performance thing, and then there’s the limit to expressivity. Some things are just easier to write/think about/understand if you have mutation.

              Quote
  15. Jason S. Moore says:

    Hmm…I love C++11! I’m really excited about it. Great work and blog post Dave! Curious about the D programming language though. Andrei?

      Quote
  16. sehe says:

    I can’t help but notice this slight inconsistency:

    [] (int x, int y) { return x+y; }

    Here, the [] ‘announces’ a lambda. The real function of the [] block is actually to contain a new kind of parameter list, explicitely reserved for declaring captured variables. Now, in

    []plus(x,y) { return x+y; }

    it bothers me slightly that we have the ugly [] distract attention from the pure elegance that follows, where it has no real purpose, as a ‘functional generic lambda’ (for want of a better name) can obviously not capture any variables…

    I’d therefore, anyday, choose simple

    auto plus(x,y) { return x+y; } // no -> return necessary */

    I appreciate that 20 years of C++ evolution are making the parser’s job way too convoluted already, so perhaps we could invent/refurbish some other keyword – other then auto – to announce the new-fangled lambda construct, like, e.g.

    def plus(x,y) { return x+y; }       // recognize something?
    implicit plus(x,y) { return x+y; }  // yet another context sensitive keyword,
                                       // 'implicit' evoking the meaning of 'implied types'

    Straying a little further

    let plus(x,y) = x+y;                // expression lambda
    let plus(x,y) = { return x+y; }     // block lambda
    plus(x,y) := { return x+y; }

    I’m sure the language designers will want to start looking at other borrowing-worthy functional programming features like currying, continuation-passing-style… If we are going to have this level of fluency with functional lambda’s, we shouldn’t go without those

    :)

      Quote
    • sehe: it bothers me slightly that we have the ugly [] distract attention from the pure elegance that follows, where it has no real purpose, as a ‘functional generic lambda’ (for want of a better name) can obviously not capture any variables… I’d therefore, anyday, choose simple
      auto plus(x,y) { return x+y; } // no -> return necessary */

      I know what you mean, and I had the same thought. But I’m not sure the grammar allows it without ambiguity, and anyway I figured we’re stuck with [], which is going to look increasingly ordinary in years to come. If we can get some core gurus to vouch for the implementability of—and the committee to accept—a nicer-looking introducer, a change like that is fine with me. But the main point of this article is to make the claim that the feature is possible.

        Quote
      • Dave says:
        Dave Abrahams: I know what you mean, and I had the same thought.But I’m not sure the grammar allows it without ambiguity, and anyway I figured we’re stuck with [], which is going to look increasingly ordinary in years to come.If we can get some core gurus to vouch for the implementability of—and the committee to accept—a nicer-looking introducer, a change like that is fine with me.But the main point of this article is to make the claim that the feature is possible.

        The reuse of symbols in C++ results in readability issues. Future language development should consider the use of more expansive character sets. There is no reason to be stuck with [] in this day and age. In fact it is down right backward.

          Quote
        • jameswidman says:
          Dave: The reuse of symbols in C++ results in readability issues. Future language development should consider the use of more expansive character sets. There is no reason to be stuck with [] in this day and age. In fact it is down right backward.

          Personally, I would not object to:

          
          
          
          
            Quote
          • jameswidman says:

            Heh. In this page that claims to be “UTF-8″, I tried to use a UTF-8-encoded character (U+1D453, “MATHEMATICAL ITALIC SMALL F”), and cpp-next.com truncated the post from that character on!

            So now I do have a reason to object to the use of extended characters: support is not as ubiquitous as it should be!

              Quote
        • I’m all for allowing all kinds of characters in identifiers, but I’m not sure if I’d want to make any ordinary component of the language dependent on typing something I can’t find visually on a US-ASCII keyboard.

            Quote
          • jameswidman says:

            How about U+0192 (LATIN SMALL LETTER F WITH HOOK)?

            On Mac OS, using the default U.S. input source (see System Preferences->Language & Text->Input Sources) you can type it using:

            <option> f

            (You can also see it by enabling the keyboard viewer.)

            On Windows, there doesn’t seem to be a nice built-in way to input the same character. You could use an alternative input method (and frankly, that’s what every non-English speaker has to live with anyway), but people will kick and scream at that.

            So this would only work if there’s an acceptable alternative token. Something like:

            \f (outside of a character constant or string literal)

            … or:

            #f (tweak the opening of clause 16 to make this work)

            Either of these could be transformed into \u0192 during translation phase 1 [lex.phases] (which is also when we transform trigraphs).

            A smart C++ text editor could easily auto-replace an instance of \f with U+0192. (Of course, it should display the actual glyph for that character. I don’t want to risk typing it now after yesterday’s issue with U+1D453.)

              Quote
          • jameswidman says:
            jameswidman: Either of these could be transformed into \u0192 during translation phase 1 [lex.phases] (which is also when we transform trigraphs).

            Oops. Please scratch that sentence. (You can’t transform \f at phase 1 because that’s before we know whether it’s a character constant. And it’s not necessary to transform either of them because both could be treated as alternative tokens (see [lex.digraph]).

              Quote
      • Daniel Wallin says:
        Dave Abrahams: I know what you mean, and I had the same thought. But I’m not sure the grammar allows it without ambiguity, …

        I think it could allow it, since it has to be a definition. You’d just look for the following brace to disambiguate.

          Quote
      • jameswidman says:
        Dave Abrahams: I know what you mean, and I had the same thought. But I’m not sure the grammar allows it without ambiguity [...]

        Even if we were to do the look-ahead for curly-braces, the new grammar must allow for an explicit return type; otherwise there’s no way to declare a function template without defining it. Example:

        []plus(x,y) -> decltype((x+y));
        /* [code that uses plus() ...] */
        auto plus(x,y) { return x+y; } // Ok, *now* you can drop the explicit return type.
        

        So the mere presence of "-> return_type" cannot mean, "use the old syntax for parameter declarations".

        So if we use 'auto' as the introducer, we need some other criterion for disambiguation. And that would seem unfortunate to me, because the whole point of an introducer like "[]foo" was to introduce a very simple & unambiguous syntax.

          Quote
        • Seth says:

          Profound thoughts there. Keeping the ability to declare a function without defining it is clearly the C++ way. However, that might be the decisive factor here: should it keep that tradition?

          Anyways, this particular syntactic sugar is shorthand for a template function anyway; template functions rarely are useful when declared without a body (since the compiler would not be able to instantiate it in another TU). So in fact, I think it is fair to limit the requirement to allow return type declaration to the case where you’d do (partial) template specialization.

          Eeck. See what I did there? I think I just replaced a small question with a bigger one :)

          How would we go about enabling (partial) specialization of these non-lambda Pythy function template thingies (we need a better name)?

            Quote
          • jameswidman says:
            Seth: Anyways, this particular syntactic sugar is shorthand for a template function anyway; template functions rarely are useful when declared without a body (since the compiler would not be able to instantiate it in another TU).

            1) If you don’t declare a pythy function parameter, then there is no use of a template parameter type, in which case there are no template parameters, so the declaration declares a function rather than a function template. Example:

            []f{} // equivalent to void f(){}
            

            2) In the example that forward-declares plus() above, the body of plus() is given later. The point is that, while you need a declaration with a body (i.e., a definition) in a TU that uses a template, you may need to use that template before its definition. But “plus()” is not the best motivating example; think of indirect recursion.

              Quote
          • Seth: Profound thoughts there. Keeping the ability to declare a function without defining it is clearly the C++ way. However, that might be the decisive factor here: should it keep that tradition?

            Hey, you’re jumping ahead, here! :-) . The whole discussion of pythy syntax started in Bloomington because we were thinking about modules, which would make that separation unnecessary and make many powerful new things possible. I will be coming to that in an upcoming article.

            Just to clarify, we’re stuck with supporting existing C++ code, but that doesn’t mean we have to support every awkward tradition in the context of new C++ features.

            How would we go about enabling (partial) specialization of these non-lambda Pythy function template thingies (we need a better name)?

            There’s no partial specialization of function templates in C++ today, and I don’t think we should add it. Even explicit specialization of function templates interacts in surprising ways with overloading. Let’s not expand the problem.

              Quote
  17. Andrzej Krzemieński says:

    This is a really interesting post. I cannot wait to read the next one.

    I remember that at some point the Committee considered allowing two syntaxes for lambdas:

    [](x, y) { return x < y ? x : y; } // for arbitrary functions
    [](x, y)( x < y ? x : y ) // for single expressions 

    That is if the body of the lambda was in parentheses it indicated that we will only write a single expression (otherwise it is a compile-time error) and the return type will obviously be…

    Is there any reason that this “expression” alternative is not feasible?

      Quote
    • You know, I’m not sure. I think it’s a good idea!

        Quote
    • James Widman says:

      It would make things a bit awkward.

      When you use lambda syntax (or pythy syntax) the parenthesized list of function parameters is optional. C++2011 Example:

      extern int x;
      int y = []{ return x; }(); // equivalent to [](void){return x;}()
      

      Pythy syntax works because the initial “[]” tells the compiler’s parser that a very simplified form of parameter declaration grammar is about to be used. It’s so simple that you may use just one token, an identifier, for the entire declaration (So, just “x” instead of, say, “InputIterator x”). But what if that identifier could be interpreted as an expression?

      []foo(i) // declares a parameter "i" (whose type is that of a template type parameter)
      {
      return i; // name lookup finds the parameter "i"
      }
      
      extern int j;
      []bar(j) // Is "(j)" the body of a function that takes (void)?
                 // (i.e., does bar return the value of ::i?)
                 // Or is this an incomplete function declaration?
      

      We could probably come up with a disambiguation rule (just like the rules we already have in [dcl.ambig.res] in ISO C++2011). But I don’t think we want to risk confusing users just so that we don’t have to type “return”.

        Quote
      • Too bad we risked confusing users just so that we don’t have to type “()!”

          Quote
      • Giovanni Deretta says:

        There are two possible easy solutions: either require the ‘;’ at the end of the single expression syntax, to discriminate between body and parameter list, like:

        extern int i;
        []foo(i); // one argument template function declaration
         
        []bar(i;); // nullary function returning the value of i;
        or use the curly braces for both statement and single expression functions and diferentiate the former from the latter by the presence of semicolon an the end of the statement:
        []foo(i, j) { i+j; } ; // returns void
        []bar(i, j) { i+k  } ; // returns i+j
        The difference is very subtle, but it looks good and many mistakes will be caught by the type system, but I suspect that compiler error messages are going to be atrociously bad.
          Quote
      • Andrzej Krzemieński says:

        Well, now I am not sure if I am not confusing some programming concepts. My intention is to use STL algorithms and lambda expressions “expressively”, i.e., I want to be able to express in one line, and clearly – w/o any syntax overhead – that I want to find an element that matches my criterion in a collection.

        Today, I have to write:

        find_if( col.begin(), col.end(), [&]( MyColType x){ return x.a == a && x.b == b; } )
        and I find it ugly not only because I have to specify my type unnecessarily, but also because “return” and even the braces and the semicolon obfuscate the code and bring no value (except for syntactic conformance). This is why I like Dave’s syntax, which would make my search expression read:
        find_if( col.begin(), col.end(), [&](x) x.a == a && x.b == b )

        It is not only about how many characters you type, but also, how easy it is for you to read what my intention was. Technically, this is only a syntax sugar, but lambdas themselves are only syntax sugar for what you were already able to write in C++03 by adding auxiliary classes.

        On the other hand I cannot imagine myself declaring a “stand-alone” function:

        []min(x, y) x < y ? x : y;

        For the same reason. It is just too compact. I need to be able to see that this part of the code defines a function. That this is the name of the function, this is the parameters we will use, and this is what the function will do. In the above example, the elements of the function definition appear to blend. I would rather go for:

        [] min(x, y) 
        { 
          return x < y ? x : y; 
        }

        Or even define some macro only to be able to write:

        X_FUNCTION  min( x, y )
        {
          return x < y ? x : y; 
        }

        Then again, I understand that having two different syntax-es for almost the same thing is confusing in itself. So, given all that, I am not sure anymore what my position is.

          Quote
        • I’ve been using this macro a lot:

           
          // RETURNS() is used to avoid writing boilerplate "->decltype(x) { return x; }" phrases.
          //
          // USAGE: auto function(<arguments>) RETURNS(<some-expression>);
          //
          // Note: we end with a static_assert so the function can be followed
          // by a semicolon.  If we omit the semicolon, editors get confused and
          // think we haven't completed the function declaration.
          #define RETURNS(...) -> decltype(__VA_ARGS__) { return (__VA_ARGS__); } static_assert(true,"")

          As for having two ways to write the same thing… C++ syntax has gotten more and more cumbersome over the years, and it keeps getting worse as we tack on new features. At some point, it’s time for a revolution, where the old forms are still supported for backward compatibility reasons, but they fall into disuse. Has that time come? I don’t know.

            Quote
  18. alfC says:

    Finally, an honest discussion of improving syntax without the pedantic “you can/cannot do this and that in C++, that is not [in the spirit of] C++”.

    Lately I don’t deal with explicit type for the most part but I need to write a lot of factory functions that deduce types of template classes on the fly. For example “auto p = ::make::myobject(arg1, arg2, …);”, p results to be some type like “::myobject<T1, T2, …>”; since this objects are usually mathematical concepts I can understand later what kind of operation I can do with it, without, for the most part, thinking that is ‘exactly’ the type. I only wish there were some default or automatic way of producing a default factories for each object constructor and also nicer syntax (without the need for a new name for the factory, –in this case a specific namespace, ::make–). I think this is the other aspect of syntax simplification complementary to the one you mention for generic function.

      Quote
    • alfC: I only wish there were some default or automatic way of producing a default factories for each object constructor and also nicer syntax (without the need for a new name for the factory, –in this case a specific namespace, ::make–). I think this is the other aspect of syntax simplification complementary to the one you mention for generic function.

      This seems pretty straightforward to me:

      template <class T, class... A>
      T make(A&&... a)
      {
          return T(std::forward<A>(a)...);
      }
       
      struct X
      {
         X(int const&);
         X(X&, char const*);
      };
       
      X a = make<X>(3);
      X b = make<X>(a, "bar");

      am I misunderstanding your problem?

        Quote
      • alfC says:

        Thanks for the suggestion, but I was thinking with this other case in mind (to improve):

          template<class A, class B, class C>
          struct Y
          {
             Y(A const&, B const&, C const&);
          };
          // typical default factory
          template<class A, class B, class C>
          make_Y(A const& a, B const& b, C const& c)
          {
             return Y<A, B, C>(a, b, c);
          }
         
          ...
          auto myY = make_Y(aa, bb, cc); // at least we have auto now

        (maybe template-template class (Y) can help here.) What I mean in my post is that it would be nice not to have to write the explicit factory at all. and furthermore not create a new name for that factory function, for example:

         auto myY = Y(aa, bb, cc); // not Y<...>(aa, bb, cc), not make_Y(aa, bb, cc)
        The objective is of course a non redundant notation that any mathematician would recognize
         auto i = interval(2., 5.); 
        If the there is template class interval (e.g. Boost.Interval) already this is not possible, unless we put an explicitly written factory in a different namespace; too much work for something that should be obvious. — Thanks for your response.
          Quote
        • Sebastian Redl says:

          Here’s something getting somewhere near what you want:

          template <template <class...> class Y, class... Args>
          Y<Args...> make(Args... args)
          {
            return Y<Args...>(args);
          }

          Of course that only works when the constructor’s arguments match up with the template arguments, which is a rather special case.

            Quote
          • alfC says:

            Hey thanks, that covers 90% of what I called a default factory. I knew a combination of template templates and variadic would make it but I never understood completely. Don’t need “return Y<Args…>(std::forward<Args…>(args))” in the return line? (I still don’t handle the new syntax and forwards well.)

              Quote
          • Sebastian Redl says:
            alfC: Don’t need “return Y<Args…>(std::forward<Args…>(args))” in the return line? (I still don’t handle the new syntax and forwards well.)

            Right, forgot to forward the arguments. That should be

            return Y<Args...>(std::forward<Args>(args)...);

            though.

              Quote
  19. arthurprs says:

    Seriously, this kind of C++ code is unreadable.

    We shouldn’t use the new features to make our code even more unreadable (even if we have to type more).

      Quote
    • @arthurps: thanks for your comment… but I’m not sure exactly what you’re saying, here. I’m talking about a proposed language feature (not one of the existing new ones). It’s purpose, at least, is to make code more readable. I gave a few examples that were ugly and unreadable in the current C++11 syntax, but I think where we end up is a big improvement on what we can do in C++ today. Do you really find the following difficult to read once you know that [] introduces a function?

      []min(x, y) { return x < y ? x : y }

      If so, what makes it difficult for you?

        Quote
      • arthurprs says:

        The final code looks good, but look at the others.

        Most of the new features are great, but we shouldn’t abuse it. Of course this short lambda isn’t the case.

          Quote
        • The final code looks good, but look at the others.

          Then I guess you “got” the point of the article :-)

          Most of the new features are great, but we shouldn’t abuse it. Of course this short lambda isn’t the case.

          but…it’s not a lambda

            Quote
      • Dave says:

        []. < <<<< come on, how this ever got incorporated into the standard is beyond me. Would it have been that difficult to use the word Lambda, or something more suitable. If not a character string maybe it is time to expand the character set used by C++. Nothing about the current solution is acceptable, especially if you are a programmer that uses a variety of languages.

        Honestly C++ has a big problem with living in the past. These days code is written on 64 bit multiprocessor machines with enormous amounts of RAM, there is no reason to overload every symbol fifteen billion times or so. It is like the term “idiomatic” doesn’t exist in the standards commity vocabulary.

        As a side note this whole drive to make C++ like a scripting language is a huge mistake in my mind. Sure one can improve the language but what is the point of turning it into Python. Don’t get me wrong there are lessons to be learned from Python and other scripting languages. One of those is that Python is readable six months later. C++ on the other hand seems to be getting worst in some respects.

        In any event I suspect that the standards group fails to acknowledge that C++ static type capability is very important and is the reason the language is often chosen. If it isn’t needed people often reach for Python. By all means improve C++ but don’t abandon it’s type system.

          Quote
        • ech says:

          Dave, there are strong arguments here for easy generic functions. It is not very compelling to dismiss them with “to make C++ like a scripting language is a huge mistake”. Nobody is talking here about abandoning the type system; what is being suggested is Python’s terseness with static type checking.

            Quote
  20. Marc says:

    I thought the post would be about std::future! ;-)

    Somehow, instead of reusing the lambda syntax, I think I’d rather use the auto syntax without the late return type. I am not so fond of hiding types, but happy to let the compiler deduce them.

    I guess I am not that excited about trying to shave off a few words here when C++ forces hardcore contorsions for other things. Say you have a class template where you want to add some code (e.g. a member function) only if the parameter satisfies some property: ideally, you would write the declaration inside some static if (between if and #if), but in C++ you need to use several classes. Variadic templates also introduced a lot of “fun” where you need to create variadic indices to access your arguments. And try processing variadic arguments from right to left: again a lot of fun. Recursion with variadics also usually requires several overloads because of the lack of static if. If you want to have a possibly empty member not take unnecessary space (like the functor in boost::transform_iterator eh?), you need to inherit from a wrapper. Those are just a few examples because I am buried in such code right now, but there are many things in C++ that require more verbosity than a couple types.

    That said, your syntax does look nice, and there is room for a simple syntax for simple cases :-)

      Quote
    • I thought the post would be about std::future!

      Hey, Marc—good point, I changed the title to something less likely to give a false impression.

      instead of reusing the lambda syntax, I think I’d rather use the auto syntax without the late return type

      So, you’d rather write auto than write nothing in that position?

      Say you have a class template where you want to add some code (e.g. a member function) only if the parameter satisfies some property: ideally, you would write the declaration inside some static if (between if and #if), but in C++ you need to use several classes.

      Well, you’d use enable_if. I think Matt Calabrese is the authority on the current state of the art (see this thread and this one from the Boost developers’ list). I’d like to get Matt to write an article or two about that here. But ultimately I think this is part of what we want to address with concepts, which I’m going to address in the next article.

      As for the variadic template stuff, I’d like to see some examples of what you’re struggling with; maybe I can help.

        Quote
      • Marc says:

        (Uh? where did the “quote” link go?)

        I changed the title to something less likely to give a false impression.

        Ah, now I thought you’d posted a second article in the same day ;-)

        So, you’d rather write auto than write nothing in that position?

        I’d rather write the template and types (except for the return type when I want the type of the return expression), but that’s probably just me…

        [function default template parameter]

        Yes, those help indeed, but they just let you disable some function definitions, not (almost) arbitrary stuff (not code inside a function, not a typedef or struct, etc).

        [concepts]

        It would be great to have something like that, which would be more reliable and general than the current type_traits. But I don’t think it would provide the syntax to protect blocs of code à-la #if, it is orthogonal.

        As for the variadic template stuff, I’d like to see some examples of what you’re struggling with; maybe I can help.

        Daniel Krügler already helped on clc++m :-)

        I wanted f(x0,…,xn,y) to return g(h(x0,y),…,h(xn,y)). But basically anything where you don’t just peal the arguments from the left is hard.

        I have functions that take n arguments, either as x0,…,xn or as a pair of iterators. Implement each one in terms of the other one (bonus points if this works well for any iterator_category). Or create a std::array from a pair of input iterators (think transform_iterator) that return temporaries, without any copying (replacing std::array with std::aligned_storage is cheating).

          Quote
        • Marc:

          I’d rather write the template and types (except for the return type when I want the type of the return expression), but that’s probably just me…

          I see.

          [concepts] It would be great to have something like that, which would be more reliable and general than the current type_traits. But I don’t think it would provide the syntax to protect blocs of code à-la #if, it is orthogonal.

          Oh, you want a more general metaprogramming facility, à la lisp macros. Yeah, that would be awesome, and, I think, relatively easy to specify. However, I also think it’s a completely different kind of feature with a very different (and narrower) audience.

          Daniel Krügler already helped on clc++m :-)

          I’m glad. He’s one smart dude.

            Quote
          • Marc says:
            Dave Abrahams: However, I also think it’s a completely different kind of feature with a very different (and narrower) audience.

            Indeed. And even though it probably won’t benefit me much directly, I completely encourage you to continue on your simplification work which could have an impact on a lot of people without changing the language rules all that much. There is space to push in many directions :-)

              Quote

Leave a Comment (post replies using links below individual comments)