Stroustrup: A Brief Look at C++0x

A quick overview of the next version of C++ (scheduled for 2009?).

The most interesting language feature is concepts (see previous item).

One of the fundamental goals is to support user-defined and built-in types equally well. This has been a goal of language design for oh so many years now, and we are not there yet. This is a point worth reflecting upon.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Vec v = { 2.3, 1.2, 6.7, 4.5

Vec v = { 2.3, 1.2, 6.7, 4.5 };

Finally! That is one of the current C++ gotchas I hate. Now if only it would let me do this in assignment and not just initialization...

The new use of auto also makes me drool.

They have got tuples wrong.

Tuples are not first class entities in the new C++ standard. This is obviously wrong. What they want to do is to provide special constructor calls for initialization by tuples (remember that an array is just a homogeneous tuple).

So instead of doing this:

template < class T > class vector {
public:
    vector(const tuple < T > &t) {
        resize(lengthof(t));
        for(int i = 0; i &lt lengthof(t); ++i) {
            data[i] = t[i];
        }
    }
};

They want to do something like this:

template < class T > class vector {
public:
    special_tuple_constructor vector(???) {
        ???
    }
};

Their decision means that tuples can only be used in constructors, and nothing else. Which means it would impossible to:

  1. define functions returning tuples.
  2. use tuples as local variables.
  3. provide operations on tuples.
  4. implement the visitor pattern at compile time.

Here is an example of what it would be impossible to do:

//using tuples as return types
tuple < int, double > foo(int i, double d) {
    return {i*2, d*2};
}

//using tuples as variables
tuple < int, double > r = {1, 3.14};

//define a visitor pattern algorithm computed at compile time
template < int N > visit_members(tuple < T > t) {
    do_action(t[N]);
    visit_members < N - 1 > (t);
}

//algorithm for case 0; notice the pattern matching?
template < > visit_members < 0 > (tuple < T > t) {
    do_action(t[0]);
}

C++ must have tuples and functions as first class values; it must also have lambda functions.

More general initializer lists to come

Take a look at N1919 for more on initalizer lists. Since it is categorized under Evolution, I would guess this is for C++1x.

Regarding tuples, a library-implementation based on Boost tuples are included in TR1 (which ships with g++ 4.0). See N1836, page 81 for the proposed standard-text.

But aggregates will not be tuples.

Algorithms specified on tuples will not accept aggregates as parameters; only derivatives on tuples. There is a missing opportunity here: to define algorithms on classes/structs/arrays/<insert your favorite aggregate here> that are independent of identifiers.

In fact, the visitor pattern on an aggregate's member is useful for many situations:

  1. defining a precise 'mark' routine for a garbage collector.
  2. automating the writing of unit tests.
  3. providing introspection programmed at compile time without the help of the compiler.

Without tuples as first class entities, it would be impossible to do all these things.

By the way, would it be possible to invoke a function with an aggregate, instead of separate values enclosed in parentheses? For example:

void myFunction(int i, double d, const char *s);
myFunction{1, 3.14, "foo"};

The block of parameters of a function is nothing more than an aggregate anyway; and it would be really helpful to invoke a function like that, because the body of parameters could be computed by a function and passed as a result to another function. Java already supports the above, although in limited fashion, for array constructors.

Nope

No, I don't think the library tuples/intializer lists will not help in bringing togheter all forms of aggregators. But they will bring some more convenience to programming in C++, and that's something at least :)

By the way, would it be possible to invoke a function with an aggregate
I wouldn't think so, doesn't feel very C++-ish.

If you haven't seen it before, I think you should take a look at The SL5 procedure mechanism (and free ugly google-cache here).
There, procedure invocation is decomposed into fixing environment, binding arguments, and finally invoking. Quite interesting.

But they will bring some

But they will bring some more convenience to programming in C++, and that's something at least :)

Some choices are incomprehensible, especially when superior altenatives exist...

C++ already has first class

C++ already has first class tuples. They can very well be implemented by a library (and classes/objects are as first class as it gets in C++), witness boost::tuple. What's missing is convenient initialization syntax, especially if you actually want a variable arity constructor. So a special "tuple constructor" exactly fits the bill. (Don't forget that good looking language extensions often backfire and require ugly kludges to be useable. Just think of namespaces and Koenig lookup.)

I'm not sure what is meant by "functions as first class values". They are a bit at odds with the execution model of C++, and objects with operator() provide a somewhat useable emulation. Given some syntactic support for constructing such objects in the form of lambda abstraction with lexical closure might be all that is needed. Again, boost::lambda already comes close. I think, some kind of true lambda abstraction has already been proposed.

C++ already has first class

C++ already has first class tuples. They can very well be implemented by a library (and classes/objects are as first class as it gets in C++), witness boost::tuple.

No there not first-class entities even with them being in library TR1 that still does not give them the first-class status, thats like saying C++ functions are first-class entities but there not (even if you overload the function call operator for user-defined types) it's a called a work-around aka language hack.

I'm not sure what is meant by "functions as first class values".

Well there you go, you're not even sure what is meant by first-class entity to suggest that boost::tuples::/std::tr1::tuple make C++ have tuples as first-class entities well they don't and they are library features/additions not a language level feature.

Given some syntactic support for constructing such objects in the form of lambda abstraction with lexical closure might be all that is needed. Again, boost::lambda already comes close. I think, some kind of true lambda abstraction has already been proposed.

You're probably talking about the soon to be successor of boost.lambda Phoenix 2.0.

First-classness and being a

