On 09/17/2010 09:02 AM, Max Samukha wrote:
On 09/17/2010 11:15 AM, Andrei Alexandrescu wrote:
Nice to hear that the problem is being worked on. What kind of
typechecking will be performed in const/immutable postblit?

The tricky part in that constructor is that you must be able to assign the fields, so they are effectively non-const, but you must NOT escape outside the constructor as modifiable lvalues. Consider:

int * global;

void foo(ref int x) { global  = &x; }

struct S {
    int a;
    this(this) immutable {
        a = 5;
        foo(a);
    }
}

The program should not compile. If it did, global would be a backdoor for modifying an immutable object. Replacing const with immutable seems to make things less stringent, but not in reality. The same typechecking must be applied to const postblit because const is a subtype of immutable.

On a funny note, we figured that for a number of reasons it would help
to allow C++-style constructors that offer access to the source; it just
turns out some idioms need to modify the source as well as the
destination.

Funny. We seem to be in the opposite situation. We originally thought
that postblit won't be enough for QtD but it looks like copying most (or
all, not sure) value types in Qt do not need access to the source object.

Yah, it's a relatively rare situation. I enjoy the robustness of this(this), but see my most recent post.

The thing is that D's const looked well suited for our purpose. Postblit
and const were discussed in TDPL so we concluded that their design and
implementation were more or less complete and harmonized. We took the
effort to change the generator to properly generate const qualifiers and
only after that discovered the postblit issues.

I understand. Were it not for that particular issue, it's not impossible you would have run into some others. D's immutability subsystem is not new, but it's one of the first deployed in a practical language. Just like with other features (exceptions, templates, lambdas, AOP...), some time is needed for the appropriate idioms to emerge. QtD was the first large-scale deployment of const, and it was expected to run into practical as well as theoretical matters. We haven't deployed const into Phobos yet for the same reason, and there is ongoing discussion on how to best go about it.

Bottom line, I have a few thoughts on the matter. First, at this point in const's maturity, it's easier to convert a working codebase to using const than to design one from scratch for const. This is counter-intuitive, but it's dictated by const's immaturity. I'm sure the trend will reverse in a couple of years.

(Come to think of this: it took over 15 years for C++'s exceptions to achieve any sign of idiomatic usage, and even now very few people know e.g. how to transport one exception from a thread to another. Java has made obvious-in-hindsight errors in designing its exception subsystem, even though it already had a large body of experience with C++ at its disposal.)

Second thought is, I am sure the use of D's const, even after it matures, will be less pervasive than the use of const in C++. This inescapably follows from the fact that D const guarantees more and is more restrictive than C++'s const. In C++ I slap const on anything that comes in sight: function parameters, stack variables, member functions... At the same time, I fully realize that the assurance I get in return is quite weak. In D, I afford only a subset of uses of const, but the payout is much more powerful.

Third thought is, we did not find the design for immutable and const as much as the design found us. What we wanted was a guarantee that you get to share immutable data, which we always believed is fundamental. Everything else was aftermath.

I wouldn't go back from a Lexus to
a Yugo because the Lexus doesn't have a butt warmer :o).

:) The Lexus doesn't start and has an obscenity scratched on its hood. A
butt warmer would double its resale price.

And a tank full of gas would triple it :o).

I understand. Let me ask you this - if your bugs had #1 priority, would
that have helped? I mean, is the slow response time to bug submissions a
large annoyance factor?

Definitely. The notorious one
(http://d.puremagic.com/issues/show_bug.cgi?id=424), which hindered QtD
development on Windows, drove a couple of good users away from D and
became a powerful FUD generator, was submitted 4 years ago.

That bug comes often in my chats with Walter. The fact of the matter is that that is a difficult bug to find and fix in an assembly program. Walter is working slowly on translating the linker into C, which should simplify a lot of things. I'll also add that he did fix two comparably pernicious linker bugs, one recently.

I think one of the big factors causing annoyances is miscommunication.
While you have immediate access to Walter, most of us have to settle for
this NG and #d IRC channel (the latter has become a source of nothing
but discouragement).

Yah :o). I occasionally lurk there. It's amusing but hardly productive.

We carefully follow discussions (at least we try to) in the mail-lists
and NG but often do not know what is the final decision on a problem
having been discussed.

I understand. At the same time, only this post took me quite a long time. Just like you all, most of my time of day is already spoken for. Doing my best.

One example is the semantics of clear() and scoped(). As I understood
from one of your posts, you agree that resurrecting the destroyed object
by calling its default constructor is objectionable. However, no further
action followed. So we are at a loss whether you have a better solution,
are still thinking about one, don't have time to change the
implementation or don't want to change the thing because it is engraved
in TDPL. The same applies to 'scoped' moving the object.

Good point. Also, clear() has been a favorite topic on #d because it's good evidence of my incompetence.

The intent of clear(obj) is rather simple. It's supposed to put obj in a well-defined, destroyable state that does not allocate resources. It's the type system's last-ditch effort to preserve safety while at the same time releasing all object state.

Currently, clear() works incorrectly for classes, where it invokes the default constructor. SVN doesn't assign the blame to me, but the decision does originate in discussions I took part in. clear() shouldn't call the default constructor of the class because then the class object is free to allocate resources once again. What it should do is to blast the default initializer for each field in the class. That's a well-defined state that doesn't allocate resources - great.

There are two problems with that state. One, the state might fail the invariant of the object, but that's expected - once you called clear(), you leave an empty shell behind that's unusable unless you reseat something into it.

Second, calling the destructor again from that state is problematic (because of failing the invariant) and the GC calls the destructor. This is also solvable: the GC might memcmp() the state of the object against its default state. If comparison comes positive, the destructor is not invoked. We need to be careful that doesn't impact collection times.

Another example is half-implemented 'inout'. Is a correct implementation
fundamentally impossible or Walter haven't had time for it?

A correct implementation is possible and we have a good understanding of what it takes. Walter didn't get around to it yet.

Such unterminated discussions tend to stack up in our minds creating a
possibly very exaggerated image of instability.

I understand. Oddly enough, we only now have such a productive discussion, after the destructor has been called :o).


Andrei

Reply via email to