Boost logo

Boost :

From: Terje Slettebø (tslettebo_at_[hidden])
Date: 2002-08-14 02:46:47


>From: "Paul Mensonides" <pmenso57_at_[hidden]>

>>From: "Terje Slettebø" <tslettebo_at_[hidden]>

>> What I would now like to see, is, at least an outline of, an MPL without
the
>> iterator concept. We could then use that as a basis for discussion. For
>> example, what would the interface to sequences, algorithms, etc. be.
Without
>> this, I think it'll mostly just be the what-if's. We already have the MPL
>> example. To put it the way the critics have, I have yet to see a
convincing
>> alternative to MPL.

>What example have we seen of MPL that shows that the underlying concept is
>sound?

Examples have been given, both in the docs, and in this thread.

>> To make any comparison easier, tasks to be accomplished, using the two
>> approaches, would also be useful.
>>
>> > The most relevant problem with the example is that it has nothing to do
>> with
>> > sequences or containers--which is the primary thing that Andrei and I
are
>> > debating.
>>
>> Andrei also questions that example, so it was useful in itself.

>Andrei questions that example, I think, primarily because of the type
>abstraction. ...and I agree with him on that point. It makes the
algorithm
>significantly less complicated an more general purpose.

Huh? What makes the algorithm less complicated and more general purpose, the
type abstraction? If so, isn't that a good thing?

Fixing the algorithm to integer, certainly doesn't make the algorithm more
general purpose.

>The relative
>super-minority that needs, for some reason, to do floating-point
calculations at
>compile time can make their own factorial to do it. <-- which, by the way,
>would also be simpler.

I think you're missing the whole point. Don't you think I've considered
this? The point is that if you have such a function in a library, then you
can use it for any types, which means people won't _have to_ write their own
function, if they want one for another datatype. That's much of the purpose
of a library! That you don't have to write the components, yourself.

Sure, you can write one for integers, one for fixed_c, one for rational_c,
one for double_prec (two long's, for example), one for
fixed_c<double_prec,double_prec>, one for... You get the idea.

Tell me one thing, how would this be less complex than having one, generic
function?

As I understand, much of the purpose of MC++D is to use metaprogramming to
avoid source code duplication, which is precisely what having a generic
function does. Which is also the same advantage of generic functions in STL.
Writing a zillion different versions of the same function, and even then,
you may not cover it all, as people may make their own data types, which
will not work with it still, is certainly a lot of needless code
duplication.

Besides, I hardly find the generic function more complex than one fixed to
integer. It means using metafunctions instead of operators, not an added
complexity in itself. It also means, as mentioned, that you only have to
write it once.

If you also start to extend the system, with more mathematical functions,
like the ones I mentioned, then, unless you write them generically, if
you're going to write them for a new type, you have to rewrite all the
functions that the function depend on. This creates a ripple-effect, which
only gets worse, the bigger or more functions you have.

I certainly wouldn't want to write this mass of unnecessary, duplicated
code.

You talked about uniformity. Having one function being able to handle all
types is uniformity. Creating a zillion special versions of the same
function, is not.

As Andrei said, I rest my case.

>> Actually, I understand it wasn't obvious, but apart from using factorial
as
>> a deliberatly simple example, I also used it because it's useful in it's
own
>> right. It enables you to for example calculate the trigonometric
functions,
>> using Taylor series, which was the primary reason I made it in the first
>> place. It's useful to have factorial, anyway, though.

>I don't necessary think that it's the best way, but I don't really care
about
>this at all. The MPL doesn't force you to put together the minor pieces
like
>this. The MPL does, on the other hand, force you to use the MPL analogies
with
>the major pieces.

I assume you here refer to the sequence abstractions? It's not easy to
understand what you mean, when you just say "the MPL analogies". The MPL
doesn't force you to do anything.

>> > > >Enough of that version.<
>> > >
>> > > Agreed :o).
>> >
>> > This is the most amusing email that I've read in days. :)
>>
>> Perhaps I made it a little too easy for Andrei, here. However, I didn't
>> expect such a cheap point to be made from it. Or I would probably not
have
>> said that. It was my opinion that that version was better, for reasons
I've
>> shown above here. However, this is something both of you may not have
>> considered. Metaprogramming is not limited to integer calculation, or
using
>> the built-in types, only.

>Of course it isn't. It is a Turing complete language so you can do all
sorts of
>things. The question is whether something is best implemented with
>meta-programming, runtime programming, or an external generative program.
This
>goes into the "ends" that Andrei mentioned, and where metaprogramming is
>*useful*, rather than just "can be done."

Right. And quite frankly, I don't think it should be up to the library to
determine what is useful, and prevent anything that isn't determined useful.
This is up to the users, not the library.

>> > We have a massive
>> > difference in perspective here IMO, academic vs. practical.
>>
>> I'm not clear who "we" you are talking about, here. You've expressed
>> understanding the usefulness of algorithmic abstraction, as elaborated on
>> above. Andrei still questions this. You both question the usefulness of
the
>> iterator concept.