First-classness and being a language feature are potentially orthogonal. Monadic computations are in no way a language feature of haskell (no, really - if you don't believe me, consider that the only monad in the Haskell 98 standard with any language-level support for their existance is IO, and that the do notation is purely syntactic sugar), yet they are first class entities with which the programmer can do as they will.

You are failing to give coherant arguments for template-defined tuples not being first-class entities in C++. I think they're made rather painful to use by C++'s lack of pattern-matching, but that's a separate issue entirely.

boost::tuples are first class

boost::tuples are first class, at least by the conventional defintion:
  • being expressible as an anonymous literal value
  • being storable in variables
  • being storable in data structures
  • having an intrinsic identity (independent of any given name)
  • being comparable for equality with other entities
  • being passable as a parameter to a procedure/function
  • being returnable as the result of a procedure/function
  • being constructable at runtime
#include<boost/tuple/tuple.hpp>
#include<boost/tuple/tuple_comparison.hpp>
#include<boost/tuple/tuple_io.hpp>
#include<iostream>
#include<string>
#include<vector>

using namespace boost;

template<class Fst, class Snd>
tuple<Fst, Snd> operator+(tuple<Fst, Snd> x, tuple<Fst, Snd> y)
{
    // returnable as the result of a procedure/function
    // constructable at runtime
    return make_tuple(x.get<0>() + y.get<0>(),
                      x.get<1>() + y.get<1>());
}

int main(int argc, char* argv[])
{
    tuple<int, double> foo(1,  3.1415); // storable in variables
    tuple<int, double> bar(41, 2.7182);

    std::cout << foo+bar // passable as a parameter to a procedure/function
              << "\n";

    // expressible as an anonymous literal value
    std::cout << tuple<std::string, float>("Hello", 1.414f) << "\n";

    // comparable for equality
    std::cout << (foo == foo ? "true" : "false") << "\n";

    std::vector<tuple<int,double> > baz;
    baz.push_back(foo); // storable in data structures    
    
    return 0;
}

boost tuples are not first class, aggregates are not tuples.

First of all, tuples are not first class, because code like {1, 2} + {3, 4} is not legal C++.

Secondly, C++ aggregates are not tuples (and certainly not boost tuples anyway).

Tuple literals

You seem to be objecting that there is no literal syntax for tuples? That's not usually a requirement for first-class citizenship---consider first-class continuations in Scheme or SML...

Tuple literals

Well, 5 is of type int. What is the type of {1, "a"}?

Either all literals must have a type or no literal has a type. Otherwise, the language is inconsistent.

Inconsistent

The C++ language is extremely inconsistent in this regard, starting with: what is the type of 0?

"First-class" and "supported by special grammar" are independent properties. In Scheme, for example, there's no particularly compelling difference between lambda and syntax-rules as far as the level of support provided by the Scheme grammar. Both are non-library syntax. But procedures are first-class in Scheme, and syntaxes definitely aren't.

The type of 0 is 'int'.

The type of 0.0 is double.

The type of {1, "a"} is? ... there is no type for it.

First-class means (at least to me) that a concept is supported by a programming language without additional code.

If we take your definition of first class, then C++ has first class support for functions (boost lambda, pheonix, fc++ etc), which contradicts what has been repeately said in LtU and to which I agree: C++ does not support first-class functions.

First-class

This is a rather technical term, with a specific meaning in the PLT community, so it's best to use it conventionally if you don't want to spend your life arguing about it...

Well, I disagree.

Don't I have the right to disagree? :-)

Please feel free to persuade me about it; I would be more than happy to learn where I am wrong (sincerely!).

I always thougth a

I always thougth a first-class value was something that could be returned from a function, and be an argument to one. (and perhaps be assigned to variable or cell (depending on language), and be an element in some first-class sequence) etc.

C++ does not have first-class tuples according to...

C++ does not have first-class tuples according to this definition:

http://en.wikipedia.org/wiki/First-class_(object)

The literal value {1, "a"} is not a first-class entity in C++, because:

  • It can not be stored in a variable/structure/returned/passed as argument
  • it does not have an intrinsic identity independent of any given name
  • it can not be compared to {2, "b"}

Criticism of Sources

Under a naive interpretation of the Wikipedia definition, functions in Standard ML (and Haskell?) would not be first-class, because they can not be compared for equality.

The statements about first

The statements about first class functions in C++ refer to what comes with the standard - it's possible to build first class function support in C++, but C++ functions are not first class values.

but C++ functions are not first class values

In a similar manner, literals like {1, "a"} are not first class.

Does anybody who believes that they are first-class care to explain why, whereas functions are not first-class?

Nobody's said they are, only

Nobody's said they are, only that the objects you construct with them are.

struct { const int; char

struct { const int; char const * const; }

{1, 2} + {3, 4}

#include<iostream>

template<class Fst, class Snd> struct tup{ Fst x;  Snd y; };

template<class Fst, class Snd>
tup<Fst, Snd> operator+(tup<Fst, Snd> a, tup<Fst, Snd> b)
{
    tup<Fst,Snd> c;
    c.x = a.x + b.x;
    c.y = a.y + b.y;
    return c;
}

template<class Fst, class Snd>
std::ostream& operator<<(std::ostream& o, const tup<Fst,Snd>& p)
{
    o << "{" << p.x << "," << p.y << "}";
    return o;
}

int main(int argc, char* argv[])
{
    std::cout << (tup<int,int>){1,2} + (tup<int,int>){3,4} << std::endl;
    
    return 0;
}

C++ Labmda Proposal

The following proposal for C++ "lambda"s is under active consideration by a couple of national bodies delegated from the overall standards committee ...

http://val.samko.info/lambda/

I like it.

What the document says is the most natural approach to lambda under C++.
But instead of providing a specific solution for a specific problem, it would be better if C++ got meta-programming right and allowed declaration of meta-functions, meta-types, etc that allowed user-defined transformation of C++ code into arbitrary data structures. It would be very easy to add great garbage collection and lambda functions with such a functionality.