View mode: basic / threaded / horizontal-split · Log in · Help
August 03, 2012
Let's not make invariants const
Hi,

This:

$ cat test.d
class A
{
    int i;

    invariant()
    {
        i = 42;
    }
}

Currently doesn't compile:

$ dmd test.d
test.d(7): Error: can only initialize const member i inside constructor

(Obviously this example is silly, but it's just meant to illustrate the 
point of this thread.)

I believe this behavior is too strict. I don't agree that the language 
should dictate what *my* invariant can and cannot do. Not to mention 
that the standard library is far from const-friendly enough for this 
strictness to be practically reasonable today (I have tons of cast()s in 
my programs today due to this - not cool).

Does anyone else find this behavior too strict?

-- 
Alex Rønne Petersen
alex@lycus.org
http://lycus.org
August 03, 2012
Re: Let's not make invariants const
On 03-08-2012 21:19, Alex Rønne Petersen wrote:
> Hi,
>
> This:
>
> $ cat test.d
> class A
> {
>      int i;
>
>      invariant()
>      {
>          i = 42;
>      }
> }
>
> Currently doesn't compile:
>
> $ dmd test.d
> test.d(7): Error: can only initialize const member i inside constructor
>
> (Obviously this example is silly, but it's just meant to illustrate the
> point of this thread.)
>
> I believe this behavior is too strict. I don't agree that the language
> should dictate what *my* invariant can and cannot do. Not to mention
> that the standard library is far from const-friendly enough for this
> strictness to be practically reasonable today (I have tons of cast()s in
> my programs today due to this - not cool).
>
> Does anyone else find this behavior too strict?
>

I should also mention that invariants weren't const until very recently, 
so this is also quite the breaking change...

-- 
Alex Rønne Petersen
alex@lycus.org
http://lycus.org
August 03, 2012
Re: Let's not make invariants const
On Fri, 03 Aug 2012 21:19:22 +0200, Alex Rønne Petersen <alex@lycus.org>  
wrote:

> Hi,
>
> This:
>
> $ cat test.d
> class A
> {
>      int i;
>
>      invariant()
>      {
>          i = 42;
>      }
> }
>
> Currently doesn't compile:
>
> $ dmd test.d
> test.d(7): Error: can only initialize const member i inside constructor
>
> (Obviously this example is silly, but it's just meant to illustrate the  
> point of this thread.)
>
> I believe this behavior is too strict. I don't agree that the language  
> should dictate what *my* invariant can and cannot do. Not to mention  
> that the standard library is far from const-friendly enough for this  
> strictness to be practically reasonable today (I have tons of cast()s in  
> my programs today due to this - not cool).
>
> Does anyone else find this behavior too strict?

Votes++

In a perfect world...

-- 
Simen
August 03, 2012
Re: Let's not make invariants const
On Fri, Aug 03, 2012 at 09:19:22PM +0200, Alex Rønne Petersen wrote:
[...]
> class A
> {
>     int i;
> 
>     invariant()
>     {
>         i = 42;
>     }
> }
> 
> Currently doesn't compile:
> 
> $ dmd test.d
> test.d(7): Error: can only initialize const member i inside constructor
[...]
> I believe this behavior is too strict.
[...]

IMO, if you need to be changing stuff inside invariants, then you're
using it wrong. Invariants are intended to verify program logic, not to
do things like altering object state. The point is to be able to compile
with invariant code turned off, and still have the program work exactly
as before.


T

-- 
Be in denial for long enough, and one day you'll deny yourself of things you wish you hadn't.
August 03, 2012
Re: Let's not make invariants const
H. S. Teoh:

> IMO, if you need to be changing stuff inside invariants, then 
> you're using it wrong. Invariants are intended to verify 
> program logic, not to do things like altering object state. The 
> point is to be able to compile with invariant code turned off, 
> and still have the program work exactly as before.

I agree, modifying the state of the struct/class instance is not 
the job of contracts and invariants. D contract programming is 
already not tidy, so better to not make it even more messy.

In a perfect world invariants and contracts should be pure too!

Bye,
bearophile
August 03, 2012
Re: Let's not make invariants const
On Fri, 03 Aug 2012 21:36:41 +0200, H. S. Teoh <hsteoh@quickfur.ath.cx>  
wrote:

> IMO, if you need to be changing stuff inside invariants, then you're
> using it wrong. Invariants are intended to verify program logic, not to
> do things like altering object state. The point is to be able to compile
> with invariant code turned off, and still have the program work exactly
> as before.

True. Then add in a (standard) library that's not const-correct, and you
have invariants that are outright unusable.

