October 27, 2010 Re: Temporary suspension of disbelief (invariant) | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Stanislav Blinov | Walter: > An invariant that is not invariant is a meaningless attribute. It's like "logical constness" where classes claim to be const but aren't. > > It's not an invariant if it only works some of the time. > > It's like C++ and the mutable keyword, which allows an escape from the const rules. Which makes C++ const fairly useless. > > A person should be able to see the invariant in a class declaration, and know that it offers a guarantee. He should not be required to read over everything else in the source code looking for the absence of a method that disables it. In this thread I have read many answers and comments, but I am not experienced enough yet about invariants and DbC to be able to answer them, I will need more time and more experiments. D after all is the first language where I have used DbC. I agree that an invariant that you may disable sounds like an oxymoron, and probably it leads to hairy code at best, or even to bug-prone code. Regarding "logical constness" see below my comments about the good answer by Stanislav Blinov. ---------------------- Stanislav Blinov: > If I get this right, then it is by design that your class may have several general logical states: e.g. "initializing" and "coherent". Right. An example from the Clojure language (it's a recent Lisp-like language that runs on the JavaVM). In Clojure most data is immutable. People that use Clojure have seen that this is nice and safe, but sometimes on the JavaVM this leads to low efficiency code especially when you create a data structure. So they have solved this problem inventing "transients", it's an initial phase when a data structure is being built, and it's mutable. Then when it's done it becomes immutable. This often regains lot of the lost performance introduced by immutables on the JVM. At the same way, I think that in some situations I may want to quickly build a data structure, in this phase the data structure may be internally not orderered (like an unbalanced tree), so in this phase the invariant may be false and it's better to disable it. (I think this is an uncommon situation, in most cases there is probably a way around this problem). It's like the transients for the immutability in Clojure. > Given this, I don't see why you'd want to disable invariant checks rather than modify those checks instead to validate current logical state. In fact, that "ghost" field simply serves as a flag for invariant showing which logical state it should enforce. The fact that states are 'logical', e.g. are different while represented by the same physical fields doesn't always rule them out as, uh, class states: I think you are right. > you could as > well have two separate inner classes that perform initialization and > polishing, each with its own invariant. Then you could use those inner > classes' private methods (without causing their invariant checks), but > in main class' invariant perform an assert on them to ensure their state > is valid. I see. I have never used this compound solution for the invariants. I will try it (as inner ones I may use structs instead, structs too support invariants in D), thank you for the idea :-) Thank you for all the interesting answers in this thread, I am learning. Bye, bearophile | |||
October 27, 2010 Re: Temporary suspension of disbelief (invariant) | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Fawzi Mohamed | Fawzi Mohamed wrote:
>
> On 27-ott-10, at 18:59, Jonathan M Davis wrote:
>
>> On Wednesday, October 27, 2010 07:33:58 Fawzi Mohamed wrote:
>>> An issue I encountered in D1 with invariant is using delete: I have a
>>> method that deletes the current object, and obviously then any
>>> invariant would fail.
>>> It would be nice to have a way to disable invariant in that case.
>>> In D2, as delete is not allowed anymore (if I got it correctly) this
>>> is not a problem.
>>
>> Except that calling a function on a deleted object would not be desirable, so
>> having the invariant fail at that point would be a _good_ thing. If anything,
>> you'd want _all_ function calls on a deleted object to fail invariant or no
>> invariant, because none of them should be happening in the first place.
>>
>> clear() in D2 does (or at least did - I don't know what it's current state is)
>> put an object in its default state prior to any constructor call which would
>> likely violate any invariant, which, on the whole, is a good thing as well.
>> However, there was discussion of making a cleared object have a nuked vtbl which
>> would be even better, since then all function calls on it would fail period.
>>
>> - Jonathan M Davis
> ...except that clear (just like my dealloc methods) at their end will call the invariant...
> *that* is what I was talking about,
> :)
> Fawzi
What for? It doesn't now, and it shouldn't (and most probably will not) when it's design is solid and it's properly implemented.
The purpose of clear() is:
1) call dtor (which implies checking invariant *only before* destruction), if object has it.
2) put an object in an invalid (from the compiler/runtime point of view) state: this has been discussed at length, and latest discussion ended with what Jonathan M Davis already mentioned: nuking object's virtual call table.
3) Leave object's memory alone so GC will later decide what to do with it
If I haven't missed something, this is pretty much it. It's not a method, it's a function -> no invariant checks after call.
| |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply