logical const is a subset of transitive const

Janice Caron caron800 at googlemail.com
Fri Sep 14 23:32:11 PDT 2007


On 9/14/07, Bill Baxter <dnewsgroup at billbaxter.com> wrote:
> It depends on
> whether you take "const X myref" to mean "this function will not modify
> the contents of myref" vs "this function will not modify myref via the
> myref handle".

The latter, by definition. The former would be "invariant" in D-speak.


> It might be reasonable to say that if you alias a const
> argument then you're in undefined behavior territory.

I think I suggested that in another thread ("restrict sucks"), but the
idea changing the default behavior and breaking deployed code in
un-diagnosable ways didn't go down too well. :-)



> > 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.
>
> Isn't that "you're on your own" territory there?  Sure some other thread
> could be changing foo, but if you're using that sort of threading then
> it was up to you to properly mutex protect foo.  I think the purpose of
> pure is more to support constructs with more limited scope, like
> parallel foreach loops.

True. In a pure function, two threads may simultaneously call f(x)
without mutex locking and get the same result... but there have to be
restrictions on the type of x or it won't work. If x is a value type
with no references, like int, and it's passed by value, that's
obviously no problem. At the other extreme, if x were a non-const
reference type, it would totally screw things up and needs to be
forbidden. But in between, there's this grey area...

If x is of type const(X), where X is a reference type then we (that
is, Walter) would /like/ it to be true that f(x) can be safely called
by multiple threads without mutex locking. Unfortunately, because even
a const object have non-pure const functions (e.g. those that call
scanf(), or read and write global variables) this desire does not hold
true.

I guess it /would/ hold true if the class X had no const functions,
but only pure functions. That is compiler-checkable.

In C++, there is the notion of a "concrete" object. There's no keyword
for it, it's just a design idea. A concrete object is an object that
behaves like a value type. It might actually /be/ a value type (e.g. a
complex number), or it might be a reference type with some sort of
smart pointer and copy-on-write (e.g. an arbitrary size matrix, or a
C++ std.string). Does this help D? I have absolutely no idea. Walter
spoke of "reference types that behave like value types", and maybe
that's what he had in mind. Operator overloads make a lot of sense for
concrete objects.

The irony is that a C++ const std.string is only /logically/ const,
not physically const, because it has a mutable reference counter in
it. Without that, it wouldn't work. (It also wouldn't work without a
copy constructor and an assignment operator).

It is safe for multiple threads to share the same instance of a C++
const std.string, not because of inherent properties of constness, but
because the implementation of std.string contains proper mutex locking
where it's needed.

In other words, a C++ const std.string can be passed to a pure
function, despite not being physically const.

The ability to be able to create concrete objects such as arbitrarily
large matrices /requires/ mutable members and/or intransitive const
(unless every matrix were "final", which would be heavy on memory use
and allocations). This is a good use case for that which Walter wants
to outlaw. However, to use them in multi-threaded land would require
the programmer of such an object to mutex-lock as required. It seems
that Walter doesn't trust the programmer to get this right.

(That's why, in another thread, I proposed that mutable members be
allowed so long as they're mutex protected. It was subsequently
pointed out to me that so long as we're prepared to risk casting away
const, we don't need language support. But are we? That's officially
undefined behaviour.)

So, you should be able to pass a concrete object to a pure function.
Unfortunately, except for very simple cases, we're not allowed to
write them.



More information about the Digitalmars-d mailing list