Clarifying 'const' terminology
Dave
Dave_member at pathlink.com
Sat Jul 8 17:38:01 PDT 2006
Sean Kelly wrote:
> Bruno Medeiros wrote:
>> Derek Parnell wrote:
>>> I'm not from a C++/C#/Java background, so please excuse my lack of
>>> understanding about the meaning that is being applied to the term
>>> 'const' in these recent discussions.
>>>
>>
>> I think many times people talked a bit vaguely with their meaning of
>> const.
>>
>>> To me, there seems to be two things being talked about.
>>>
>>> (a) Data, which once initialized, is not to be modified for the
>>> run-time life of the application.
>>>
>>> (b) Data, which once passed to some function, is not to be modified
>>> for the run-time life of that function.
>>>
>>> Walter's proposed refinement of the 'in' keyword does nothing for
>>> type (a), and only limited support for type (b), in that it protects
>>> data from the called function but not from functions that that
>>> subsequently calls. It is only protection for one level deep. And the
>>> only data protected is class objects and not other reference types.
>>>
>>> Is there any other types (or subtypes) of 'const' meanings being
>>> discussed or considered?
>>>
>>> For example, are we distinguishing between compile-time protection
>>> and run-time protection?
>>>
>>
>> 'const', in a general sense, is a mechanism to specify whether a
>> variable/data/object can or can not modified, and enforce that
>> contract (at compile time). 'const' is usually in the sense of (b),
>> that is, some parts of code may modify the data, while others can only
>> read it (thus it is used for ownership management). That's the case
>> for C++.
>> Enforcing the contract means you cannot assign a const variable to a
>> non-const one, or similarly, pass a const variable to a function that
>> expects a non-const argument. The only way to subvert this is with a
>> cast (which should be the only way to subvert anything).
>
> In the realm of compiler optimization techniques, there's another issue
> as well: can the compiler assume that, because it is evaluating a const
> reference, that the underlying data will not change while that reference
> is in use. This is the truly sticky part, and is I think a large reason
> why Walter hasn't settled on anything yet. For example, consider "const
> by default":
>
> void readWrite( inout T val ) {}
> void readOnly( in T val ) {}
>
> T val;
>
> readWrite( inout val );
> ...
> readOnly( val );
>
> In the above, because a mutable reference to val is obtained before
> readOnly is called, can the compiler assume that the contents of val
> will not change while readOnly is being evaluated? Can it ever make
> that assumption for the entire life of the program after readWrite is
> called?
>
For either const by default or most of Walter's 'in' proposal (for byref
function parameters), there may be a solution at the bottom of:
http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/39757
It does rely on a non-release-build runtime check (just like array
bounds checking) so it isn't perfect, but at least it's consistent with
other language and reference implementation features, and as such I
think the optimization techniques you mention could be safely applied
for 'const' parameters. That would truly be cool IMHO.
I think this would make const-by-default or 'in' parameters a lot easier
to debug and safer for passing byref args. around in multi-threaded
apps. too.
Even for non-release builds the assert(x !is y) would be substantially
faster than bounds checking in simple loops so the overhead isn't that
terrible.
>> There are some variations in const semantics. In C++, const is a
>> type-modifier, meaning that const can be applied to each type element,
>> and not the "variable as whole". Best to give an example. In C++ you
>> can have:
>> const int * iptr = ...;
>> int const * iptr = ...;
>
> These two are actually identical. Though things can get a bit tricky if
> 'int' is replaced by a typedef involving a reference type, which is why
> the latter form tends to be preferred these days--it is unambiguous,
> unlike the former form.
>
>> const int const * iptr = ...;
>> each with different meanings:
>
> I believe this is the same as the above, you merely applied the const to
> int twice. What you probably meant for these three was:
>
> const int * iptr = ...; // mutable ptr to const int
> int const * iptr = ...; // same as previous line
> int * const iptr = ...; // const ptr to mutable int
> const int * const iptr = ...; // const ptr to const int
> int const * const iptr = ...; // same as previous line
>
> To return to the typedef issue for a moment, if you do:
>
> typedef char* pchar;
>
> template<class T> void func( const T val ) {}
>
> pchar val = "hello";
>
> func( val );
>
> then it's not entirely clear whether the val in func is a const pointer
> to mutable data or vice-versa. Thus the preferred method is:
>
> template<class T> void func( T const val ) {}
>
> Where it's obvious that the 'const' will apply to the pointer if one
> exists.
>
>
> Sean
More information about the Digitalmars-d-learn
mailing list