comp.lang.ada
 help / color / mirror / Atom feed
From: "Randy Brukardt" <randy@rrsoftware.com>
Subject: Re: I am not understanding user defined exceptions
Date: Thu, 9 Feb 2017 15:47:49 -0600
Date: 2017-02-09T15:47:49-06:00	[thread overview]
Message-ID: <o7io26$51i$1@franka.jacob-sparre.dk> (raw)
In-Reply-To: wcco9ybfahw.fsf@TheWorld.com

"Robert A Duff" <bobduff@TheWorld.com> wrote in message 
news:wcco9ybfahw.fsf@TheWorld.com...
...
  E.g.:
>
>    subtype S is Integer with Static_Predicate => S >= 0;
>
> If you change it to:
>
>    subtype S is Integer with Static_Predicate => S >= 1;
>
> client code is just as likely to break as if you changed it
> to a dynamic predicate.

It's surely possible to have client code break, but it is far less likely if 
the client used the abstraction as intended.

When one goes from a static to a dynamic predicate, all client code using 
for loops and case statements will fail. Period.

When one changes the details of a static predicate, the only code that might 
fail (statically) is use in a case statement. And such problems generally 
point out issues with the use of the abstraction (presuming of course that 
the abstraction was sensibly defined in the first place).

For instance, if one had used static predicates to partition a type:
   subtype Part1 is Integer with Static_Predicate => Part1 >= 0;
   subtype Part2 is Integer with Static_Predicate => Part2 < 0;
then a case statement using the partitions would continue to work if what 
exactly is in each partition is changed.

If, on the other hand, a case statement assumed which partition a particular 
value belongs, then it might fail if that is changed down the road. But that 
clearly broke the abstraction, so the failure seems like a good thing in 
such a case.

Clearly, there are far fewer possiblities of failure when one changes a 
values in a static predicate than when one changes from a static predicate 
to a dynamic one. So that argument does not hold much water.

>  So what?  Any time you change the
> visible part of a widely used library unit, you have to be
> careful about breaking clients.

The more help that we can give the maintainer to prevent such problems, the 
better. This is an area where Ada does not do very well, as things that 
usually don't matter (parameter subtypes, for instance) come into play in 
some obscure rules and thus virtually any change to a specification will 
break some code. This is a serious problem; once a library gets into wide 
use its specification is effectively encased in amber. You have to start 
over to make any significant changes.

I don't see any point in making new features be even worse for that than the 
existing ones. Luckily, the ARG agreed.

> Note that the first S above is exactly the same as:
>
>    subtype S is Integer range 0 .. Integer'Last;
>
> And we don't bother to mark that as a static range.
> You could change it to "0 .. Dynamic_Value", and break
> clients.

Right. And I as I mentioned elsewhere, we should have done that. (Actually, 
what we should have done is required one to mark dynamic subtypes, as 
they're not very likely. Definitely too late for that, though.)

>>...and they'd have
>> no understanding of why (or any hope of fixing it).
>
> Now that's REALLY overstating the case.  Anybody who can read Ada code
> can understand why (and hope to fix it).

It's a bit of an overstatement, but it's close: "no understanding why" => 
there's no indication in the source code (if you use GNAT's evil 
"predicate") and the rules for when it is static are not intuitive. There's 
almost no chance that I would think of such a predicate change when I first 
saw such a problem, I would waste a lot of time looking elsewhere first.

And there's no hope of fixing it because it happened in reusable code that 
they have no control over. They've unintentionally depended on a property 
that the library did not intend to make stable. The only fix is to totally 
replace the failing constructs with different ones (and in the case case :-) 
losing the completeness checks at the same time.

>>... By declaring your intent
>> as static or dynamic, clients can properly use the predicate subtype and 
>> you
>> as the maintainer can't break their expectations without at least 
>> realizing
>> that there is a potential problem.
>
> The above argument proves that to be wrong -- the maintainer CAN
> break clients DESPITE the fact that the predicate is marked
> Static_.

Only clients that misused the abstraction in case statements. (For loops 
won't break, at least not statically -- and if the loop depends on the exact 
values that it iterates over, they've again missed the point of the 
abstraction.) I'm definitely less concerned about breakage in iffy code than 
I am about breakage that occurs in perfect code.

Being forced to replace:
    case Something is
        when Part1 => ...
        when Part2 => ...
    end case;

with a less safe if statement just because someone screwed up seems horrible 
to me.

>> This is especially true as many expressions that *seem* simple aren't
>> allowed as static predicates (simple math operators aren't allowed, for
>> instance). After all, a static predicate is a (bizarre) way to describe a
>> set constraint, whereas a dynamic predicate is an implicitly inserted
>> assertion. Quite different semantically.
>
> In the same sense that a static constant is quite different from a
> dynamic one.  For example you can say "when X =>" in a case
> statement if X is static.  And if somebody changes X to a different
> static value, or to a dynamic value, the case statement will
> become illegal.

Right, and I view this as a signicificant flaw in Ada. If I was designing a 
language from scratch, these would clearly be marked as different things. 
Most likely:

     X : Integer := ...; -- Static constant
     X : constant Integer := ...; -- Non-static constant
     X : variable Integer := ...; -- Variable.

Since the default should be the safest thing. (Note that an initializer 
would be required for all of these; <> could be used to explicitly mark it 
as default-initialized.) The same with subtypes (anything that has a name).

We can't make this change to Ada for obvious reasons, but surely two wrongs 
do not make a right.

                                         Randy.



  reply	other threads:[~2017-02-09 21:47 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-02-03 20:27 I am not understanding user defined exceptions patrick
2017-02-03 21:08 ` Randy Brukardt
2017-02-03 22:41   ` patrick
2017-02-04  1:26 ` Dennis Lee Bieber
2017-02-04  6:58   ` J-P. Rosen
2017-02-04 17:08     ` Simon Wright
2017-02-08 17:55       ` Georg Bauhaus
2017-02-08 23:37         ` Randy Brukardt
2017-02-09 19:08           ` Robert A Duff
2017-02-09 21:47             ` Randy Brukardt [this message]
2017-02-09 22:52               ` Robert A Duff
2017-02-10  9:52                 ` Simon Wright
2017-02-10 10:11                   ` Dmitry A. Kazakov
2017-02-10 20:56                 ` Randy Brukardt
2017-02-10 21:09                 ` Randy Brukardt
2017-02-10 22:07                   ` Dmitry A. Kazakov
2017-02-13 23:20                     ` Randy Brukardt
2017-02-14  8:39                       ` Dmitry A. Kazakov
2017-02-14 20:07                         ` Randy Brukardt
2017-02-15  9:32                           ` Dmitry A. Kazakov
2017-02-10 23:53                   ` Shark8
2017-02-09  0:36         ` Robert A Duff
2017-02-09  7:43           ` Simon Wright
2017-02-09 19:15             ` Robert A Duff
2017-02-09 20:39               ` Randy Brukardt
2017-02-09 21:06               ` Randy Brukardt
2017-02-09 23:08                 ` Robert A Duff
2017-02-04  8:41 ` Simon Wright
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox