Jump to page: 1 24  
Page
Thread overview
Let's not make invariants const
Aug 03, 2012
Simen Kjaeraas
Aug 03, 2012
H. S. Teoh
Aug 03, 2012
bearophile
Aug 03, 2012
Davidson Corry
Aug 04, 2012
deadalnix
Aug 03, 2012
Davidson Corry
Aug 03, 2012
Era Scarecrow
Aug 05, 2012
Davidson Corry
Aug 03, 2012
bearophile
Aug 04, 2012
Marco Leise
Aug 03, 2012
Simen Kjaeraas
Aug 03, 2012
Paulo Pinto
Aug 04, 2012
Jonathan M Davis
Aug 04, 2012
Mehrdad
Aug 04, 2012
Era Scarecrow
Aug 04, 2012
Jonathan M Davis
Aug 04, 2012
Era Scarecrow
Aug 04, 2012
Christophe Travert
Aug 04, 2012
deadalnix
Aug 04, 2012
Jonathan M Davis
Aug 05, 2012
Simen Kjaeraas
Aug 05, 2012
Jakob Ovrum
Aug 05, 2012
Simen Kjaeraas
Aug 06, 2012
deadalnix
August 03, 2012
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
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
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
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
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
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
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
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
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
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