October 27, 2010 Re: Temporary suspension of disbelief (invariant) | ||||
|---|---|---|---|---|
| ||||
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.
Fawzi
On 27-ott-10, at 15:08, Stanislav Blinov wrote:
> 27.10.2010 4:00, bearophile wrote:
>> I have not asked this in the D.learn newsgroup because I think it may be a bit interesting for other general people too.
>>
>> In D contract programming the invariant is not called before/after private methods. I think that in some cases you may want to disable the invariant even in some public methods. If your class/struct has a public method that invalidates the state of the class instance, and one public method that fixes the class instance state (I am thinking about certain data structures where in a first phase you may add many items, and then you ask the data structure to clean up itself and become coherent. This may avoid some computations), I have found this way to implement it:
> If I get this right, then it is by design that your class may have several general logical states: e.g. "initializing" and "coherent". 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: 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.
>
> IMHO, proper invariants should be strict and act by the numbers at all times, otherwise there's little to no gain in using them at all.
| ||||
October 27, 2010 Re: Temporary suspension of disbelief (invariant) | ||||
|---|---|---|---|---|
| ||||
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
| ||||
October 27, 2010 Re: Temporary suspension of disbelief (invariant) | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Fawzi Mohamed | 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.
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.
| |||
October 27, 2010 Re: Temporary suspension of disbelief (invariant) | ||||
|---|---|---|---|---|
| ||||
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
| ||||
October 27, 2010 Re: Temporary suspension of disbelief (invariant) | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Walter Bright |
On 27-ott-10, at 20:20, Walter Bright wrote:
> 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.
>
> 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.
well for methods that destroy the object I think that not checking the invariant is something reasonable, and not a hole that destroys the whole system. Being able to write methods that invalidate the object can be useful IMHO.
At the moment in those objects I simply have no invariant, and by the way, no I don't think that having the invalidating methods always external is really a good solution.
You can do without, but sometime an @invalidate property (or similar) has its uses.
Fawzi
| |||
October 27, 2010 Re: Temporary suspension of disbelief (invariant) | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Fawzi Mohamed | Fawzi Mohamed wrote:
> well for methods that destroy the object I think that not checking the invariant is something reasonable, and not a hole that destroys the whole system. Being able to write methods that invalidate the object can be useful IMHO.
> At the moment in those objects I simply have no invariant, and by the way, no I don't think that having the invalidating methods always external is really a good solution.
> You can do without, but sometime an @invalidate property (or similar) has its uses.
I agree that having a method that destroys an object can be useful. Such classes can't have an invariant, however.
The problem with an @invalidate property is the user has to go through every declaration in the class looking for such a property (grep isn't sufficient because it can pick up false positives (nested functions) and can miss things inserted by templates and mixins). An invariant should be a guarantee, not "this is guaranteed unless someone somewhere violates it, which is perfectly legal".
It's the same problem that C++ "mutable" produces, and it's not worth it.
| |||
October 27, 2010 Re: Temporary suspension of disbelief (invariant) | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Walter Bright |
On 27-ott-10, at 20:57, Walter Bright wrote:
> Fawzi Mohamed wrote:
>> well for methods that destroy the object I think that not checking the invariant is something reasonable, and not a hole that destroys the whole system. Being able to write methods that invalidate the object can be useful IMHO.
>> At the moment in those objects I simply have no invariant, and by the way, no I don't think that having the invalidating methods always external is really a good solution.
>> You can do without, but sometime an @invalidate property (or similar) has its uses.
>
> I agree that having a method that destroys an object can be useful. Such classes can't have an invariant, however.
>
> The problem with an @invalidate property is the user has to go through every declaration in the class looking for such a property (grep isn't sufficient because it can pick up false positives (nested functions) and can miss things inserted by templates and mixins). An invariant should be a guarantee, not "this is guaranteed unless someone somewhere violates it, which is perfectly legal".
>
> It's the same problem that C++ "mutable" produces, and it's not worth it.
the only thing is that the invariant is not checked *after* those method that destroy the object, it will be ok to require a special name for that method (for example destroy, dealloc or similar) if you want to avoid misusage.
The next method called on the object would fail (as it should), I often store invalid info on purpose before deleting to increase the probability of detecting such usages.
invariant is still valid (and checked) before and after all methods.
It is even impossible to call twice the destroy method (as the check at the beginning of it would fail.
So I think that everything would stay perfectly well defined.
I think it is a different situation than mutable
| |||
October 27, 2010 Re: Temporary suspension of disbelief (invariant) | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Fawzi Mohamed | Fawzi Mohamed wrote:
> the only thing is that the invariant is not checked *after* those method that destroy the object, it will be ok to require a special name for that method (for example destroy, dealloc or similar) if you want to avoid misusage.
There is a method that does that, it's called the destructor. An invariant is not checked after the destructor is run.
| |||
October 27, 2010 Re: Temporary suspension of disbelief (invariant) | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Walter Bright |
On 27-ott-10, at 22:41, Walter Bright wrote:
> Fawzi Mohamed wrote:
>> the only thing is that the invariant is not checked *after* those method that destroy the object, it will be ok to require a special name for that method (for example destroy, dealloc or similar) if you want to avoid misusage.
>
> There is a method that does that, it's called the destructor. An invariant is not checked after the destructor is run.
ok I don't think that this is a major feature, or anything like that, so I will stop arguing after this,
but I still believe that it would be useful.
The destructor is an example of a method that should not check the invariant, but it does not address my use case, because one cannot explicitly call a destructor, and there is an important difference between a destructor called by the GC and a destructor called explicitly: the one called explicitly can access the memory of the object.
Not only that it might be useful for some methods to delete the object itself.
A classical example is reference counting, the last release (the one that sets the refCount to 0) should be able to delete the object.
It is not natural to make this impossible, or to force al reference counted object to have no invariant.
| |||
October 27, 2010 Re: Temporary suspension of disbelief (invariant) | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Fawzi Mohamed | Fawzi Mohamed wrote:
> Not only that it might be useful for some methods to delete the object itself.
The pimpl pattern should be used for such, if you want to use an invariant.
Note that the C++0x shared_ptr uses pimpl in that the ref count is held separately from the object.
| |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply