range and algorithm-related stuff

Steven Schveighoffer schveiguy at yahoo.com
Mon Jan 26 08:46:09 PST 2009


"Andrei Alexandrescu" wrote
> Steven Schveighoffer wrote:
>> "Andrei Alexandrescu" wrote
>>> I'm working on the new range stuff and the range-based algorithm. In all 
>>> likelihood, you all might be pleased with the results.
>>>
>>> I wanted to gauge opinions on a couple of issues. One is, should the 
>>> empty() member function for ranges be const? On the face of it it 
>>> should, but I don't want that to be a hindrance. I presume non-const 
>>> empty might be necessary sometimes, e.g. figuring out if a stream is 
>>> empty effectively means fetching an element off it.
>>>
>>
>> Ranges are structs.  It should not matter if you want to make some const 
>> and some non-const.  Basically, it depends on the range implementation. 
>> If you can make it const, make it const, if not, don't make it const.  It 
>> shouldn't break any APIs.
>
> The problem is "higher-order" ranges - ranges that take other ranges as 
> argument. For example, consider Retro, a range that iterates another range 
> backwards.
>
> struct Retro(Range)
> {
>    Range _input;
>    ...
>    bool empty() { return _input.empty; }
> }
>
> If Retro.empty is const and Range.empty is not, that won't compile. If 
> Retro.empty is non-const and Range.empty is const, it will compile, but 
> passing a const Retro won't work as well as passing a const Range.

Hm... you need the template code to take the place of the designer who looks 
at code and decides that something should or should not be const.

For the case of Retro, you'd need some sort of const detection on Range's 
empty function.

But in general, when is it necessary for Range.empty to be const (and 
therefore Retro.empty to be const)?  If Range is working with a const 
container, wouldn't you expect that Range itself would not be const, just 
the reference to the container is const?  A range that doesn't mutate 
doesn't seem like a very useful idiom.

>> For example, an array range might have empty be const, but a stream range 
>> might not.  What matters is what functions you can use those ranges in, 
>> but those are generally templated functions, so the compiler will tell 
>> you whether it can be used or not when it tries to compile it.
>>
>> Personally, I see no benefit to having empty() be const.  What benefits 
>> do you gain by specifically making empty const and the other functions 
>> not const?  Presumably, the underlying container must be not const in 
>> order for head, next, etc. to work properly, so there is no requirement 
>> there.
>
> If you have a constant range with random access, empty, length, and 
> opIndex should be enough for you to look at anything you want without 
> altering the range itself.

Why not just pass the container itself if the range isn't going to mutate? 
The container probably already has opIndex, and length (empty AFAIK plays no 
role here).  If it doesn't it seems like a bad design to me.

If you have a good example where this is useful, I'd like to hear it.

-Steve 





More information about the Digitalmars-d mailing list