Why D const is annoying

Graham St Jack Graham.StJack at internode.on.net
Sun Dec 11 15:00:17 PST 2011


On 11/12/11 06:55, Jonathan M Davis wrote:
> On Saturday, December 10, 2011 05:45:11 bearophile wrote:
>> Timon Gehr:
>>> Just slice the const array to get a range. The specialization for ranges
>>> does not have the bug.
>>>
>>> import std.algorithm;
>>> void main() {
>>>
>>>       const arr = [1, 2, 3];
>>>       reduce!"a*b"(arr[]);   // It works.
>>>
>>> }
>> Wasn't arr a range already?
> Per isInputRange!(typeof(arr)), no. It has the right functions, but it can't
> use them, because it's const. A const range is essentially useless, because
> you can't iterate over it.
>
> When a template is instantiated, it's instantiated on the exact types that
> it's given. So, if you given a const or immutable array, it's going to
> instantiate on that type, even though it _could_ theoretically instantiate
> itself with a mutable array with const or immutable elements. And since, a
> const or immutable array won't work as a range, the template instantiation
> fails.
>
> The range-based functions in std.array and std.string work with const and
> immutable arrays simply because they are either coded specifically for arrays
> or have specializations for them. You need a function which takes const(T)[]
> rather than one which takes const T[]. std.array and std.string typically take
> const(T)[] rather than const T[], whereas a more general range function is
> taking R, which in the case above is determined to be const int[], which won't
> work as a range.
>
> It used to be that the slice of an array was the exact type of that array,
> meaning Timon's solution wouldn't work without a cast, because the slice would
> be just as const as the original. Fortunately, that has been changed, so now a
> slice of a const or immutable array will have its elements be const or
> immutable but not the slice itself. So, now const and immutable arrays are
> like static arrays in that you need to slice them to use them with range-based
> functions, but you can't use them directly with range-based functions.
>
> A bigger problem is const or immutable ranges which are structs. Unless the
> programmer who defined the range type managed to have an opSlice which returned
> a version with const or immutable elements but where the range itself wasn't
> const or immutable (i.e. a tail-const slice), then you can't even get slicing
> to work. And even if templates were improved to the point that they would
> instantiate const int[] as const(int)[] (which I expect is a change which will
> never happen due to the difficulties in doing so), that wouldn't solve the
> problem for ranges which aren't arrays.
Instead of an immutable struct trying to be a range, why not have it 
return a mutable range over its immutable elements? This would be 
analogous to slicing an immutable array.
> Also, const and immutable ranges which aren't arrays which have no opSlice
> will _never_ work, because there's no way to get a mutable slice of them to
> operate on, so you're stuck with a const or immutable range.
>
> Really what this means is that you need to slice const and immutable ranges
> when you pass them to range-based functions, and then as long as they're
> arrays or their opSlices have been defined properly, it'll work just fine.
>
> If ranges had been designed more like slists (i.e. they have head and tail
> rather than front and popFront), then they would have been inherently tail-
> const and we wouldn't be having these problems. But that's less efficent,
> because you have to copy the range every time that you want to remove an
> element from it. Regardless, it's too late now. Ranges are too heavily used
> with their current API for us to change it that drastically now.
>
> - Jonathan M Davis


-- 
Graham St Jack



More information about the Digitalmars-d mailing list