
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