logical const is a subset of transitive const

Steven Schveighoffer schveiguy at yahoo.com
Fri Sep 14 13:44:32 PDT 2007


"Bill Baxter" wrote
> Janice Caron wrote:
>> On 9/14/07, Steven Schveighoffer <schveiguy at yahoo.com> wrote:
>>> I disagree.  Declaring it const means that calling that function will 
>>> not
>>> change any members of the date object.
>>>
>>> Declaring it pure means that it will always return the same value, which
>>> means it would be safe for multiple threads to access without locking (I 
>>> am
>>> very new to this concept, but I got all my knowledge from wikipedia:
>>> http://en.wikipedia.org/wiki/Functional_programming)
>>
>> I stand corrected. Yes, you are right. A function can be declared
>> const and still read and write global variables, and hence not be
>> threadsafe.
>
> Whoa.  Excuse me while I get up off the floor after having the rug pulled 
> out from under me.
>
> Was the point of const then perhaps more micro-level optimizations? Things 
> like if "X is const then I can assume the value in this register is still 
> valid without having to re-fetch from main memory".  For instance
>     X* foo;
>     foo.bar = 10;
>     func(foo);  // takes fully_const X*
>
>     // In C++ const the next line requires re-fetching foo.bar
>     // from memory,
>     // because func might actually change fully_const X*.
>     // In D it could reuse the value in register, or even assume it's
>     // still the constant 10.
>
>     Y biff = foo.bar;
>
> Just a guess.  IANACW (compiler writer).

IAANACW (I am also not a compiler writer).

You are wrong in your assumption.  Even in a single thread, I can circumvent 
the constness by having a global non-const pointer to my object, and using 
that object.  Very bad implementation, but it would not break the rules. 
For example:

X mutableinstance;

class X
{
   int bar;
}

func(const X myref)
{
  mutableinstance.bar++; // I can do this because I'm not changing myref
}

myfoolishfunc()
{
  X foo = new X;
  mutableinstance = foo;
  foo.bar = 10;
  func(foo); // increments foo.bar because mutableinstance is foo

  int biff = foo.bar; // biff now should be 11.
}

The definition of a function that does not have ANY side effects is a pure 
function (see the functional programming reference).  That type of function 
would not be able to change anything, even global variables, and so the 
compiler could assume that bar still contained 10  (BTW you cannot assume 
the register is still valid after calling func because func is allowed to 
change registers, even if it is pure).

However, in multithreaded land, it is questionable whether you can assume 
that foo will not change even with pure functions because another thread 
could conceivably come along and wreck foo while you are calling your pure 
function.

Multithreaded programming is hard.  const sucks.  There are a lot of strange 
rules.  Not being a compiler writer, I have no idea what compiler advantages 
transitive const has over logical const, but I'm going to defer to Walter on 
that because he is the compiler writer, and he seems to be very hard-set on 
it.  However, being an OO programmer and designer, and having lots of 
experience with threading, I want to ensure that the compiler optimizations 
are not going to impede the language as a good OO-equiped language.  I hope 
with my proposal, that both sides are satisfied.

-Steve 





More information about the Digitalmars-d mailing list