|
Boost : |
From: Simonson, Lucanus J (lucanus.j.simonson_at_[hidden])
Date: 2008-05-02 13:09:39
>> There is no need to have both run time and compile time accessors,
and
>> you can do things with run time accessors that you cannot do with
>> compile time accessors. The reverse is not true. I think you made
the
>> wrong decision and should consider making the accessors runtime only
>> instead.
>I precise that it's not a final decision, just an idea. But my guts
>feeling is that compile-time access is a weaker requirement than
>runtime access, so in the idea that a concept must always model the
>*minimal* requirements, compile-time should be preferred.
In what way weaker? This implies that there should be a type that can
provide compile time access, but can't meet the stronger requirement and
provide runtime access. Can you produce such a type?
>This time, we access both structures as easily. Just because arrays
>and tuples are both accessible with a compile-time index, while tuples
>are not accessible with a runtime index. Adapting a struct { x, y, z }
>would be trickier in both cases, but looks more natural with
>compile-time indexes in my opinion (you map a compile-time stuff onto
>another compile-time stuff).
You do have a point there, though I would say that tuples are accessible
with a runtime index, just not as conveniently.
>As pointed out by John, another advantage of compile-time access is
>the ability to have different types for each coordinate. It's
>something that has been asked for several times during recent
>discussions on this list. I was even wondering the other day if it
>wouldn't be better to not require any coordinate_type typedef and have
>the algorithms deducing by themselves the type of each coordinate by a
>BOOST_TYPEOF on the accessor.
Hmmm, that does inspire some thought, doesn't it? At some point, though
the different coordinate types need to be used together and the result
will be auto-casting. It seems reasonable to me to declare the
coordinate type of an object with heterogeneous coordinates as the one
to which the others will auto cast when used together. Clearly, this
could be bad if you mix signed and unsigned, but that would end badly
eventually anyway.
>For me, the only advantage of runtime access is to be easier to use
>inside the library algorithms. As the writer of a library is not here
>to facilitate his own life but the user's life, this kind of advantage
>shouldn't be taken into account if it's the only one.
The reason for parameterizing such concepts as orientation and direction
in the library is not for the library author's convenience, but for the
user. We typically see code that looks like this coming from the
average programmer:
if(layer % 2) {
...150 lines of application code that look like
do_something(point.x() + value);
...
} else {
...150 lines of near identical application code that look like
do_something(point.y() + value);
...
}
which is copy-paste coding run amok. More specifically the programmer
is using flow control as a substitute for data. We want them to
refactor and write the following instead:
orientation_2d orient = layer % 2 ? VERTICAL : HORIZONTAL;
...150 lines of application code where there were 300 before that look
like
do_something(point.get(orient) + value);
The refactored form is preferable for a number of reasons, not least of
which being that it is 50% less code.
>This being said, if you have a precise example of algorithm that
>technically needs runtime indexing on points, could you please show it
>to me? I haven't been able to think of such a situation until now. If
>every algorithm of the library is able to work on compile-time
>indexes, so I definitely don't see why it would require runtime
>access. It would mean requiring more than actually needed, which is a
>no-sense for a concept.
In the precise example above the application code does not know layer at
compile time, it is a runtime variable, and orientation depends on it.
To rewrite the above code (for the application programmer, I can't help
them, they would have to do it themselves) they would write:
template <int I>
void
function_i_have_to_write_because_of_compile_time_accessors(point_type
point) { ...150 lines of code that depend on I... }
if(layer % 2)
function_i_have_to_write_because_of_compile_time_accessors<1>(point);
else
function_i_have_to_write_because_of_compile_time_accessors<2>(point);
which is impractical because in the real case the block being factored
into the function probably depends on a couple dozen local variables in
the application code and cannot easily be factored into a function.
Most users are not as sophisticated as library authors, and requiring
them to template their code to use our templated code does raise the bar
for learning and using the library. Also, in this case, it makes it
less likely that the user adopts the isotropic programming style we
prefer because refactoring of flow control into compile time parameters
is less convenient than refactoring flow control into runtime parameters
since flow control is decided at run time.
Thanks,
Luke
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk