On 10/6/10 22:39 CDT, Walter Bright wrote:
This is a meta comment Andrei and I discussed earlier today.
C++ tries to make 99.9% of the use cases doable, but they do it at the
cost of 90% of C++ programmers being unable to implement a usable
iterator or container. If you've ever peeked under the hood at the
implementation of STL iterators and containers, you know what I mean. If
you've ever wondered what an rvalue reference was and why, you know what
I mean. If you've noticed the dearth of C++ reusable libraries, while
such grow like weeds for Java/C#/Python, you know what I mean.
I think what we're doing with struct ctors, dtors, postblit and opAssign
is in the right direction. In C++, if you provide a copy constructor,
but forget the opAssign, almost certainly the default opAssign generated
by the compiler will be wrong (it's a memcpy). Even worse, this error
will often generate corruption at runtime.
D, on the other hand, builds a copy constructor out of a postblit,
meaning that the compiler generates for you most of the mechanics of the
copy constructor. The postblit only deals with where it differs from a
memcpy. Best of all, a *correct* default opAssign is automatically
generated out of the postblit and destructor.
You might be able to hand write a more efficient opAssign, but if you
don't, at least you'll get a logically correct one, rather than the C++
default one which is almost certainly wrong.
Applying the same idea to ranges suggests that missing functionality
should be either automatically and correctly generated, or if that is
not possible, issue a compile time error.
Additionally, if D range/container implementations start looking
anything like C++ STL implementations in terms of complexity, we've failed.
I agree with all of the above. After all has been said and done, it
looks like uniform function call syntax is a pivotal feature for
simplifying ranges. Most ranges can simply define the basic operations,
and std.range takes care of defining boilerplate defaults for a host of
cases. For example, you just call r.moveFront() and that becomes
moveFront(r) which is defined by std.range.
Whenever the range is defined in a way that makes it impossible to
generate e.g. moveFront() appropriately, the user would have to. Would
this be acceptable?
Andrei