-- 
Simen
August 03, 2012
Re: Let's not make invariants const
On 03-08-2012 21:36, H. S. Teoh wrote:
> On Fri, Aug 03, 2012 at 09:19:22PM +0200, Alex Rønne Petersen wrote:
> [...]
>> class A
>> {
>>      int i;
>>
>>      invariant()
>>      {
>>          i = 42;
>>      }
>> }
>>
>> Currently doesn't compile:
>>
>> $ dmd test.d
>> test.d(7): Error: can only initialize const member i inside constructor
> [...]
>> I believe this behavior is too strict.
> [...]
>
> IMO, if you need to be changing stuff inside invariants, then you're
> using it wrong. Invariants are intended to verify program logic, not to
> do things like altering object state. The point is to be able to compile
> with invariant code turned off, and still have the program work exactly
> as before.
>
>
> T
>

So what if, for whatever reason, the invariant needs to track and 
maintain some state in order to catch some kind of ugly bug?

I agree that ideally an invariant should not ever need to change state. 
But I think in some cases it can be a useful debugging tool.

But even ignoring that, making invariants const at this point in time is 
just not practical. We seem to be doing things in the completely wrong 
order. The library should be made const-friendly and *then* invariants 
could be made const (not that I want them to be anyway).

-- 
Alex Rønne Petersen
alex@lycus.org
http://lycus.org
August 03, 2012
Re: Let's not make invariants const
On Friday, 3 August 2012 at 19:43:18 UTC, Simen Kjaeraas wrote:
> On Fri, 03 Aug 2012 21:36:41 +0200, H. S. Teoh 
> <hsteoh@quickfur.ath.cx> wrote:
>
>> IMO, if you need to be changing stuff inside invariants, then 
>> you're
>> using it wrong. Invariants are intended to verify program 
>> logic, not to
>> do things like altering object state. The point is to be able 
>> to compile
>> with invariant code turned off, and still have the program 
>> work exactly
>> as before.
>
> True. Then add in a (standard) library that's not 
> const-correct, and you
> have invariants that are outright unusable.

Personally I feel D's contracts are still a bit off of what 
Eiffel, .NET and Ada 2012 offer.

--
Paulo
August 03, 2012
Re: Let's not make invariants const
On 8/3/2012 12:40 PM, bearophile wrote:
> H. S. Teoh:
>
>> IMO, if you need to be changing stuff inside invariants, then you're
>> using it wrong. Invariants are intended to verify program logic, not
>> to do things like altering object state. The point is to be able to
>> compile with invariant code turned off, and still have the program
>> work exactly as before.
>
> I agree, modifying the state of the struct/class instance is not the job
> of contracts and invariants. D contract programming is already not tidy,
> so better to not make it even more messy.
>
> In a perfect world invariants and contracts should be pure too!

Absolutely. Invariant clauses (and contract clauses generally) must not
have side effects, lest the class behavior change depending upon whether
or not they are compiled into the build. Assigning a value within the
invariant clause is definitely a side effect.

It is the job of the *constructor* to establish the invariant state,
not of the invariant clause (which only *verifies* it).

The compiler *should* be catching a side effect in the invariant clause,
if it can do so statically.
August 03, 2012
Re: Let's not make invariants const
On 8/3/2012 1:14 PM, Paulo Pinto wrote:
> Personally I feel D's contracts are still a bit off of what Eiffel,
  .NET and Ada 2012 offer.

On 8/3/2012 1:01 PM, Alex Rønne Petersen wrote:
> So what if, for whatever reason, the invariant needs to track and
> maintain some state in order to catch some kind of ugly bug?
>
> I agree that ideally an invariant should not ever need to change state.
> But I think in some cases it can be a useful debugging tool.

The "track and maintain some state" bit usually means capturing some
state at entry to the class (via a public method), so that the invariant
can at exit from the class compare the new, possibly modified, state
to the previous one.

This is the purpose of Eiffel's 'old' construct, which D does not have.
(Yet.) (One hopes.) (And it would be nice to be able to capture an old
*expression* and not just an old variable.)

'old' is used more often with postconditions than with invariants, but
it can be useful in both.

> But even ignoring that, making invariants const at this point in time is
> just not practical. We seem to be doing things in the completely wrong
> order. The library should be made const-friendly and *then* invariants
> could be made const (not that I want them to be anyway).

Certainly the libraries should be made as const-correct as possible. But
it's not like we are forced to do only the one or the other (except for
the insufficient supply of Walters, perhaps...). IMO, invariants should
"be made const" (i.e. statically check for side effects) as discussed
elsewhere. In fact, I believe that having more rigorous contract checks
could *help* improve library code, by making it harder for loose code
to get into the library.
« First   ‹ Prev
1 2 3 4
Top | Discussion index | About this forum | D home