const debacle

Steven Schveighoffer schveiguy at yahoo.com
Mon Mar 24 07:54:24 PDT 2008


"Walter Bright" wrote
> Steven Schveighoffer wrote:
>> "Walter Bright" wrote
>>> Steven Schveighoffer wrote:
>>>> I want to specify that the function does not change the input buffer, 
>>>> and returns the same type as passed in (without duping the input).
>>> Look at it another way. You want to declare a filter that does not 
>>> change the input, but can pass it along to another function that will. I 
>>> suspect this might be a fundamentally broken concept:
>>>
>>>    T[] f(const T[]);
>>>    void g(T[]);
>>>
>>>    ...
>>>
>>>    T[] t;
>>>    g(f(t));
>>>
>>> What's happened here? Although f() promised it wouldn't modify t, it got 
>>> modified anyway, because f() passed t to g() which modified it. Far from 
>>> being a weakness in D's const regime, I think the fact that such cannot 
>>> be implemented without casting away const at some point shows that the 
>>> const system is sound, and trying to implement such a filter is unsound.
>>
>> I wholeheartedly disagree :)
>>
>> g(f(t)) is a shortcut for:
>>
>> auto tmp = f(t);
>> g(tmp);
>>
>> and as you can see, using g on the output of f is not f's fault.
>
> Yes, it is, because f returned a mutable reference to const data. This is 
> *fundamentally* unsound because f promised not to change its input, and 
> yet by returning a mutable reference to it it allows others to change it.

The block to your understanding might be because the language does not allow 
me to express my point :)

your original example had

T[] f(const T[] arg)

Which, I agree, if specified this way cannot return a slice of the argument, 
because that would violate const rules.  What I'm talking about is:

??? T[] f(??? T[] arg)

Where the ??? is replaced by some yet uncreated construct that says "you 
cannot modify arg while in f, but f can return a subset of arg".  The return 
type is dependent on the argument type, similar to a template.  If the 
argument passed is mutable, the return value is mutable.  If the argument 
passed is const, the return value is const.  However, even if the argument 
passed is mutable, it cannot be changed while inside f, allowing the coder 
to specify that f does not modify the arg, without restricting the caller 
from modifying the arg (if the arg is mutable to begin with).

Two great examples are Janice's example of strchr, and a min/max template. 
None of these should modify the arguments, but if specified as const 
arguments, the results must then also be const (with the current regime), 
thereby forcing you not to specify const in the signature, but rather in the 
documentation.

>> Even if you wanted a filter function, I would expect the filter to return 
>> exactly the same type as it was given (as it is meant to be injected in 
>> place as an argument to another function which would normally take the 
>> same input).
>
> Splitting g(f()) into two statements with a temporary does not 
> fundamentally alter anything, and if it did, that should be a huge red 
> flag that something is wrong.

I agree :)  But if the arg is mutable, f didn't violate the rule I stated 
above, it did not change the arg.  It doesn't even violate const rules that 
you have specified, since the arg is mutable.  However, it also did not 
restrict the caller from changing the arg.

>
>> Actually, your example demonstrates this point exactly.  If the code 
>> looks like:
>>
>> g(t);
>>
>> and I say "oh, I want to filter that input with f":
>>
>> g(f(t));
>>
>> If f now returns const T[], then this will not compile,
>
> right
>
>> and the filter is useless, but here comes the worst problem.  If someone 
>> else is responsible for f, they might say "hey, f doesn't modify the 
>> input, so I can re-label it const.  Oops, it won't let me return a 
>> mutable array, I'll just change that" without realizing the implications 
>> it has on its usage.
>
> That's right - that's what const-correctness is all about. 
> Const-correctness is useless otherwise <g>.

Hm... I would argue that const-correctness is then less useful, and most 
likely will not be used, thereby rendering it useless to all except 
functional programmers.  The problem is that you are peppering const all 
over phobos, and so this will be a huge barrier to people who just want to 
get things done and don't care about functional programming.  Without const 
being fully specified, it will go the way of C++ const, where it's a useful 
concept in theory, but fails in practice.  I'm not saying that all of const 
is bad, I think you are on the right track, but in order to be used in 
practice, you need to give everyone the tools that make sense.

>
>
>> I think people are going to have to leave out const for such fucntions 
>> and templatize them, even if they are correctly const, and therefore, 
>> const loses some of its value (not to mention, if you templatize f, it 
>> can generate 2 or 3 identical functions for no good reason).
>
> Templatizing is the language solution. I know about the bloat problem, but 
> that is really an implementation issue. I know the linker doesn't do it 
> now, but identical blocks of generated code with different names should be 
> merged.

That is good to hear :)

-Steve 





More information about the Digitalmars-d mailing list