>Andrei and I vs. you (in particular). Yes, you can do all sorts of things
with
>metaprogramming--just like you can do all sorts of things with runtime
>programming, but that doesn't make something worthwhile just because it can
be
>done.

Who are you to say?

Besides, you've said earlier you found the algorithmic abstraction useful.
It's not easy to understand what your opinion is.

>> My example above, that Andrei was replying to, is such an example that
>> you've said shows useful MPL abstractions. So who are you agreeing with,
>> really?

>What do you think Loki's "Select" is? It is the near exact analogue to
>apply_if.

It's more like if_, but it's not a big difference.

>Some things are useful in the practical world, some things are
>not--abstracting the types is not--in any kind of general sense--useful in
the
>real world.

I guess you think that Burton et al's example isn't either, then.

Well, I do think abstracting the types is useful in the real world.

>> I was just replying to the question for real-life examples. I didn't say
>> that Loki's typelists isn't used in real-life, as well. Indeed, I've used
>> them in my own programs. They worked well for that. However, I'm
questioning
>> the extensibility of that way of doing things.
>>
>> Furthermore, aren't you contradicting yourself, here? First you make the
>> point that Loki's typelists are being used, and then you say the argument
>> (about something being used) doesn't fly, as bad code is also being used.
>> Sure, but this is not an argument against a specific library. You can't
use
>> the use of Loki as an argument for Loki, yet deny the same argument for
MPL.

>No, I was saying "who cares" to your statement that the MPL is being
used--so is
>Visual Basic--so what? What kind of argument is that?

Read my lips. I said:

> I was just replying to the question for real-life examples.

>> As Dave Abrahams replied in a posting, he has experience with a case
where
>> they picked a typelist, to implement it. However, it may later turn out
that
>> another sequence was better. If you hardwire it to a specific sequence,
then
>> it's not possible to do it like this. Then you're stuck with a specific
>> performance characteristic, also with respect to compilers.

>Where do you get these supposed "characteristics"? You are just
unilaterally
>applying runtime concepts to compile-time structures.

Nope, measurements. Particularly that different compilers vary a lot, with
respect to which sequences are most efficient, or even usable. However, I
see from another posting that you disregard this, as well. You can do that,
of course, but with reference to your academical vs practical statement
above, I don't find this a very practical approach.

>> Personally, I
>> would oppose a design that didn't let me use it on the system I use,
which
>> is mostly Intel C++. On this system, vectors are very slow, if they work
at
>> all.

>What kind of sizes are you talking about?

I was referring to the sequence_test program I posted a while ago. I have
not got it to work for vector, on Intel C++ 6.0, using the settings there.
[Addition, doing some changes got it to work better, for smaller vectors, as
described below. It probably would have worked with the original source, as
well, it just took a very long time to compile, multiple times the
list-version, so in the end, I stopped the compilation, at the time.]

I used the following changes to the posted program (reducing the vector
length from 40 to 8, to try to make it work):

With or without the following macros made no difference:

//#define BOOST_MPL_USE_PREPROCESSED_HEADERS
//#define BOOST_MPL_LIMIT_VECTOR_SIZE 50

typedef vector<> SequenceType; // Change to test for list
const int length=8;
const int iterations=0; // Number of calls to push_front

This takes 2 minutes and 50 seconds to compile on Intel C++. Changing the
sequence type to list<> makes it compile in 20 seconds.

However, from reports from Richard Crossley, who also has reported
pathologically long compile times for Intel C++, and traced it to the /Zi
switch (debug information), I changed it from "Program Database" (storing
the symbols used in the program, for easier debugging, such as
single-stepping) to "None", changed the compile time for vector to 20
seconds for vector, as well. The list compile time is unchanged by this.

I see that I can jack it up from "None" to "Line numbers only", but not
higher, so you get at least some debug info. This makes vector usable, after
all, but only if you sacrifice debug information.

Using this information, I could test the original settings, again (using
"None" for debug information):

#define BOOST_MPL_USE_PREPROCESSED_HEADERS
#define BOOST_MPL_LIMIT_VECTOR_SIZE 50

typedef vector<> SequenceType; // Change to test for list
const int length=40;
const int iterations=1000; // Number of calls to push_front

vector - 40 s
list - 40 s

So they come out the same.

However, trying to get any longer vectors ran into problems, again. Using
the following:

//#define BOOST_MPL_USE_PREPROCESSED_HEADERS
#define BOOST_MPL_LIMIT_VECTOR_SIZE 60

const int length=50;

Gave the error message "vector60.hpp" doesn't exist.

Using:

//#define BOOST_MPL_LIMIT_VECTOR_SIZE 60

Gave an incredibly long error message.

So there you have it.

I've also tried the above on g++ 2.95.3. Same result. I'd still be
interested to know if someone gets vectors over 50 elements to work.

Regards,

Terje


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk