comp.lang.ada
 help / color / mirror / Atom feed
* Reconsidering assignment
@ 2007-06-06 21:33 Maciej Sobczak
  2007-06-06 22:52 ` Ray Blaak
                   ` (2 more replies)
  0 siblings, 3 replies; 69+ messages in thread
From: Maciej Sobczak @ 2007-06-06 21:33 UTC (permalink / raw)


My discussion with Dmitry in another thread looked as if completely
abandoned by everybody, so I decided to start a new thread.

As a short recap, my point was that assignment of T'Class should be
banned. Dmitry has challenged me with analogies to regular
unconstrained types where my construct fell apart.
After some rethinking of the whole issue I believe I have something
reasonably consistent.
Here it goes.

First of all, the motivation.
The motivation is to create (at least in theory) a type system where
CONSTRAINT_ERROR can be raised only in those places where explicit
conversions are required. In other words, whenever an implicit
conversion is allowed, it must follow that the absence of constraint
error can be statically provable. This makes sense in high-integrity
systems, because the places of potentially raised exceptions are
distinguished in source code.
The motivation is also to have a system that is consistent enough to
cover both unconstrained types and class-wide types - these are
similar enough to give them consistent treatment.

<disclaimer>
I'm learning Ada for about one year. I'm still missing the proper
terminology, so please bring me on track whenever I go astray - but
remember that I'm writing here about some hypothetical Ada-like-but-
better language, not about Ada2005. This allows me to get away with
some terminology details. ;-)
</disclaimer>

Some important foundations.
A type can be unconstrained/constrained. It can be also a subtype of
another type, adding some more constraints. An important observation
is that the value-space and constraint-space might be or might not be
equivalent within the given type. This distinction will be needed
later to justify handling of various fundamental constructs.

I will consider three different types that quite widely represent what
we can have in Ada, and reconsider the examples from my previous posts
(and those of Dmitry):
- Integer (any number type, actually) as a type that has equivalent
value-space and constraint-space.
- String as a type that has different (although inclusive) value- and
constraint-spaces.
- Tagged types and class-wide types.

1. Integer and its subtypes (like Positive).
An Integer object has some value - and only that. Any subtype of
Integer is defined within the same space, which means that this only
thing that Integer has is also subject for the constraint check. In
other words, *every* modification of the Integer (or subtype of)
object is potentially violating the constraint.

Consider:

procedure P1(X : in Integer);
procedure P2(X : out Positive);
procedure Swap(X, Y : in out Integer);

declare
  X : Integer := -1;
  Y : Positive := 1;
begin
  P1(X); -- (1) OK (matching)
  P1(Y); -- (1) OK (actual is stricter)
  P2(Y); -- (2) OK (matching)
  P2(X); -- (2) OK (actual is wider)
  Swap(X, Y); -- (3) compile-time error on second parameter
end;

The call at (3) should banned. For types that have equivalent value-
and constraint- spaces, the rules for parameter passing are as
follows:
1. "in" formal parameters can get actual parameters that have
constraints matching or stricter
2. "out" formal parameters can get actual parameters that have
constraints matching or wider
3. "in out" formal parameters can only get actual parameters that have
matching constraints.

Any violation of these rules leads to potential constraint error that
cannot be prevented at compile-time.

2. String.
Unconstrained array types have different value- and constraint-spaces
(in the sense that they can have many different values within the same
constraint). This means that there is a whole class of modifications
that can be statically proven not to involve the constraint.
Consider:

procedure To_Upper(S : in out String);

Such a procedure is perfectly reasonable.
What is not reasonable is this:

procedure Swap(X, Y : in out String);

The problem comes from the fact that the two formal parameters could
be initialized with actual parameters that have different constraints.
This alone is not yet a problem (and we have to allow this
signature!), but the body of Swap would have to contain some
operations that potentially violate the constraint of each actual
parameter. Potentially - meaning that run-time error could be raised.
The solution is to introduce the concept of restricted parameters.
Consider:

procedure Safe_Swap(X, Y : in out String) with X'Length = Y'Length;

The restriction says that this procedure can be called only with
actual parameters that have the same length. There is still a lot we
can do in the body (remember that value-space is different that
constraint-space), but the safety can be protected at the call-site.
Even statically:

declare
  S1 : String := "abc";
  S2 : String := "xyz";
  S3 : String := "klmnop";
begin
  Safe_Swap(S1, S2); -- OK
  Safe_Swap(S1, S3); -- compile-time error
  Safe_Swap(S1, S3(1..3)); -- OK
end;

Now is the time to bring the assignment.
The rule is simple: the language provides the assignment operation
with restriction that its parameters must have equal constraint, if
there are any.
This allows to actually implement the Safe_Swap body!

3. Tagged types.
I promised that this construct will consistently cover tagged types.
Notice that for class-wide types that value-space and constraint-space
are different, similarly to unconstrained arrays, and *unlike* number
types.
This means that there is a room for modifications that don't involve
constraint, so we can and should allow in out T'Class. For example,
the geometry package might have the Object type with some hypothetical
"center" coordinates and the primitive operation Move that can move
around the plane whatever specific figure we throw at it:

procedure Move(A : in out Object'Class; DX, DY : in Real);

This can work without modifying the constraint (tag), so should be
allowed.
But the naive Swap procedure should not be allowed - I mean, the
signature is OK, but there is no way to implement it.
We can have this instead:

procedure Safe_Swap(X, Y : in out Object'Class) with X'Tag = Y'Tag;

declare
  T1 : Triangle := ...;
  T2 : Triangle := ...;
  C : Circle := ...;
begin
  Safe_Swap(T1, T2); -- OK
  Safe_Swap(T1, C); -- compile-time error
end;

Again, the language offers the assignment operation with similar
signature (that is, restricted). This can be even inherited,
dispatching, whatever. But has to be restricted, because T'Class is
(sort of) unconstrained type:

declare
  T1 : Triangle := ...;
  T2 : Triangle := ...;
  C : Circle := ...;
begin
  T1 := T2; -- OK
  C := T1; -- compile-time error (violating the restriction)
end;

Of course, programmers can provide their own assignment overloads for
whatever combination of types they care, but then it is *their*
business. And their responsability.


I believe that the above is consistent and meets the initial goals.
The two things I was lacking before are:
1. Understanding the distinction between value-space and constraint-
space (and the fact that their relation makes a difference between
Integers and tagged types)
2. The hypothetical restricted functions; these are actually more
general beasts, since the restriction can be about just anything.
Whether it is enforced at compile- or run-time is another story, but
for the sake of meeting my motivation of not having exceptions where
implicit conversions are allowed I expect that restricted parameters
follow the same logic and are themselves statically checked, with run-
time checks injected in those places where the actual parameters are
explicitly converted to match formals.

Now - what am I missing? :-)

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: Reconsidering assignment
  2007-06-06 21:33 Reconsidering assignment Maciej Sobczak
@ 2007-06-06 22:52 ` Ray Blaak
  2007-06-07  7:15   ` Maciej Sobczak
  2007-06-07  7:10 ` Stefan Lucks
  2007-06-07  9:27 ` Dmitry A. Kazakov
  2 siblings, 1 reply; 69+ messages in thread
From: Ray Blaak @ 2007-06-06 22:52 UTC (permalink / raw)


Maciej Sobczak <see.my.homepage@gmail.com> writes:
> procedure To_Upper(S : in out String);
> 
> Such a procedure is perfectly reasonable.
> What is not reasonable is this:
> 
> procedure Swap(X, Y : in out String);

I don't see the difference. Consider:

  declare
    s : String := "123";
  begin
    To_Upper(s);
  end;

  procedure To_Upper(S : in out String)
  begin
    s := "12345678";
  end;

> procedure Safe_Swap(X, Y : in out String) with X'Length = Y'Length;

Ugh. This is tedious. Seems easier to me to just let the contraint error happen.

If you really need this, also have a way to just say "with matching
constraints" directly, e.g.

  with X'Subtype = Y'Subtype

That way one does not have to get all explicit for other types that have many
explicit constraints.

-- 
Cheers,                                        The Rhythm is around me,
                                               The Rhythm has control.
Ray Blaak                                      The Rhythm is inside me,
rAYblaaK@STRIPCAPStelus.net                    The Rhythm has my soul.



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: Reconsidering assignment
  2007-06-06 21:33 Reconsidering assignment Maciej Sobczak
  2007-06-06 22:52 ` Ray Blaak
@ 2007-06-07  7:10 ` Stefan Lucks
  2007-06-07  7:32   ` Maciej Sobczak
  2007-06-07 16:28   ` Ray Blaak
  2007-06-07  9:27 ` Dmitry A. Kazakov
  2 siblings, 2 replies; 69+ messages in thread
From: Stefan Lucks @ 2007-06-07  7:10 UTC (permalink / raw)


On Wed, 6 Jun 2007, Maciej Sobczak wrote:

> 1. Integer and its subtypes (like Positive).
> An Integer object has some value - and only that. Any subtype of
> Integer is defined within the same space, which means that this only
> thing that Integer has is also subject for the constraint check. In
> other words, *every* modification of the Integer (or subtype of)
> object is potentially violating the constraint.

Yes, that is what subtypes are for. And if a subprogram delivers you a 
value in the types range, but outside the subtype's range, a 
Constraint_Error is IMHO the right thing. Note that the Constraint_Error 
is raised at the caller's side, after it got the subprogram's response.
So calling Swap(X,Y) with X: integer := -1; and Y: Natural := 1; gives 
you exactly the same "result" as, say, Y := X*Y. You (the caller) are 
responsible for maintaining the subtypes constraints -- and thus 
for raising the exception ...

> 2. String.
This issue is different from (Of course, this generalises to all types 
with constraints ...). The difference is that the exceptions are raised 
inside the subprogram, so the caller would need the details of the 
subprograms implementation to predict if an exception will be raised. That 
is bad!

I like your suggestion, but i would prefer a simpler syntax. Use some 
attribute Type in this case. Thus, I would prefer

procedure Swap (X: in out String; Y: in out X'Type);

over

> procedure Safe_Swap(X, Y : in out String) with X'Length = Y'Length;

(BTW, your clause ensures that the lengths of the two strings are 
identical, the semantic of X'Type would even ensure X'First = Y'First and 
X'Last = Y'Last ...

Assignment:

Do_Something(X: T, Y: X'Type, <... other params ...>) is
begin
   ...
   -- here you can use X := Y or Y := X without raising Constraint_Error
   -- except, of course, T is limited
end Do_Something;


> 3. Tagged types.

> procedure Safe_Swap(X, Y : in out Object'Class) with X'Tag = Y'Tag;

procedure Safe_Swap(X: in out Object'Class; Y: X'Type) is

> declare
>  T1 : Triangle := ...;
>  T2 : Triangle := ...;
>  C : Circle := ...;
> begin
>  Safe_Swap(T1, T2); -- OK
>  Safe_Swap(T1, C); -- compile-time error
> end;

Comments?

-- 
Stefan Lucks      (moved to Bauhaus-University Weimar, Germany)
------  I  love  the  taste  of  Cryptanalysis  in  the  morning!  ------





^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: Reconsidering assignment
  2007-06-06 22:52 ` Ray Blaak
@ 2007-06-07  7:15   ` Maciej Sobczak
  2007-06-07 16:34     ` Ray Blaak
  0 siblings, 1 reply; 69+ messages in thread
From: Maciej Sobczak @ 2007-06-07  7:15 UTC (permalink / raw)


On 7 Cze, 00:52, Ray Blaak <rAYbl...@STRIPCAPStelus.net> wrote:

> > procedure To_Upper(S : in out String);
>
> > Such a procedure is perfectly reasonable.
> > What is not reasonable is this:
>
> > procedure Swap(X, Y : in out String);
>
> I don't see the difference. Consider:
>
>   declare
>     s : String := "123";
>   begin
>     To_Upper(s);
>   end;
>
>   procedure To_Upper(S : in out String)
>   begin
>     s := "12345678";
>   end;

Good point, but the solution is simple: ban it. :-)
You can ban it on the basis that the modifying operation (the s :=
"12345678") operates in (ie. potentially modifies) the constraint-
space in the context where the constraint itself is statically
unknown.

This is OK:

procedure To_Upper(S : in out String) is
begin
  for I in S'First .. S'Last loop
    S(I) := ...;
  end loop;
end;

Above none of the modifying operation (well, there is only one)
operates in the constraint-space of S.

> > procedure Safe_Swap(X, Y : in out String) with X'Length = Y'Length;
>
> Ugh. This is tedious. Seems easier to me to just let the contraint error happen.

The whole Ada is tedious. Let's move to Python, where even the chore
of writing begin/end is eliminated. ;-)


> If you really need this, also have a way to just say "with matching
> constraints" directly, e.g.
>
>   with X'Subtype = Y'Subtype
>
> That way one does not have to get all explicit for other types that have many
> explicit constraints.

Yes, that makes sense.

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: Reconsidering assignment
  2007-06-07  7:10 ` Stefan Lucks
@ 2007-06-07  7:32   ` Maciej Sobczak
  2007-06-07 11:11     ` Stefan Lucks
  2007-06-07 16:28   ` Ray Blaak
  1 sibling, 1 reply; 69+ messages in thread
From: Maciej Sobczak @ 2007-06-07  7:32 UTC (permalink / raw)


On 7 Cze, 09:10, Stefan Lucks <l...@th.informatik.uni-mannheim.de>
wrote:

> > 1. Integer and its subtypes (like Positive).
> > An Integer object has some value - and only that. Any subtype of
> > Integer is defined within the same space, which means that this only
> > thing that Integer has is also subject for the constraint check. In
> > other words, *every* modification of the Integer (or subtype of)
> > object is potentially violating the constraint.
>
> Yes, that is what subtypes are for. And if a subprogram delivers you a
> value in the types range, but outside the subtype's range, a
> Constraint_Error is IMHO the right thing.

Yes, but my motivation was to exclude it if the code looks "innocent":

function Make_Integer return Integer;
function Make_Positive return Positive;

declare
  I : Integer;
  P : Positive;
begin
  I := Make_Positive; -- OK, looks "innocent", cannot raise
  P := Make_Integer; -- should be error ("innocent" lies)
  P := (Positive)Make_Integer; -- OK, beware potential errors
end;

> > 2. String.

> The difference is that the exceptions are raised
> inside the subprogram

But the rules will then apply inside this subprogram.
The rule is simple: "innocent" code should not lie.

> so the caller would need the details of the
> subprograms implementation to predict if an exception will be raised.

In other words, the call-site looks innocent, even though the body of
subprogram contains evil code raising exceptions.

function Innocent_Looking return Positive is
begin
  return (Positive)Make_Integer;
end;

declare
  P : Positive;
begin
  P := Innocent_Looking; -- ?
end;

This is good point. Maybe introducing exception specifications to
subprogram signatures would help (like in Java).
Things get interesting...

> I like your suggestion, but i would prefer a simpler syntax. Use some
> attribute Type in this case. Thus, I would prefer
>
> procedure Swap (X: in out String; Y: in out X'Type);

I don't like it because it introduces artificial assymetry in code (it
looks like there is a restriction on Y only, whereas in fact the
restriction binds both parameters).
But the idea is OK.

> > procedure Safe_Swap(X, Y : in out String) with X'Length = Y'Length;
>
> (BTW, your clause ensures that the lengths of the two strings are
> identical, the semantic of X'Type would even ensure X'First = Y'First and
> X'Last = Y'Last ...

Yes, except that these additional restrictions might not be needed in
a given context. But I think it would be good to have this possibility
as well, see also Ray's variant with X'Subtype = Y'Subtype.

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: Reconsidering assignment
  2007-06-06 21:33 Reconsidering assignment Maciej Sobczak
  2007-06-06 22:52 ` Ray Blaak
  2007-06-07  7:10 ` Stefan Lucks
@ 2007-06-07  9:27 ` Dmitry A. Kazakov
  2007-06-07 16:54   ` contracted exceptions (was Re: Reconsidering assignment) Ray Blaak
  2007-06-09 22:37   ` Reconsidering assignment Maciej Sobczak
  2 siblings, 2 replies; 69+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-07  9:27 UTC (permalink / raw)


On Wed, 06 Jun 2007 14:33:50 -0700, Maciej Sobczak wrote:

[...]
> Some important foundations.
> A type can be unconstrained/constrained. It can be also a subtype of
> another type, adding some more constraints.

New subtypes can also be obtained through generalization, i.e. by lifting
constraints. For example, an enumeration type could be extended, or an
integer type could be promoted to a real.

> Consider:
> 
> procedure P1(X : in Integer);
> procedure P2(X : out Positive);
> procedure Swap(X, Y : in out Integer);
> 
> declare
>   X : Integer := -1;
>   Y : Positive := 1;
> begin
>   P1(X); -- (1) OK (matching)
>   P1(Y); -- (1) OK (actual is stricter)
>   P2(Y); -- (2) OK (matching)
>   P2(X); -- (2) OK (actual is wider)
>   Swap(X, Y); -- (3) compile-time error on second parameter
> end;
> 
> The call at (3) should banned. For types that have equivalent value-
> and constraint- spaces, the rules for parameter passing are as
> follows:
> 1. "in" formal parameters can get actual parameters that have
> constraints matching or stricter
> 2. "out" formal parameters can get actual parameters that have
> constraints matching or wider
> 3. "in out" formal parameters can only get actual parameters that have
> matching constraints.
> 
> Any violation of these rules leads to potential constraint error that
> cannot be prevented at compile-time.

This does not work because most of the base type operations will be lost.

   function "+" (Left, Right : Integer) return Integer;

This cannot be inherited by Positive according to your rules because the
result is out. Thus the programmer will have to delegate it:

   function "+" (Left, Right : Positive) return Positive is
   begin
      return Positive (Integer (Left) + Integer (Right));
   end "+";

which were ambiguous:

   X : Integer := 1 + 1;

is it Positive'(1)+Positive'(1) or Integer'(1)+Integer'(1)? You will need
complex preference rules to resolve this mess.

> procedure Safe_Swap(X, Y : in out String) with X'Length = Y'Length;

This does not change anything, because the constraint is not static.

The summary of your program is to map constraint [more generally,
substitutability] violations onto types. You do this by disallowing
operations, and disallowing is static relatively to the type of the
operation. Hence to make it work, all constraints have to be static in the
type scope. But the string length is not such a constraint.

> declare
>   S1 : String := "abc";
>   S2 : String := "xyz";
>   S3 : String := "klmnop";

S4 : String := Read_From_File;

> begin
>   Safe_Swap(S1, S2); -- OK
>   Safe_Swap(S1, S3); -- compile-time error
>   Safe_Swap(S1, S3(1..3)); -- OK

Safe_Swap(S1, S4); -- ?

Note that Ada addresses this issue. If you wanted the above you should
simply do the following:

type Three_Character_String is new String (1..3);
type Six_Character_String is new String (1..6);

Done. If you use String instead, then there must be a reason for.

[...]
> Now - what am I missing? :-)

That Constraint_Error is a valid outcome. The problem is not that "-" of
Integer is inherited by Positive. It shall be. It is also not, that the
Positive's "-" is a composition of the Integer's "-" with two conversion
functions Integer->Positive and Positive->Integer (where the former cannot
be implemented without Constraint_Error). Whether you compose it this way
or choose to override it, it would be impossible to implement without
Constraint_Error. This is not the actual problem.

I would like to see contracted exceptions. Consider your examples in the
light of:

procedure Foo is
   X : Integer := -1;
   Y : Positive := 1;
begin
   Swap (X, Y); --Illegal
end Foo; 

The contract of Foo does not have Constraint_Error, but Swap has it.

Let Swap have no Constraint_Error in the contract, then it cannot be
inherited by Positive, because the inheritance will compose it with
Integer->Positive, which has Constraint_Error in its contract. So, you'll
be forced to either override it or drop inheritance...

or redesign Foo:

procedure Foo is
   X : Integer := -1;
   Y : Positive := 1;
begin
   Swap (X, Y);
exception
   when Constraint_Error =>
      -- Aha!
      ...
end Foo;

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: Reconsidering assignment
  2007-06-07  7:32   ` Maciej Sobczak
@ 2007-06-07 11:11     ` Stefan Lucks
  0 siblings, 0 replies; 69+ messages in thread
From: Stefan Lucks @ 2007-06-07 11:11 UTC (permalink / raw)


[-- Attachment #1: Type: TEXT/PLAIN, Size: 1655 bytes --]

On Thu, 7 Jun 2007, Maciej Sobczak wrote:

> declare
>  I : Integer;
>  P : Positive;
> begin
>  I := Make_Positive; -- OK, looks "innocent", cannot raise
>  P := Make_Integer; -- should be error ("innocent" lies)
>  P := (Positive)Make_Integer; -- OK, beware potential errors
> end;

If I wanted to ensure P := Make_Integer is a compile-time error, I would 
define Positive as a type, instead of a subtype. OK, then I would have to 
write I := Integer(Make_Positive), but � would not regard this as too much 
of a problem. Either I want the ease of mixing my types, see (2) below, in 
which case I use the "subtype" Ada syntax, or I want the firewall between 
types, where I use "type", see (1).

    type    Pos_T is new Integer range 1 .. Integer'Last; -- (1)
    subtype P_Sub is     Integer range 1 .. Integer'Last; -- (2)

The distinction between "subtype" and "type" helps to write correct and 
easy-to-read programs. I don't think however, that making subtypes more 
type-like ("type" in the sense of the Ada syntax) would help at all.

BTW, you would not get rid of innocent lies, anyway. See th following 
exampes:

    Odd_Number := Make_Positive;
    Prime      := Make_Positive;

These are innocent-looking but semantically wrong (assuming the 
constraints suggested by the choice of the identifiers). Now, please 
define an advanced type system to statically enforce such constraints! 
(You could perhaps statically enforce them by the aid of static analysis 
tools, such as the SPARK toolset.)

-- 
Stefan Lucks      (moved to Bauhaus-University Weimar, Germany)
------  I  love  the  taste  of  Cryptanalysis  in  the  morning!  ------


^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: Reconsidering assignment
  2007-06-07  7:10 ` Stefan Lucks
  2007-06-07  7:32   ` Maciej Sobczak
@ 2007-06-07 16:28   ` Ray Blaak
  1 sibling, 0 replies; 69+ messages in thread
From: Ray Blaak @ 2007-06-07 16:28 UTC (permalink / raw)


Stefan Lucks <lucks@th.informatik.uni-mannheim.de> writes:
> I like your suggestion, but i would prefer a simpler syntax. Use some
> attribute Type in this case. Thus, I would prefer
> 
> procedure Swap (X: in out String; Y: in out X'Type);
> 
> over
> 
> > procedure Safe_Swap(X, Y : in out String) with X'Length = Y'Length;

A much better idea, and it allows an easier way to contrain different
arguments, e.g.

  procedure Doit(X: in out Foo; Y : in out X'Type; A : Bar; B : A'Type);

-- 
Cheers,                                        The Rhythm is around me,
                                               The Rhythm has control.
Ray Blaak                                      The Rhythm is inside me,
rAYblaaK@STRIPCAPStelus.net                    The Rhythm has my soul.



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: Reconsidering assignment
  2007-06-07  7:15   ` Maciej Sobczak
@ 2007-06-07 16:34     ` Ray Blaak
  0 siblings, 0 replies; 69+ messages in thread
From: Ray Blaak @ 2007-06-07 16:34 UTC (permalink / raw)


Maciej Sobczak <see.my.homepage@gmail.com> writes:
> > Ugh. This is tedious. Seems easier to me to just let the contraint error
> > happen.
> 
> The whole Ada is tedious. Let's move to Python, where even the chore
> of writing begin/end is eliminated. ;-)

I want the ability to specify "contracts" to guide how things should behave,
but there is no reason to make that any more difficult than it needs to be.

It is a whole black art how to figure out the trade off between ease of use,
clarity, expresive power and safety.

At any rate, I do have an affection for dynamic languages, but it has to be
Lisp instead of Python :-).

-- 
Cheers,                                        The Rhythm is around me,
                                               The Rhythm has control.
Ray Blaak                                      The Rhythm is inside me,
rAYblaaK@STRIPCAPStelus.net                    The Rhythm has my soul.



^ permalink raw reply	[flat|nested] 69+ messages in thread

* contracted exceptions (was Re: Reconsidering assignment)
  2007-06-07  9:27 ` Dmitry A. Kazakov
@ 2007-06-07 16:54   ` Ray Blaak
  2007-06-07 20:04     ` contracted exceptions Robert A Duff
                       ` (2 more replies)
  2007-06-09 22:37   ` Reconsidering assignment Maciej Sobczak
  1 sibling, 3 replies; 69+ messages in thread
From: Ray Blaak @ 2007-06-07 16:54 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> I would like to see contracted exceptions...

The Java experience shows that compiler checked exception specifications don't
work. It sounds good in theory, but in practice programmers tend to write
unnecessary try/catch handlers that result in the worst possible outcome, and
in fact the exact opposite of what exception specs were intended for:
exceptions get ignored without changing control flow.

A typical naive programmer, forced by the compiler to handle an exception,
overwhelmingly seems to do:

  try
  {
    doSomething();
  }
  catch (SomeError e)
  {
    e.printStackTrace();
  }

or even worse:

  try
  {
    doSomething();
  }
  catch (SomeError e)
  {
  }

And the program continues on its merry way.

Slightly more aware programmers tend to do:

  void doManyThings() throws ManyErrors
  {
    try
    {
      doSomething();
    }
    catch (SomeError e)
    {
      throw new ManyErrors(e);
    }
  }

I.e. they carefully catch all errors and rethrow according to the contract of
their current method. This results in substantial portions of code that is
simply mechanical tedious try/catch/rethrow clutter.

If one observes what actually is needed for exception processing it tends to
be:

a) abort control flow - the current op cannot proceed.
b) report the error to the user in a central way (in a popup, via a log,
   whatever), and either exit or wait for the next new input/action.

This means that in practice one does not actually need to handle exceptions at
all. Handling exceptions actually becomes the "exception" not the rule, so to
speak.

So, use unchecked exceptions, throw away all those try/catch handlers, and the
code gets cleaned up, and is actually safer. 

It is also safer for newbie programmers: they will no longer be forced to
handle anything, and so their default action will actually be correct.

C# got it right, and all its exceptions are unchecked. I have done significant
C# projects, and it works well.

My current Java code is now everywhere always of the form:

  void doIt() throws Exception

which allows all exceptions to quietly go everywhere.

-- 
Cheers,                                        The Rhythm is around me,
                                               The Rhythm has control.
Ray Blaak                                      The Rhythm is inside me,
rAYblaaK@STRIPCAPStelus.net                    The Rhythm has my soul.



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-07 16:54   ` contracted exceptions (was Re: Reconsidering assignment) Ray Blaak
@ 2007-06-07 20:04     ` Robert A Duff
  2007-06-07 21:11       ` Ray Blaak
  2007-06-08  2:19       ` Randy Brukardt
  2007-06-08 11:22     ` contracted exceptions (was Re: Reconsidering assignment) Martin Krischik
  2007-06-08 12:10     ` contracted exceptions Robert A Duff
  2 siblings, 2 replies; 69+ messages in thread
From: Robert A Duff @ 2007-06-07 20:04 UTC (permalink / raw)


Ray Blaak <rAYblaaK@STRIPCAPStelus.net> writes:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>> I would like to see contracted exceptions...
>
> The Java experience shows that compiler checked exception
> specifications don't work.

I don't quite agree.  I'd say the Java experience shows that the exact
rules of Java don't work very well.  But that does not imply that the
whole idea can't work well.

I think Java is on the right track here, and with a few tweaks to the
rules would work quite well.

One example of a "tweak": if (in Ada) you have:

    procedure Iterate (..., Action: not null access procedure (...));

you want some way to say "Iterate can raise anything that Action can
raise".  The actual parameter passed to Action, I mean.

Also, Java has a way to suppress the rules when appropriate,
by making the exception "unchecked".  But this method is not
flexible enough, plus they chose the wrong answer for some
of the predefined exceptions.

> A typical naive programmer, forced by the compiler to handle an exception,

Well, the compiler isn't doing the forcing, the programmer who defined
the exception is.  And you're not forced to handle it; you also have
the choice of declaring it to be propagated.

> overwhelmingly seems to do:

[...lots of reasonable complaints about Java snipped]

> If one observes what actually is needed for exception processing it tends to
> be:
>
> a) abort control flow - the current op cannot proceed.
> b) report the error to the user in a central way (in a popup, via a log,
>    whatever), and either exit or wait for the next new input/action.

True of some programs.  But many embedded systems have no use for
popping up or logging.

- Bob



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-07 20:04     ` contracted exceptions Robert A Duff
@ 2007-06-07 21:11       ` Ray Blaak
  2007-06-07 23:44         ` Robert A Duff
  2007-06-08  2:19       ` Randy Brukardt
  1 sibling, 1 reply; 69+ messages in thread
From: Ray Blaak @ 2007-06-07 21:11 UTC (permalink / raw)


Robert A Duff <bobduff@shell01.TheWorld.com> writes:
> Ray Blaak <rAYblaaK@STRIPCAPStelus.net> writes:
> 
> > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> >> I would like to see contracted exceptions...
> >
> > The Java experience shows that compiler checked exception
> > specifications don't work.
> 
> I don't quite agree.  I'd say the Java experience shows that the exact
> rules of Java don't work very well.  But that does not imply that the
> whole idea can't work well.

I think the problem is that one cannot reliably predict in advance which
exceptions can propagate. Furthermore this set can change over time as a
system is maintained.

> you want some way to say "Iterate can raise anything that Action can
> raise".  The actual parameter passed to Action, I mean.

My point is that in general it doesn't matter. What happens when something
unexpected is raised anyway? You still have to have a strategy for that.

> Well, the compiler isn't doing the forcing, the programmer who defined
> the exception is.  And you're not forced to handle it; you also have
> the choice of declaring it to be propagated.

The heavy use of 3rd party libraries in Java programs at least dictates it to
the programmer. Sure, the programmer can define better behaviours in their own
software.

Also, declaring exceptions to be propagated cause internal design artifacts to
be propagated to the public specification of the design.

A compromise approach I have seen and used myself is to let all possible
exceptions propagate freely in the internals of a subsystem, and then at the
public edges handle and wrap into the official publically allowable exceptions.

Some more modern Java libraries make use of unchecked exceptions. E.g. the
org.w3c.dom API has its root DOMException type derived from the unchecked
RuntimeException.

> > If one observes what actually is needed for exception processing it tends to
> > be:
> >
> > a) abort control flow - the current op cannot proceed.
> > b) report the error to the user in a central way (in a popup, via a log,
> >    whatever), and either exit or wait for the next new input/action.
> 
> True of some programs.  But many embedded systems have no use for
> popping up or logging.

So what do embedded systems tend to do? They cannot simply halt after all.

My guess is that they handle known (i.e. expected) errors has best they can,
possibly with recovery, but unknown errors simply cause some sort of reset to
a known state. This is still a central strategy, no?

-- 
Cheers,                                        The Rhythm is around me,
                                               The Rhythm has control.
Ray Blaak                                      The Rhythm is inside me,
rAYblaaK@STRIPCAPStelus.net                    The Rhythm has my soul.



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-07 21:11       ` Ray Blaak
@ 2007-06-07 23:44         ` Robert A Duff
  0 siblings, 0 replies; 69+ messages in thread
From: Robert A Duff @ 2007-06-07 23:44 UTC (permalink / raw)


Ray Blaak <rAYblaaK@STRIPCAPStelus.net> writes:

> So what do embedded systems tend to do?

Various different strategies are used.  Some systems use SPARK to prove
that exceptions will not happen at run time, and suppress all
compiler-generated run-time checks, and forbid programmers from
writing "raise".  Some require all potential exceptions to be
handled very locally.  Some log the error and keep going.  Etc.

> ...They cannot simply halt after all.

Right, usually not.  I once worked on a system that had a big red button
that would shut off all power, with no software (exceptions or anything
else) involved in the decision.  The operator was supposed to press it
when they smelled smoke, or whatever.  ;-)

> My guess is that they handle known (i.e. expected) errors has best they can,
> possibly with recovery, but unknown errors simply cause some sort of reset to
> a known state. This is still a central strategy, no?

Yes.  And these "errors" could be Ada exceptions, or they could be
something else.

- Bob



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-07 20:04     ` contracted exceptions Robert A Duff
  2007-06-07 21:11       ` Ray Blaak
@ 2007-06-08  2:19       ` Randy Brukardt
  2007-06-08  7:39         ` Dmitry A. Kazakov
                           ` (2 more replies)
  1 sibling, 3 replies; 69+ messages in thread
From: Randy Brukardt @ 2007-06-08  2:19 UTC (permalink / raw)


"Robert A Duff" <bobduff@shell01.TheWorld.com> wrote in message
news:wccwsyfa5vf.fsf@shell01.TheWorld.com...
> Ray Blaak <rAYblaaK@STRIPCAPStelus.net> writes:
>
> > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> >> I would like to see contracted exceptions...
> >
> > The Java experience shows that compiler checked exception
> > specifications don't work.
>
> I don't quite agree.  I'd say the Java experience shows that the exact
> rules of Java don't work very well.  But that does not imply that the
> whole idea can't work well.
>
> I think Java is on the right track here, and with a few tweaks to the
> rules would work quite well.

I'm not as convinced. We discussed this subject in the ARG and no one had
any ideas that were real improvements on the Java situation. (It's too bad
that you can't come to meetings more often, because you often have a unique
perspective on things.) Thus the idea was dropped.

It's fairly clear that the default for Ada would have to be to let
exceptions propagate (for compatibility with existing code, if for no other
reason). That might actually be the rule change that fixes the Java
problems, but it also would make any contracts not particularly relevant.

It is certainly true that in some cases (such as a public library like Claw)
you really do want to document all of the exceptions propagated (*and
why!*), and some compiler enforcement might be nice. But even there, it
would seem that such contracts would get in the way of debugging (if a
violated exception contract caused Program_Error to be raised, the original,
unexpected exception and its information would be lost, and that would make
debugging harder. I'd rather know about a Constraint_Error due to a null
access value being dereferenced than an exception contract being
violated...).

Anyway, it would seem that real Preconditions and Invariants would be more
useful (the rest of the original thread this was split from seems mainly to
be about a rather weak from of preconditions). We (the ARG) worked a lot
harder on those, but could never get the inheritance rules quite right. (And
thus it is dropped from the Amendment for a lack of maturity.)

                            Randy.





^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-08  2:19       ` Randy Brukardt
@ 2007-06-08  7:39         ` Dmitry A. Kazakov
  2007-06-08  8:53           ` Ray Blaak
  2007-06-08 11:26         ` Martin Krischik
  2007-06-08 12:02         ` Robert A Duff
  2 siblings, 1 reply; 69+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-08  7:39 UTC (permalink / raw)


On Thu, 7 Jun 2007 21:19:08 -0500, Randy Brukardt wrote:

> It is certainly true that in some cases (such as a public library like Claw)
> you really do want to document all of the exceptions propagated (*and
> why!*), and some compiler enforcement might be nice. But even there, it
> would seem that such contracts would get in the way of debugging (if a
> violated exception contract caused Program_Error to be raised, the original,
> unexpected exception and its information would be lost, and that would make
> debugging harder. I'd rather know about a Constraint_Error due to a null
> access value being dereferenced than an exception contract being
> violated...).

Shouldn't "contracted exceptions" actually mean statically contracted ones?
IMO, a contract can be violated only by the [buggy] compiler.

> Anyway, it would seem that real Preconditions and Invariants would be more
> useful (the rest of the original thread this was split from seems mainly to
> be about a rather weak from of preconditions).

I think it is a different thing, provided, you meant preconditions checked
at run-time.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-08  7:39         ` Dmitry A. Kazakov
@ 2007-06-08  8:53           ` Ray Blaak
  2007-06-08 12:08             ` Dmitry A. Kazakov
  0 siblings, 1 reply; 69+ messages in thread
From: Ray Blaak @ 2007-06-08  8:53 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> On Thu, 7 Jun 2007 21:19:08 -0500, Randy Brukardt wrote:
> Shouldn't "contracted exceptions" actually mean statically contracted ones?
> IMO, a contract can be violated only by the [buggy] compiler.

Some points:

Even with a perfect compiler and runtime, one still has to be prepared to
handle unexpected errors due to the environment (e.g. someone yanks out the
network cable, etc.).

Say you have a contract for a particular exception to occur or not occur.  Now
how has your behaviour changed with that knowledge? In my experience, in the
usual case, it's nothing in real terms. All that is usually desired is to
perculate it upward.

In the occasional situations where one needs to cleanup before rethrowing, one
tends to need to do that for any exception, not particular ones.

In practical terms, an exception contract primarily affects the programmer in
forcing them to ensure that callers' contracts are compatible. This is
artificial work. 

An exception's type and details are primarily useful for (eventually) showing
to the user, to aid in post-analysis of the problem.

-- 
Cheers,                                        The Rhythm is around me,
                                               The Rhythm has control.
Ray Blaak                                      The Rhythm is inside me,
rAYblaaK@STRIPCAPStelus.net                    The Rhythm has my soul.



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions (was Re: Reconsidering assignment)
  2007-06-07 16:54   ` contracted exceptions (was Re: Reconsidering assignment) Ray Blaak
  2007-06-07 20:04     ` contracted exceptions Robert A Duff
@ 2007-06-08 11:22     ` Martin Krischik
  2007-06-08 17:44       ` Ray Blaak
  2007-06-08 12:10     ` contracted exceptions Robert A Duff
  2 siblings, 1 reply; 69+ messages in thread
From: Martin Krischik @ 2007-06-08 11:22 UTC (permalink / raw)


Am 07.06.2007, 19:54 Uhr, schrieb Ray Blaak <rAYblaaK@STRIPCAPStelus.net>:

> Slightly more aware programmers tend to do:
>  void doManyThings() throws ManyErrors
>   {
>     try
>     {
>       doSomething();
>     }
>     catch (SomeError e)
>     {
>       throw new ManyErrors(e);
>     }
>   }

Stange - I just used to do (in Java and C++):

   void doManyThings() throws ManyErrors, SomeError
    {
    doSomething();
    }

Of course in C++ it did not work out in the end as the compiler would not  
support me in my efforts.

Martin



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-08  2:19       ` Randy Brukardt
  2007-06-08  7:39         ` Dmitry A. Kazakov
@ 2007-06-08 11:26         ` Martin Krischik
  2007-06-08 12:02         ` Robert A Duff
  2 siblings, 0 replies; 69+ messages in thread
From: Martin Krischik @ 2007-06-08 11:26 UTC (permalink / raw)


Am 08.06.2007, 05:19 Uhr, schrieb Randy Brukardt <randy@rrsoftware.com>:

> It's fairly clear that the default for Ada would have to be to let
> exceptions propagate (for compatibility with existing code, if for no  
> other
> reason). That might actually be the rule change that fixes the Java
> problems, but it also would make any contracts not particularly relevant.

Which is how C++ does it - and it did nor work! Legacy libraries then come  
with out contracted exceptions and that makes it almost impossible to use  
contracted exceptions in your own code. Trust me: I tried and failed.

Martin






^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-08  2:19       ` Randy Brukardt
  2007-06-08  7:39         ` Dmitry A. Kazakov
  2007-06-08 11:26         ` Martin Krischik
@ 2007-06-08 12:02         ` Robert A Duff
  2 siblings, 0 replies; 69+ messages in thread
From: Robert A Duff @ 2007-06-08 12:02 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:

> "Robert A Duff" <bobduff@shell01.TheWorld.com> wrote in message
> news:wccwsyfa5vf.fsf@shell01.TheWorld.com...

>> I think Java is on the right track here, and with a few tweaks to the
>> rules would work quite well.
>
> I'm not as convinced. We discussed this subject in the ARG and no one had
> any ideas that were real improvements on the Java situation. (It's too bad
> that you can't come to meetings more often, because you often have a unique
> perspective on things.) Thus the idea was dropped.

With my "implementer of Ada 2005" hat on, I'd say that's probably a good
thing.  ;-)

> It's fairly clear that the default for Ada would have to be to let
> exceptions propagate (for compatibility with existing code, if for no other
> reason). That might actually be the rule change that fixes the Java
> problems, but it also would make any contracts not particularly relevant.

I've been thinking about the issue purely in the abstract
(from-scratch language design).  If you add the "compatibility"
requirement, that probably makes it much harder, or even impossible.
And of course in the context of Ada revisions, compatibility IS a
requirement.

> It is certainly true that in some cases (such as a public library like Claw)
> you really do want to document all of the exceptions propagated (*and
> why!*),

Right, the "why" leads to preconditions and whatnot, as you note below.

>... and some compiler enforcement might be nice. But even there, it
> would seem that such contracts would get in the way of debugging (if a
> violated exception contract caused Program_Error to be raised, the original,
> unexpected exception and its information would be lost, and that would make
> debugging harder. I'd rather know about a Constraint_Error due to a null
> access value being dereferenced than an exception contract being
> violated...).

That's true with or without contracts.  Whenever an exception gets
turned into a different one, for whatever reason, you want debugging
facilities (interactive debugger, logging, etc) to be able to get
their hands on the original.

> Anyway, it would seem that real Preconditions and Invariants would be more
> useful...

Yes.  I'd say preconditions (etc) subsume the Java "what can this raise"
idea.  So my "few tweaks" comment above is rather an understatement.

>... (the rest of the original thread this was split from seems mainly to
> be about a rather weak from of preconditions). We (the ARG) worked a lot
> harder on those, but could never get the inheritance rules quite right. (And
> thus it is dropped from the Amendment for a lack of maturity.)

I did participate in those design discussions.  AdaCore has even
considered implementing that stuff as impl-def pragmas, but I don't
think it will happen any time soon.

- Bob



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-08  8:53           ` Ray Blaak
@ 2007-06-08 12:08             ` Dmitry A. Kazakov
  2007-06-08 17:31               ` Ray Blaak
  0 siblings, 1 reply; 69+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-08 12:08 UTC (permalink / raw)


On Fri, 08 Jun 2007 08:53:28 GMT, Ray Blaak wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>> On Thu, 7 Jun 2007 21:19:08 -0500, Randy Brukardt wrote:
>> Shouldn't "contracted exceptions" actually mean statically contracted ones?
>> IMO, a contract can be violated only by the [buggy] compiler.
> 
> Some points:
> 
> Even with a perfect compiler and runtime, one still has to be prepared to
> handle unexpected errors due to the environment (e.g. someone yanks out the
> network cable, etc.).
>
> Say you have a contract for a particular exception to occur or not occur.  Now
> how has your behaviour changed with that knowledge? In my experience, in the
> usual case, it's nothing in real terms. All that is usually desired is to
> perculate it upward.

This is what I meant by referring to static contracts. A subprogram has an
exception in its contract when there is *any* possibility for this
exception to propagate [in a legal program].

It cannot both "may occur" and "may not occur."

> In practical terms, an exception contract primarily affects the programmer in
> forcing them to ensure that callers' contracts are compatible. This is
> artificial work. 

Why? Isn't passing a proper floating-type argument instead of
anything-with-a-dot-in-the-middle artificial as well?

> An exception's type and details are primarily useful for (eventually) showing
> to the user, to aid in post-analysis of the problem.

OK, this is a fundamental disagreement on what is fault and what is error.
We'd better not go into it.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-07 16:54   ` contracted exceptions (was Re: Reconsidering assignment) Ray Blaak
  2007-06-07 20:04     ` contracted exceptions Robert A Duff
  2007-06-08 11:22     ` contracted exceptions (was Re: Reconsidering assignment) Martin Krischik
@ 2007-06-08 12:10     ` Robert A Duff
  2007-06-08 15:56       ` Stefan Lucks
                         ` (2 more replies)
  2 siblings, 3 replies; 69+ messages in thread
From: Robert A Duff @ 2007-06-08 12:10 UTC (permalink / raw)


Ray Blaak <rAYblaaK@STRIPCAPStelus.net> writes:

> The Java experience shows that compiler checked exception specifications don't
> work.

> A typical naive programmer, forced by the compiler to handle an exception,
> overwhelmingly seems to do:
...
> or even worse:
>
>   try
>   {
>     doSomething();
>   }
>   catch (SomeError e)
>   {
>   }

Well, this part of the problem can't be blamed on the language.
This code is just plain bad practise.  The solution is better
training for programmers, not better language design:
You should almost never silently swallow an exception
like that, and if you do, you should always have a comment
explaining why.

I've seen the same thing (rarely) in Ada code, too.

- Bob



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-08 12:10     ` contracted exceptions Robert A Duff
@ 2007-06-08 15:56       ` Stefan Lucks
  2007-06-08 20:27         ` Pascal Obry
  2007-06-08 17:40       ` Ray Blaak
  2007-06-08 19:18       ` Simon Wright
  2 siblings, 1 reply; 69+ messages in thread
From: Stefan Lucks @ 2007-06-08 15:56 UTC (permalink / raw)


On Fri, 8 Jun 2007, Robert A Duff wrote:

> Ray Blaak <rAYblaaK@STRIPCAPStelus.net> writes:
>
>> The Java experience shows that compiler checked exception specifications don't
>> work.
>
>> A typical naive programmer, forced by the compiler to handle an exception,
>> overwhelmingly seems to do:
> ...
>> or even worse:
>>
>>   try
>>   {
>>     doSomething();
>>   }
>>   catch (SomeError e)
>>   {
>>   }
>
> Well, this part of the problem can't be blamed on the language.
> This code is just plain bad practise.  The solution is better
> training for programmers, not better language design:
> You should almost never silently swallow an exception
> like that, and if you do, you should always have a comment
> explaining why.

Unfortunately, this is what Ada tasks implicitely do.

If a task fails to handle an exception raised somewhere inside, the task 
silently dies -- without notifying anyone. Enforcing the subprograms used 
by the task to precisely specify "this subprogram might raise these 
exceptions and none else" would help a lot ...


-- 
Stefan Lucks      (moved to Bauhaus-University Weimar, Germany)
------  I  love  the  taste  of  Cryptanalysis  in  the  morning!  ------





^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-08 12:08             ` Dmitry A. Kazakov
@ 2007-06-08 17:31               ` Ray Blaak
  2007-06-08 18:00                 ` Dmitry A. Kazakov
  0 siblings, 1 reply; 69+ messages in thread
From: Ray Blaak @ 2007-06-08 17:31 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> > In practical terms, an exception contract primarily affects the programmer
> > in forcing them to ensure that callers' contracts are compatible. This is
> > artificial work.
> 
> Why? Isn't passing a proper floating-type argument instead of
> anything-with-a-dot-in-the-middle artificial as well?

No, because the recipient of the argument requires correct data for
processing.

With the throwing of an exception, in practice it is only exception clauses
being enforced, and their purpose is only for enforcing other exception
clauses. No real work, in practical terms.

Note that by "contract" I am referring only to some imaginary Ada syntax that
indicates that a subprogram can raise a particular set of exceptions.

> > An exception's type and details are primarily useful for (eventually)
> > showing to the user, to aid in post-analysis of the problem.
> 
> OK, this is a fundamental disagreement on what is fault and what is error.
> We'd better not go into it.

Hm. I'm not so sure there is a disagreement as such with fault vs error. I
guess that my point is that what the software does in response to both tends
to be the same: report it and reset/halt/whatever.

It the the humans that react differently in response: fix the environment for
the fault, or fire the programmer for the error.

-- 
Cheers,                                        The Rhythm is around me,
                                               The Rhythm has control.
Ray Blaak                                      The Rhythm is inside me,
rAYblaaK@STRIPCAPStelus.net                    The Rhythm has my soul.



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-08 12:10     ` contracted exceptions Robert A Duff
  2007-06-08 15:56       ` Stefan Lucks
@ 2007-06-08 17:40       ` Ray Blaak
  2007-06-09 18:14         ` Robert A Duff
  2007-06-08 19:18       ` Simon Wright
  2 siblings, 1 reply; 69+ messages in thread
From: Ray Blaak @ 2007-06-08 17:40 UTC (permalink / raw)


Robert A Duff <bobduff@shell01.TheWorld.com> writes:
> Ray Blaak <rAYblaaK@STRIPCAPStelus.net> writes:
> > or even worse:
> >
> >   try
> >   {
> >     doSomething();
> >   }
> >   catch (SomeError e)
> >   {
> >   }
> 
> Well, this part of the problem can't be blamed on the language.
> This code is just plain bad practise.  The solution is better
> training for programmers, not better language design

Well, you are right in theory. The problem is that such naive programmers are
directed by the compiler to do something about the exception, and being naive
they make this mistake. Training is hard, and this particular problem is
unexpectedly pervasive.

So, when one realizes that in the majority of cases all that is happening is
just an upwards perculation, that in fact the exception checking is not
usually needed, the observation is that changing the language design lets
quirkly irrational imperfect humans avoid certain errors more readily.

What we should strive for in language design are approaches that naturally
encourage correct or robust behaviour by default, so that the need for
training becomes less of an issue. 

> You should almost never silently swallow an exception
> like that, and if you do, you should always have a comment
> explaining why.

Absolutely.

-- 
Cheers,                                        The Rhythm is around me,
                                               The Rhythm has control.
Ray Blaak                                      The Rhythm is inside me,
rAYblaaK@STRIPCAPStelus.net                    The Rhythm has my soul.



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions (was Re: Reconsidering assignment)
  2007-06-08 11:22     ` contracted exceptions (was Re: Reconsidering assignment) Martin Krischik
@ 2007-06-08 17:44       ` Ray Blaak
  0 siblings, 0 replies; 69+ messages in thread
From: Ray Blaak @ 2007-06-08 17:44 UTC (permalink / raw)


"Martin Krischik" <krischik@users.sourceforge.net> writes:
> Stange - I just used to do (in Java and C++):
> 
>    void doManyThings() throws ManyErrors, SomeError
>     {
>     doSomething();
>     }

Sure. But the problem with this approach is that clients are impacted and need
to have visibility to all of the exception classes, some of which might have
been internal, private to the subsystem's implementation.

Also, this approach is tolerable for one or two exceptions. If you method is
using a lot of libraries, it can get out of hand, and suddenly you need a
throws clause with many exceptions.

An internal change to method bodies can readily cause new exceptions to be
requird, forcing clients to recompile, etc.

It becomes a non-trivial maintenance issue.

-- 
Cheers,                                        The Rhythm is around me,
                                               The Rhythm has control.
Ray Blaak                                      The Rhythm is inside me,
rAYblaaK@STRIPCAPStelus.net                    The Rhythm has my soul.



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-08 17:31               ` Ray Blaak
@ 2007-06-08 18:00                 ` Dmitry A. Kazakov
  2007-06-08 18:20                   ` Georg Bauhaus
  2007-06-08 19:15                   ` Simon Wright
  0 siblings, 2 replies; 69+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-08 18:00 UTC (permalink / raw)


On Fri, 08 Jun 2007 17:31:05 GMT, Ray Blaak wrote:

> Note that by "contract" I am referring only to some imaginary Ada syntax that
> indicates that a subprogram can raise a particular set of exceptions.

Then I don't see any problem with that. Consider:

if Halt (x) then
   raise Y;
end if;

the contract has Y. So you can always match such contracts statically.

Of course, Raise_Exception and Raise_Occurence from Ada.Exceptions will
have all exceptions in their contracts.

> Hm. I'm not so sure there is a disagreement as such with fault vs error. I
> guess that my point is that what the software does in response to both tends
> to be the same: report it and reset/halt/whatever.

Software and more narrowly exceptions cannot report own bugs. It would be a
very bad idea to exceptions for that, because vital information about the
reasons will be inevitably destroyed. The best possible way is to break
into debugger, stopping everything else.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-08 18:00                 ` Dmitry A. Kazakov
@ 2007-06-08 18:20                   ` Georg Bauhaus
  2007-06-08 18:56                     ` Dmitry A. Kazakov
  2007-06-08 19:15                   ` Simon Wright
  1 sibling, 1 reply; 69+ messages in thread
From: Georg Bauhaus @ 2007-06-08 18:20 UTC (permalink / raw)


On Fri, 2007-06-08 at 20:00 +0200, Dmitry A. Kazakov wrote: 
> On Fri, 08 Jun 2007 17:31:05 GMT, Ray Blaak wrote:

> > Hm. I'm not so sure there is a disagreement as such with fault vs error. I
> > guess that my point is that what the software does in response to both tends
> > to be the same: report it and reset/halt/whatever.
> 
> Software and more narrowly exceptions cannot report own bugs. It would be a
> very bad idea to exceptions for that, because vital information about the
> reasons will be inevitably destroyed. The best possible way is to break
> into debugger, stopping everything else.

Or use backtracking and try an alternative path? Which,
of course, must have be provided, then.

Another option in distributed systems is advertized
as fault tolerance in the presence of Byzantine faults.
Uses replicas. Bought by the Redmond machine.

(M. Castro (MS) and B. Liskov (MIT) 2002; I admit I have
only read the abstract.)





^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-08 18:20                   ` Georg Bauhaus
@ 2007-06-08 18:56                     ` Dmitry A. Kazakov
  0 siblings, 0 replies; 69+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-08 18:56 UTC (permalink / raw)


On Fri, 08 Jun 2007 20:20:58 +0200, Georg Bauhaus wrote:

> On Fri, 2007-06-08 at 20:00 +0200, Dmitry A. Kazakov wrote: 
>> On Fri, 08 Jun 2007 17:31:05 GMT, Ray Blaak wrote:
> 
>>> Hm. I'm not so sure there is a disagreement as such with fault vs error. I
>>> guess that my point is that what the software does in response to both tends
>>> to be the same: report it and reset/halt/whatever.
>> 
>> Software and more narrowly exceptions cannot report own bugs. It would be a
>> very bad idea to exceptions for that, because vital information about the
>> reasons will be inevitably destroyed. The best possible way is to break
>> into debugger, stopping everything else.
> 
> Or use backtracking and try an alternative path? Which,
> of course, must have be provided, then.

and selected by another program. Debugger is also other program.

> Another option in distributed systems is advertized
> as fault tolerance in the presence of Byzantine faults.
> Uses replicas. Bought by the Redmond machine.

That does not help much with software faults, except the case when the bug
was exposed by some stochastic state. But even then, if you try a replica
on the exactly same state, then it will fail again. If you continue it from
a different state, then it won't be really 100% recovering or a replica.
Redundant systems are good for dealing with hardware faults. Well-paid Ada
programmers for preventing software ones (:-)).

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-08 18:00                 ` Dmitry A. Kazakov
  2007-06-08 18:20                   ` Georg Bauhaus
@ 2007-06-08 19:15                   ` Simon Wright
  2007-06-09  0:14                     ` Randy Brukardt
  2007-06-09  8:21                     ` Dmitry A. Kazakov
  1 sibling, 2 replies; 69+ messages in thread
From: Simon Wright @ 2007-06-08 19:15 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:

> Software and more narrowly exceptions cannot report own bugs. It
> would be a very bad idea to exceptions for that, because vital
> information about the reasons will be inevitably destroyed. The best
> possible way is to break into debugger, stopping everything else.

I don't really understand the first sentence of this ..

If our fielded application raises an unhandled exception it's going to
be the result of a design error or at least a design shortcoming. We
will log the exception traceback and stop all application processing;
the system is in an unstable state. The operator can then restart and
(if we are lucky) send us the fault log for debugging. If we're
unlucky they'll just complain about us to each other and our
reputation is shot.

The operator has no access to or interest in a debugger.



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-08 12:10     ` contracted exceptions Robert A Duff
  2007-06-08 15:56       ` Stefan Lucks
  2007-06-08 17:40       ` Ray Blaak
@ 2007-06-08 19:18       ` Simon Wright
  2 siblings, 0 replies; 69+ messages in thread
From: Simon Wright @ 2007-06-08 19:18 UTC (permalink / raw)


Robert A Duff <bobduff@shell01.TheWorld.com> writes:

> You should almost never silently swallow an exception like that, and
> if you do, you should always have a comment explaining why.

I saw such a construct recently, the comment effectively said that
someone else would notice the problem and sort it out .. at least it
revealed the mis-thinking involved!



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-08 15:56       ` Stefan Lucks
@ 2007-06-08 20:27         ` Pascal Obry
  2007-06-09  0:19           ` Randy Brukardt
  0 siblings, 1 reply; 69+ messages in thread
From: Pascal Obry @ 2007-06-08 20:27 UTC (permalink / raw)
  To: Stefan Lucks

Stefan Lucks a �crit :
> If a task fails to handle an exception raised somewhere inside, the task
> silently dies -- without notifying anyone. Enforcing the subprograms
> used by the task to precisely specify "this subprogram might raise these
> exceptions and none else" would help a lot ...

That's really different. And think about it, since a task is mapped to a
thread which comes with its own stack... who could possibly handle this
exception ?

And note that in Ada 2005 you can use Ada.Task_Termination to register
termination notifications.

Pascal.

-- 

--|------------------------------------------------------
--| Pascal Obry                           Team-Ada Member
--| 45, rue Gabriel Peri - 78114 Magny Les Hameaux FRANCE
--|------------------------------------------------------
--|              http://www.obry.net
--| "The best way to travel is by means of imagination"
--|
--| gpg --keyserver wwwkeys.pgp.net --recv-key C1082595



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-08 19:15                   ` Simon Wright
@ 2007-06-09  0:14                     ` Randy Brukardt
  2007-06-09  2:44                       ` Larry Kilgallen
  2007-06-09  8:21                     ` Dmitry A. Kazakov
  1 sibling, 1 reply; 69+ messages in thread
From: Randy Brukardt @ 2007-06-09  0:14 UTC (permalink / raw)


"Simon Wright" <simon.j.wright@mac.com> wrote in message
news:m2k5ue8dhk.fsf@mac.com...
...
> If our fielded application raises an unhandled exception it's going to
> be the result of a design error or at least a design shortcoming. We
> will log the exception traceback and stop all application processing;
> the system is in an unstable state. The operator can then restart and
> (if we are lucky) send us the fault log for debugging. If we're
> unlucky they'll just complain about us to each other and our
> reputation is shot.
>
> The operator has no access to or interest in a debugger.

And that's true for virtually all applications. [Aside: didn't we have this
discussion a few months ago??] Only the original developer(s) care about why
something failed; other users (the vast majority) only care that it failed.
Even users of a compiler don't want an internal error to throw them into a
debugger: what value could that have? (As for the original developer(s),
they can only use a debugger if they can reproduce the actual error -- and
the ability to do that is rare. It's actually better to have the partial
information from a good logging mechanism, because at least some fraction of
the time the error will be obvious and fixable. And the information doesn't
have to be that partial; I recall that the error dump on the Pascal compiler
we used in college actually dumped all of the local variables in its
traceback on a failure. That compiler's facilities were used as the model
for error handling in Janus/Ada [although not the local variable dumps...too
much overhead])

                            Randy.





^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-08 20:27         ` Pascal Obry
@ 2007-06-09  0:19           ` Randy Brukardt
  2007-06-09 18:04             ` Robert A Duff
  0 siblings, 1 reply; 69+ messages in thread
From: Randy Brukardt @ 2007-06-09  0:19 UTC (permalink / raw)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 1157 bytes --]

"Pascal Obry" <pascal@obry.net> wrote in message
news:4669BBBB.8040806@obry.net...
> Stefan Lucks a �crit :
> > If a task fails to handle an exception raised somewhere inside, the task
> > silently dies -- without notifying anyone. Enforcing the subprograms
> > used by the task to precisely specify "this subprogram might raise these
> > exceptions and none else" would help a lot ...
>
> That's really different. And think about it, since a task is mapped to a
> thread which comes with its own stack... who could possibly handle this
> exception ?

And more importantly, where would it be raised? If it was raised in the
parent task, that could happen anywhere, which would be a design nightmare
(a different nightmare than the current one, anyway).

> And note that in Ada 2005 you can use Ada.Task_Termination to register
> termination notifications.

It's unfortunate that the default isn't to notify someone, however. Worse,
this interface might not work in out-of-memory circumstances (one of the
most common reasons for task failure, at least in Janus/Ada programs where
the default stack size is rather small).

                      Randy.





^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-09  0:14                     ` Randy Brukardt
@ 2007-06-09  2:44                       ` Larry Kilgallen
  0 siblings, 0 replies; 69+ messages in thread
From: Larry Kilgallen @ 2007-06-09  2:44 UTC (permalink / raw)


In article <f4cr8j$mb8$1@jacob-sparre.dk>, "Randy Brukardt" <randy@rrsoftware.com> writes:
> "Simon Wright" <simon.j.wright@mac.com> wrote in message
> news:m2k5ue8dhk.fsf@mac.com...
> ...
>> If our fielded application raises an unhandled exception it's going to
>> be the result of a design error or at least a design shortcoming. We
>> will log the exception traceback and stop all application processing;
>> the system is in an unstable state. The operator can then restart and
>> (if we are lucky) send us the fault log for debugging. If we're
>> unlucky they'll just complain about us to each other and our
>> reputation is shot.
>>
>> The operator has no access to or interest in a debugger.
> 
> And that's true for virtually all applications. [Aside: didn't we have this
> discussion a few months ago??] Only the original developer(s) care about why
> something failed; other users (the vast majority) only care that it failed.
> Even users of a compiler don't want an internal error to throw them into a
> debugger: what value could that have? (As for the original developer(s),
> they can only use a debugger if they can reproduce the actual error -- and
> the ability to do that is rare. It's actually better to have the partial
> information from a good logging mechanism, because at least some fraction of
> the time the error will be obvious and fixable. And the information doesn't
> have to be that partial; I recall that the error dump on the Pascal compiler
> we used in college actually dumped all of the local variables in its
> traceback on a failure.

There is a long tradition of a "core dump" on a failing program,
although these days it tends to be more structured.  The VMS dump
from an application can be examined back at the developer's shop
using the regular debugger interface -- for those cases where the
security policy of the user site allows export of such opaque data
to the developer.



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-08 19:15                   ` Simon Wright
  2007-06-09  0:14                     ` Randy Brukardt
@ 2007-06-09  8:21                     ` Dmitry A. Kazakov
  2007-06-09 12:32                       ` Simon Wright
  1 sibling, 1 reply; 69+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-09  8:21 UTC (permalink / raw)


On Fri, 08 Jun 2007 20:15:03 +0100, Simon Wright wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> 
>> Software and more narrowly exceptions cannot report own bugs. It
>> would be a very bad idea to exceptions for that, because vital
>> information about the reasons will be inevitably destroyed. The best
>> possible way is to break into debugger, stopping everything else.
> 
> I don't really understand the first sentence of this ..

When the program has a bug, then it could be anything, including reporting
another or non-existing bug, raising exceptions (false positive), not
raising exception (false negative), whatever.

Let the probability of a program state where it would have a false positive
be sufficiently greater than the probability of the states with false
negative. Then it is better not to report anything!

What is known about these probabilities?

> The operator has no access to or interest in a debugger.

It is all about having another system monitoring the system one. The best
possible secondary system is a programmer with an IDE. An operator comes
next.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-09  8:21                     ` Dmitry A. Kazakov
@ 2007-06-09 12:32                       ` Simon Wright
  2007-06-09 18:38                         ` Dmitry A. Kazakov
  2007-06-11 14:15                         ` Bob Spooner
  0 siblings, 2 replies; 69+ messages in thread
From: Simon Wright @ 2007-06-09 12:32 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:

> On Fri, 08 Jun 2007 20:15:03 +0100, Simon Wright wrote:
>
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>> 
>>> Software and more narrowly exceptions cannot report own bugs. It
>>> would be a very bad idea to exceptions for that, because vital
>>> information about the reasons will be inevitably destroyed. The best
>>> possible way is to break into debugger, stopping everything else.
>> 
>> I don't really understand the first sentence of this ..
>
> When the program has a bug, then it could be anything, including
> reporting another or non-existing bug, raising exceptions (false
> positive), not raising exception (false negative), whatever.
>
> Let the probability of a program state where it would have a false
> positive be sufficiently greater than the probability of the states
> with false negative. Then it is better not to report anything!
>
> What is known about these probabilities?

Not a lot .. an exception is raised because some assertion made by the
designer/implementer of the library concerned has turned out to be
false (the value will be in this range; the file will be open; the
file is a valid XML document ...).

If I can find out which of my assumptions failed, I have at least
somewhere to start.

I agree that an exception message isn't of any use to the end user (I
suppose they may grow to learn that some messages happen because of
particular sequences of operations, and to avoid those sequences).



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-09  0:19           ` Randy Brukardt
@ 2007-06-09 18:04             ` Robert A Duff
  2007-06-09 18:37               ` Dmitry A. Kazakov
  0 siblings, 1 reply; 69+ messages in thread
From: Robert A Duff @ 2007-06-09 18:04 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:

> "Pascal Obry" <pascal@obry.net> wrote in message
> news:4669BBBB.8040806@obry.net...
>> Stefan Lucks a �crit :
>> > If a task fails to handle an exception raised somewhere inside, the task
>> > silently dies -- without notifying anyone. Enforcing the subprograms
>> > used by the task to precisely specify "this subprogram might raise these
>> > exceptions and none else" would help a lot ...
>>
>> That's really different. And think about it, since a task is mapped to a
>> thread which comes with its own stack... who could possibly handle this
>> exception ?
>
> And more importantly, where would it be raised? If it was raised in the
> parent task, that could happen anywhere, which would be a design nightmare
> (a different nightmare than the current one, anyway).

I can think of lots of rules that are not perfect, but are at least
superior to the existing rule of silently ignoring the exception.

The simplest would be to terminate the entire program immediately.
And print an error message on systems where that makes sense.
Ada has no way to terminate the whole program (i.e. call "exit"),
but it should.

Or just print an error message.

Or raise Program_Error in the parent task at the point where that task
awaits its dependents.  Option: abort all the siblings as well.

Or put the task to sleep, so the parent waits forever (and the
programmer has to debug a "deadlock").

>> And note that in Ada 2005 you can use Ada.Task_Termination to register
>> termination notifications.
>
> It's unfortunate that the default isn't to notify someone, however.

Right.  Ada.Task_Termination is another way, and the default should be
to raise alarms of some sort.

>...Worse,
> this interface might not work in out-of-memory circumstances (one of the
> most common reasons for task failure, at least in Janus/Ada programs where
> the default stack size is rather small).

Right, out-of-memory is a difficult issue.  I don't know of any language
that solves it well.  You might think you could do:

    task body T is
    begin
        declare
            ...
        begin
            ...
        exception
            when others =>
                ...
        end;
    end T;

and carefully prove that the handler code cannot raise any exceptions
itself.  But you can't prove the absense of Storage_Error in Ada.

My solution: allow the programmer to declare that certain regions of
code cannot run out of memory.  The compiler must reserve enough memory
(and if can't, then raise S_E before entering that region).  Of course,
what you can do in such a region is implementation dependent.

This would make life difficult for compilers that generate C,
or any other target language that doesn't have sufficient control
over memory use.  :-(

- Bob



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-08 17:40       ` Ray Blaak
@ 2007-06-09 18:14         ` Robert A Duff
  0 siblings, 0 replies; 69+ messages in thread
From: Robert A Duff @ 2007-06-09 18:14 UTC (permalink / raw)


Ray Blaak <rAYblaaK@STRIPCAPStelus.net> writes:

> Robert A Duff <bobduff@shell01.TheWorld.com> writes:
>> Ray Blaak <rAYblaaK@STRIPCAPStelus.net> writes:
>> > or even worse:
>> >
>> >   try
>> >   {
>> >     doSomething();
>> >   }
>> >   catch (SomeError e)
>> >   {
>> >   }
>> 
>> Well, this part of the problem can't be blamed on the language.
>> This code is just plain bad practise.  The solution is better
>> training for programmers, not better language design
>
> Well, you are right in theory. The problem is that such naive programmers are
> directed by the compiler to do something about the exception, and being naive
> they make this mistake. Training is hard, and this particular problem is
> unexpectedly pervasive.

I agree that training is hard, but this particular case seems pretty
obvious.  One can have a coding convention, and enforce it by code
reviews.  The compiler could warn about the above evil.  The language
could define such a warning to be required.  As in all cases of a
warning that is sometimes wrong, you need a way to suppress the message
locally.

Really, if a programmer doesn't understand why the above code is bad
practise, the only imaginable solution is better training -- whether or
not the language has Java-like rules that might encourage such bad
practise.  As I said, I've seen this bad practise in Ada, too -- some
programmer was getting a Constraint_Error at run time, didn't understand
why, and decided to put a penny in the fusebox.

- Bob



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-09 18:04             ` Robert A Duff
@ 2007-06-09 18:37               ` Dmitry A. Kazakov
  2007-06-09 20:43                 ` Robert A Duff
  0 siblings, 1 reply; 69+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-09 18:37 UTC (permalink / raw)


On Sat, 09 Jun 2007 14:04:23 -0400, Robert A Duff wrote:

> I can think of lots of rules that are not perfect, but are at least
> superior to the existing rule of silently ignoring the exception.
> 
> The simplest would be to terminate the entire program immediately.
> And print an error message on systems where that makes sense.
> Ada has no way to terminate the whole program (i.e. call "exit"),
> but it should.

Terminate the parent task and that should become equivalent to "exit".

> Or just print an error message.
> 
> Or raise Program_Error in the parent task at the point where that task
> awaits its dependents.  Option: abort all the siblings as well.
> 
> Or put the task to sleep, so the parent waits forever (and the
> programmer has to debug a "deadlock").

Maybe a sort of rendezvous on the predefined entry point with the parent
task? When the parent task accepts it, the exception is propagated out of
the point of rendezvous in the parent, while the offending task finally
rests in peace. When the parent task does not have this entry, then it
(with all its children) is terminated. The process continues until
rendezvous accepted or else death of the main task.

> My solution: allow the programmer to declare that certain regions of
> code cannot run out of memory.  The compiler must reserve enough memory
> (and if can't, then raise S_E before entering that region).  Of course,
> what you can do in such a region is implementation dependent.

Contracted exceptions? Let the user declare a subprogram with the contract
of no Storage_Error. Then the compiler checks that code and if it cannot
generate it in a way that would reserve all necessary memory before
entering the body, it would refuse to compile it.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-09 12:32                       ` Simon Wright
@ 2007-06-09 18:38                         ` Dmitry A. Kazakov
  2007-06-09 21:04                           ` Simon Wright
  2007-06-11 14:15                         ` Bob Spooner
  1 sibling, 1 reply; 69+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-09 18:38 UTC (permalink / raw)


On Sat, 09 Jun 2007 13:32:59 +0100, Simon Wright wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> 
>> On Fri, 08 Jun 2007 20:15:03 +0100, Simon Wright wrote:
>>
>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>>> 
>>>> Software and more narrowly exceptions cannot report own bugs. It
>>>> would be a very bad idea to exceptions for that, because vital
>>>> information about the reasons will be inevitably destroyed. The best
>>>> possible way is to break into debugger, stopping everything else.
>>> 
>>> I don't really understand the first sentence of this ..
>>
>> When the program has a bug, then it could be anything, including
>> reporting another or non-existing bug, raising exceptions (false
>> positive), not raising exception (false negative), whatever.
>>
>> Let the probability of a program state where it would have a false
>> positive be sufficiently greater than the probability of the states
>> with false negative. Then it is better not to report anything!
>>
>> What is known about these probabilities?
> 
> Not a lot .. an exception is raised because some assertion made by the
> designer/implementer of the library concerned has turned out to be
> false (the value will be in this range; the file will be open; the
> file is a valid XML document ...).

In Ariane case the physical value was in range but assertion failed.

I don't think that failed run-time assertions should be converted into
exceptions. Among many reasons, one is that this would break exception
contracts:

procedure Foo -- I don't aise Baz
begin
   pragma Assert (<something>); -- I raise Baz when not <something>

The contract would be a lie. Another reason is that you could not handle
Baz, because that would change the program behavior with and without
assertions checked. IMO run-time assertions is an utterly wrong idea.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-09 18:37               ` Dmitry A. Kazakov
@ 2007-06-09 20:43                 ` Robert A Duff
  2007-06-10  9:21                   ` Dmitry A. Kazakov
  2007-06-11 19:18                   ` Randy Brukardt
  0 siblings, 2 replies; 69+ messages in thread
From: Robert A Duff @ 2007-06-09 20:43 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:

> On Sat, 09 Jun 2007 14:04:23 -0400, Robert A Duff wrote:
>
>> I can think of lots of rules that are not perfect, but are at least
>> superior to the existing rule of silently ignoring the exception.
>> 
>> The simplest would be to terminate the entire program immediately.
>> And print an error message on systems where that makes sense.
>> Ada has no way to terminate the whole program (i.e. call "exit"),
>> but it should.
>
> Terminate the parent task and that should become equivalent to "exit".

Only if the parent task is the environment task.

>> Or just print an error message.
>> 
>> Or raise Program_Error in the parent task at the point where that task
>> awaits its dependents.  Option: abort all the siblings as well.
>> 
>> Or put the task to sleep, so the parent waits forever (and the
>> programmer has to debug a "deadlock").
>
> Maybe a sort of rendezvous on the predefined entry point with the parent
> task?

Maybe.  Will you let me define entries of the environment task?  ;-)

>... When the parent task accepts it, the exception is propagated out of
> the point of rendezvous in the parent, while the offending task finally
> rests in peace. When the parent task does not have this entry, then it
> (with all its children) is terminated. The process continues until
> rendezvous accepted or else death of the main task.

Hmm.  I guess the important thing is that the RM should define this
situation (exception propagation reaches the end of the task body) as an
error.  That would encourage implementations to print error messages,
and debuggers to take control in such situations.

Nothing prevents an implementation from printing an error message in
this situation already -- but it's not encouraged by the RM, any more
than encouraging the impl to print an error every time you assign 42 to
a variable.

>> My solution: allow the programmer to declare that certain regions of
>> code cannot run out of memory.  The compiler must reserve enough memory
>> (and if can't, then raise S_E before entering that region).  Of course,
>> what you can do in such a region is implementation dependent.
>
> Contracted exceptions? Let the user declare a subprogram with the contract
> of no Storage_Error. Then the compiler checks that code and if it cannot
> generate it in a way that would reserve all necessary memory before
> entering the body, it would refuse to compile it.

The implementation can always calculate (at link time) a worst-case
amount of stack space that might be needed.  The worst case might be the
size of the address space in some cases (recursion, X:String:=..., etc).
But the implementation cannot know statically whether that space will
be available at run time, unless the entire program has that property
(see SPARK).

- Bob



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-09 18:38                         ` Dmitry A. Kazakov
@ 2007-06-09 21:04                           ` Simon Wright
  2007-06-10  9:21                             ` Dmitry A. Kazakov
  0 siblings, 1 reply; 69+ messages in thread
From: Simon Wright @ 2007-06-09 21:04 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:

> On Sat, 09 Jun 2007 13:32:59 +0100, Simon Wright wrote:

>> Not a lot .. an exception is raised because some assertion made by
>> the designer/implementer of the library concerned has turned out to
>> be false (the value will be in this range; the file will be open;
>> the file is a valid XML document ...).
>
> In Ariane case the physical value was in range but assertion failed.

I thought it was a constraint check?

I was trying to make the point that some restraints on program
legality can be made in the language by defining constrained types,
others you're stuck with hand-coded checks:

   pragma Assert ({correct calling sequence}, "bad calling sequence");

or if you prefer

   if not {correct calling sequence} then
      raise Use_Error;
   end if;

All much of a muchness in terms of trying to make sure that the
program is correct and is used correctly.

> I don't think that failed run-time assertions should be converted
> into exceptions. Among many reasons, one is that this would break
> exception contracts:
>
> procedure Foo -- I don't aise Baz
> begin
>    pragma Assert (<something>); -- I raise Baz when not <something>

I had forgotten the context of this discussion, I was talking about
Ada :-)

Also, this check is about a precondition, if the caller violates the
precondition she has no right to expect me not to raise unheralded
exceptions!

> The contract would be a lie. Another reason is that you could not
> handle Baz, because that would change the program behavior with and
> without assertions checked. IMO run-time assertions is an utterly
> wrong idea.

As I said before, I see little difference between assertions &
predefined language checks in terms of where they should be
used. Clearly you shouldn't use an assertion where the thing being
checked is legitimate failure behaviour!

   pragma Assert (not Vessel_On_Firing_Range);
   Start_Test_Missile_Firing;

Of course you can suppress (some) language-defined checks, but then
you get undefined bahaviour at run time if the error condition
happens. Is it worse to get unexpected exceptions or to compute with
out-of-range data?

Best of course to prove that the error can't happen.

--S



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: Reconsidering assignment
  2007-06-07  9:27 ` Dmitry A. Kazakov
  2007-06-07 16:54   ` contracted exceptions (was Re: Reconsidering assignment) Ray Blaak
@ 2007-06-09 22:37   ` Maciej Sobczak
  2007-06-10  9:21     ` Dmitry A. Kazakov
  2007-06-11 18:57     ` Randy Brukardt
  1 sibling, 2 replies; 69+ messages in thread
From: Maciej Sobczak @ 2007-06-09 22:37 UTC (permalink / raw)


On 7 Cze, 11:27, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> > Some important foundations.
> > A type can be unconstrained/constrained. It can be also a subtype of
> > another type, adding some more constraints.
>
> New subtypes can also be obtained through generalization, i.e. by lifting
> constraints.

Yes, but then they are not SUBtypes. :-)

> For example, an enumeration type could be extended

BTW - the fact that I cannot make a subtype by selecting non-
contiguous subranges of enum values is really disappointing.

> > For types that have equivalent value-
> > and constraint- spaces, the rules for parameter passing are as
> > follows:
> > 1. "in" formal parameters can get actual parameters that have
> > constraints matching or stricter
> > 2. "out" formal parameters can get actual parameters that have
> > constraints matching or wider
> > 3. "in out" formal parameters can only get actual parameters that have
> > matching constraints.
>
> > Any violation of these rules leads to potential constraint error that
> > cannot be prevented at compile-time.
>
> This does not work because most of the base type operations will be lost.
>
>    function "+" (Left, Right : Integer) return Integer;
>
> This cannot be inherited by Positive according to your rules because the
> result is out.

Not necessarily. Note that "+" for Integer was there already by pure
magic and the programmer didn't have to implement it. Why not having
similar magic for subtypes of Integer?
This of course doesn't solve the general problem, because we can have
regular functions as well:

function My_Function(I : Integer) return Integer;

I'm not sure whether it should be inherited by Positive. I would say
no, for the reason of its return type.

> Thus the programmer will have to delegate it:
>
>    function "+" (Left, Right : Positive) return Positive is
>    begin
>       return Positive (Integer (Left) + Integer (Right));
>    end "+";

Not for the magic "+", probably yes for My_Function (and only if
My_Function still makes sense for the subtype - but it's the
programmer who should know; on the other hand, if it doesn't, then
maybe it should not be a subtype).

> which were ambiguous:
>
>    X : Integer := 1 + 1;
>
> is it Positive'(1)+Positive'(1) or Integer'(1)+Integer'(1)? You will need
> complex preference rules to resolve this mess.

It's a compile-time expression with the value 2.
Not very complex. ;-)

> > procedure Safe_Swap(X, Y : in out String) with X'Length = Y'Length;
>
> This does not change anything, because the constraint is not static.

But can be statically checked at the call site - most likely
conservatively, but nothing more is really needed. You can always
explicitly convert.

> The summary of your program is to map constraint [more generally,
> substitutability] violations onto types. You do this by disallowing
> operations, and disallowing is static relatively to the type of the
> operation. Hence to make it work, all constraints have to be static in the
> type scope. But the string length is not such a constraint.

It can be checked at the call site.

> > declare
> >   S1 : String := "abc";
> >   S2 : String := "xyz";
> >   S3 : String := "klmnop";
>
> S4 : String := Read_From_File;

Good point.

> > begin
> >   Safe_Swap(S1, S2); -- OK
> >   Safe_Swap(S1, S3); -- compile-time error
> >   Safe_Swap(S1, S3(1..3)); -- OK
>
> Safe_Swap(S1, S4); -- ?

Compiler should cowardly refuse it (that's what "conservative" means).
Add an explicit conversion (or view conversion or whatever other
mechanism that ensures the constraint is correct) and then the
compiler will be your friend.

> Note that Ada addresses this issue. If you wanted the above you should
> simply do the following:
>
> type Three_Character_String is new String (1..3);
> type Six_Character_String is new String (1..6);
>
> Done.

Yes. Lot's of typing.

> If you use String instead, then there must be a reason for.

Of course. The point is that this presumed reason is incompatible with
swapping with statically constrained Strings.
Short version:

declare
  S1 : String := "abc"; -- statically constrained
  S2 : String := Read_From_File; -- statically unknown constraint
begin
  Swap(S1, S2); -- no-no
end;

I find it difficult to imagine a practical situation where it would
make sense.

> > Now - what am I missing? :-)
>
> That Constraint_Error is a valid outcome.

Somehow the "Error" part of the name doesn't go hand in hand with
"valid outcome". The whole point of having C_E is to signal *invalid*
outcome and all my speculations are about avoiding it.

> The problem is not that "-" of
> Integer is inherited by Positive.

Sure. Positive gets its own "-" by the same magic that gifted it to
Integer in the first place.

> It shall be.

I'm not sure about this.

> I would like to see contracted exceptions.

Java guys failed with this exercise, but I can imagine it in some
other contexts.

> procedure Foo is
>    X : Integer := -1;
>    Y : Positive := 1;
> begin
>    Swap (X, Y); --Illegal
> end Foo;
>
> The contract of Foo does not have Constraint_Error, but Swap has it.

Safe_Swap doesn't. That's my point.
And Safe_Swap will not compile in the above context. That's my point
as well.

> Let Swap have no Constraint_Error in the contract, then it cannot be
> inherited by Positive, because the inheritance will compose it with
> Integer->Positive, which has Constraint_Error in its contract. So, you'll
> be forced to either override it or drop inheritance...

I would drop inheritance.

> or redesign Foo:
>
> procedure Foo is
>    X : Integer := -1;
>    Y : Positive := 1;
> begin
>    Swap (X, Y);
> exception
>    when Constraint_Error =>
>       -- Aha!
>       ...
> end Foo;

My version:

procedure Foo is
  X : Integer := -1;
  Y := Positive := 1;
begin
  Safe_Swap(X, Integer'(Y)); -- explicit conversion (*), beware!
exception
  when Constraint_Error =>
    -- Aha! I was explicitly asking for troubles and I got them
    ...
end Foo;

(*) Let's assume this conversion works on "references" and doesn't
create temporaries.

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-09 20:43                 ` Robert A Duff
@ 2007-06-10  9:21                   ` Dmitry A. Kazakov
  2007-06-11 19:18                   ` Randy Brukardt
  1 sibling, 0 replies; 69+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-10  9:21 UTC (permalink / raw)


On Sat, 09 Jun 2007 16:43:08 -0400, Robert A Duff wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> 
>> Maybe a sort of rendezvous on the predefined entry point with the parent
>> task?
> 
> Maybe.  Will you let me define entries of the environment task?  ;-)

No, but you can always design it as:

env task
   appl. Ada root task
      all other children

>>... When the parent task accepts it, the exception is propagated out of
>> the point of rendezvous in the parent, while the offending task finally
>> rests in peace. When the parent task does not have this entry, then it
>> (with all its children) is terminated. The process continues until
>> rendezvous accepted or else death of the main task.
> 
> Hmm.  I guess the important thing is that the RM should define this
> situation (exception propagation reaches the end of the task body) as an
> error.  That would encourage implementations to print error messages,
> and debuggers to take control in such situations.

Printing messages is not enough. One would like to be able to handle this
within the program. BTW, if task were a controlled type, you know... (:-))

>>> My solution: allow the programmer to declare that certain regions of
>>> code cannot run out of memory.  The compiler must reserve enough memory
>>> (and if can't, then raise S_E before entering that region).  Of course,
>>> what you can do in such a region is implementation dependent.
>>
>> Contracted exceptions? Let the user declare a subprogram with the contract
>> of no Storage_Error. Then the compiler checks that code and if it cannot
>> generate it in a way that would reserve all necessary memory before
>> entering the body, it would refuse to compile it.
> 
> The implementation can always calculate (at link time) a worst-case
> amount of stack space that might be needed.  The worst case might be the
> size of the address space in some cases (recursion, X:String:=..., etc).
> But the implementation cannot know statically whether that space will
> be available at run time, unless the entire program has that property

and "no Storage_Error" contract could be an easy way to have this property
on subprogram basis. It does not say that Storage_Error will not be
propagated at a call point. It says that it will not if the caller has no
Storage_Error in its contract as well.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-09 21:04                           ` Simon Wright
@ 2007-06-10  9:21                             ` Dmitry A. Kazakov
  2007-06-10 11:49                               ` Simon Wright
  2007-06-10 18:12                               ` Georg Bauhaus
  0 siblings, 2 replies; 69+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-10  9:21 UTC (permalink / raw)


On Sat, 09 Jun 2007 22:04:24 +0100, Simon Wright wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> 
>> On Sat, 09 Jun 2007 13:32:59 +0100, Simon Wright wrote:
> 
> I was trying to make the point that some restraints on program
> legality can be made in the language by defining constrained types,
> others you're stuck with hand-coded checks:
> 
>    pragma Assert ({correct calling sequence}, "bad calling sequence");
> 
> or if you prefer
> 
>    if not {correct calling sequence} then
>       raise Use_Error;
>    end if;
> 
> All much of a muchness in terms of trying to make sure that the
> program is correct and is used correctly.

That's OK. My point is that raising Use_Error is a correct behavior of the
program. It is not a bug. Therefore it has to be documented:

   "when the sequence is not this and that, then Use_Error is propagated."
 
Such sequences are legal sequences, like an illegal Ada program is a legal
input for an Ada compiler. Therefore the caller has to have a handler for
Use_Error or else document it, etc. This is why exceptions should be
contracted and not considered as "oops, we didn't think about this."

> Also, this check is about a precondition, if the caller violates the
> precondition she has no right to expect me not to raise unheralded
> exceptions!

Oh my. "If you don't do that, then I ..." (:-))

No, if the precondition was violated by the caller, then how this caller is
supposed to handle the exception it does not know? And why would you rely
on this handling, provided that it is exactly one who first violated the
contract?

If I designed pre-/postcondition/invariant stuff for Ada, then I would
consider implementation of all run-time checks in an independent task with
own stack. A violation would immediately about the monitored task, and the
exception would be propagated in the monitor task.
 
>> The contract would be a lie. Another reason is that you could not
>> handle Baz, because that would change the program behavior with and
>> without assertions checked. IMO run-time assertions is an utterly
>> wrong idea.
> 
> As I said before, I see little difference between assertions &
> predefined language checks in terms of where they should be
> used. Clearly you shouldn't use an assertion where the thing being
> checked is legitimate failure behaviour!
> 
>    pragma Assert (not Vessel_On_Firing_Range);
>    Start_Test_Missile_Firing;

Wasn't it an anti-vessel missile?... (:-))

Yes this is what I meant. The above would be legal, and people would use
it, no matter what guidelines say.

> Of course you can suppress (some) language-defined checks, but then
> you get undefined bahaviour at run time if the error condition
> happens. Is it worse to get unexpected exceptions or to compute with
> out-of-range data?

It is same, without any assumptions about the nature of the error. These
assumptions cannot be reasonably made for unknown in advance errors.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: Reconsidering assignment
  2007-06-09 22:37   ` Reconsidering assignment Maciej Sobczak
@ 2007-06-10  9:21     ` Dmitry A. Kazakov
  2007-06-11  9:04       ` Maciej Sobczak
  2007-06-11 18:57     ` Randy Brukardt
  1 sibling, 1 reply; 69+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-10  9:21 UTC (permalink / raw)


On Sat, 09 Jun 2007 15:37:53 -0700, Maciej Sobczak wrote:

> On 7 Cze, 11:27, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
> 
>>> Some important foundations.
>>> A type can be unconstrained/constrained. It can be also a subtype of
>>> another type, adding some more constraints.
>>
>> New subtypes can also be obtained through generalization, i.e. by lifting
>> constraints.
> 
> Yes, but then they are not SUBtypes. :-)

subtype /= subset. Especially if you consider Liskov-Wing definitions. They
defines it in terms of substitutability. A more pragmatic definition would
be:

S is a subtype of T in an operation f when S inherits the interface of f.

>> For example, an enumeration type could be extended
> 
> BTW - the fact that I cannot make a subtype by selecting non-
> contiguous subranges of enum values is really disappointing.

That is because you cannot inherit "..", 'Succ and 'Pred. To have
non-contiguous enumerations, you should have them as a base type/interface
first.

>>> For types that have equivalent value-
>>> and constraint- spaces, the rules for parameter passing are as
>>> follows:
>>> 1. "in" formal parameters can get actual parameters that have
>>> constraints matching or stricter
>>> 2. "out" formal parameters can get actual parameters that have
>>> constraints matching or wider
>>> 3. "in out" formal parameters can only get actual parameters that have
>>> matching constraints.
>>
>>> Any violation of these rules leads to potential constraint error that
>>> cannot be prevented at compile-time.
>>
>> This does not work because most of the base type operations will be lost.
>>
>>    function "+" (Left, Right : Integer) return Integer;
>>
>> This cannot be inherited by Positive according to your rules because the
>> result is out.
> 
> Not necessarily. Note that "+" for Integer was there already by pure
> magic and the programmer didn't have to implement it. Why not having
> similar magic for subtypes of Integer?

Again, it is no matter how "+" is implemented, what matters is its
interface = whether "+" is primitive on Integer'Class.

>> which were ambiguous:
>>
>>    X : Integer := 1 + 1;
>>
>> is it Positive'(1)+Positive'(1) or Integer'(1)+Integer'(1)? You will need
>> complex preference rules to resolve this mess.
> 
> It's a compile-time expression with the value 2.
> Not very complex. ;-)

It is complex, because 1 (as any literal) is a function, an overloaded one.
Positive inherits 1 from Integer. It does not 0.

>> The summary of your program is to map constraint [more generally,
>> substitutability] violations onto types. You do this by disallowing
>> operations, and disallowing is static relatively to the type of the
>> operation. Hence to make it work, all constraints have to be static in the
>> type scope. But the string length is not such a constraint.
> 
> It can be checked at the call site.

>>> declare
>>>   S1 : String := "abc";
>>>   S2 : String := "xyz";
>>>   S3 : String := "klmnop";
>>
>> S4 : String := Read_From_File;
> 
> Good point.
> 
>>> begin
>>>   Safe_Swap(S1, S2); -- OK
>>>   Safe_Swap(S1, S3); -- compile-time error
>>>   Safe_Swap(S1, S3(1..3)); -- OK
>>
>> Safe_Swap(S1, S4); -- ?
> 
> Compiler should cowardly refuse it (that's what "conservative" means).

No, this wouldn't be a typed system anymore. S2 and S4 have exactly the
same type. Therefore there cannot be a type error in Safe_Swap (S1, S4) and
no one in (S1, S2). It would be just inconsistent.

Ada has statically constrained types for this. This is how a typed language
works. If you want to distinguish something between legal and an illegal
you need different types. Legality cannot depend on a constraint. You have
to promote the constraint to a new type.

>>> Now - what am I missing? :-)
>>
>> That Constraint_Error is a valid outcome.
> 
> Somehow the "Error" part of the name doesn't go hand in hand with
> "valid outcome". The whole point of having C_E is to signal *invalid*
> outcome and all my speculations are about avoiding it.

Huh, it is like: the whole point of having -1 is to signal an invalid
return code for fread!

As long as a correct program runs, everything it does is valid. This by the
way is the definition of "correct program." Constraint_Error signals
nothing, it is propagated according to the contract of its emitter.

>> The problem is not that "-" of
>> Integer is inherited by Positive.
> 
> Sure. Positive gets its own "-" by the same magic that gifted it to
> Integer in the first place.

And what does the magic say about 0-1?

>> It shall be.
> 
> I'm not sure about this.

About what? You said that Positive gets [own] "-". The implementation is
irrelevant, as always. The fact is -- Positive inherits the interface of
"-" from Integer. It must be this way. It means that Positive is a subtype
of Integer in "-". Then your magic comes into play to deliver positive 0-1.
 
>> Let Swap have no Constraint_Error in the contract, then it cannot be
>> inherited by Positive, because the inheritance will compose it with
>> Integer->Positive, which has Constraint_Error in its contract. So, you'll
>> be forced to either override it or drop inheritance...
> 
> I would drop inheritance.

No need to change anything then:

type Positive is range 1..Integer'Last;

>> or redesign Foo:
>>
>> procedure Foo is
>>    X : Integer := -1;
>>    Y : Positive := 1;
>> begin
>>    Swap (X, Y);
>> exception
>>    when Constraint_Error =>
>>       -- Aha!
>>       ...
>> end Foo;
> 
> My version:
> 
> procedure Foo is
>   X : Integer := -1;
>   Y := Positive := 1;
> begin
>   Safe_Swap(X, Integer'(Y)); -- explicit conversion (*), beware!

That is not a conversion and so illegal for an in out parameter. A
conversion would be:

   Safe_Swap (X, Integer (Y)); -- Legal Ada, works for in out

> (*) Let's assume this conversion works on "references" and doesn't
> create temporaries.

Why? The compiler is free to implement it copy-in, copy-out, the result
will be same. There is no need in referential semantics what that is not
the problem space requirement. Ada's design [rightfully] tires to remove
any differences between by-value and by-reference.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-10  9:21                             ` Dmitry A. Kazakov
@ 2007-06-10 11:49                               ` Simon Wright
  2007-06-10 15:20                                 ` Dmitry A. Kazakov
  2007-06-10 18:14                                 ` Georg Bauhaus
  2007-06-10 18:12                               ` Georg Bauhaus
  1 sibling, 2 replies; 69+ messages in thread
From: Simon Wright @ 2007-06-10 11:49 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:

> On Sat, 09 Jun 2007 22:04:24 +0100, Simon Wright wrote:

>> Also, this check is about a precondition, if the caller violates
>> the precondition she has no right to expect me not to raise
>> unheralded exceptions!
>
> Oh my. "If you don't do that, then I ..." (:-))
>
> No, if the precondition was violated by the caller, then how this
> caller is supposed to handle the exception it does not know? And why
> would you rely on this handling, provided that it is exactly one who
> first violated the contract?

How is the callee supposed to handle the contract violation? The whole
program is unsafe.



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-10 11:49                               ` Simon Wright
@ 2007-06-10 15:20                                 ` Dmitry A. Kazakov
  2007-06-11  4:13                                   ` Ray Blaak
  2007-06-10 18:14                                 ` Georg Bauhaus
  1 sibling, 1 reply; 69+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-10 15:20 UTC (permalink / raw)


On Sun, 10 Jun 2007 12:49:46 +0100, Simon Wright wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> 
>> On Sat, 09 Jun 2007 22:04:24 +0100, Simon Wright wrote:
> 
>>> Also, this check is about a precondition, if the caller violates
>>> the precondition she has no right to expect me not to raise
>>> unheralded exceptions!
>>
>> Oh my. "If you don't do that, then I ..." (:-))
>>
>> No, if the precondition was violated by the caller, then how this
>> caller is supposed to handle the exception it does not know? And why
>> would you rely on this handling, provided that it is exactly one who
>> first violated the contract?
> 
> How is the callee supposed to handle the contract violation? The whole
> program is unsafe.

Right, this is why continuation in any form, including raising exceptions,
is unsafe. There must be an independent program [a judge] to handle the
case.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-10  9:21                             ` Dmitry A. Kazakov
  2007-06-10 11:49                               ` Simon Wright
@ 2007-06-10 18:12                               ` Georg Bauhaus
  2007-06-11  7:55                                 ` Dmitry A. Kazakov
  1 sibling, 1 reply; 69+ messages in thread
From: Georg Bauhaus @ 2007-06-10 18:12 UTC (permalink / raw)


On Sun, 2007-06-10 at 11:21 +0200, Dmitry A. Kazakov wrote: 
> exceptions should be
> contracted and not considered as "oops, we didn't think about this."

That's a good one. We should document what we didn't think about.


> > Also, this check is about a precondition, if the caller violates the
> > precondition she has no right to expect me not to raise unheralded
> > exceptions!
> 
> Oh my. "If you don't do that, then I ..." (:-))

"If you don't do that, then I might ..." is precisely the point of DbC.






^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-10 11:49                               ` Simon Wright
  2007-06-10 15:20                                 ` Dmitry A. Kazakov
@ 2007-06-10 18:14                                 ` Georg Bauhaus
  1 sibling, 0 replies; 69+ messages in thread
From: Georg Bauhaus @ 2007-06-10 18:14 UTC (permalink / raw)


On Sun, 2007-06-10 at 12:49 +0100, Simon Wright wrote: 
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> 
> > On Sat, 09 Jun 2007 22:04:24 +0100, Simon Wright wrote:
> 
> >> Also, this check is about a precondition, if the caller violates
> >> the precondition she has no right to expect me not to raise
> >> unheralded exceptions!
> >
> > Oh my. "If you don't do that, then I ..." (:-))
> >
> > No, if the precondition was violated by the caller, then how this
> > caller is supposed to handle the exception it does not know?

If the precondition was violated by the caller then, yes, an assertion
error will ensue; obviously, the caller is not prepared to handle the
error because that's the point of contracts: that caller fulfills the
precondition of callee and this will get it the postcondition, not the
precondition or its violation. If not, there is a bug that the party
that *states* the contract cannot take care of, being a callee whose
contract was not fulfilled.

Obviously, the caller has a bug. I have not yet heard of a way
to document unknown caller bugs whatever contracts.






^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-10 15:20                                 ` Dmitry A. Kazakov
@ 2007-06-11  4:13                                   ` Ray Blaak
  2007-06-11  7:58                                     ` Dmitry A. Kazakov
  0 siblings, 1 reply; 69+ messages in thread
From: Ray Blaak @ 2007-06-11  4:13 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> Right, this is why continuation in any form, including raising exceptions,
> is unsafe. There must be an independent program [a judge] to handle the
> case.

What to do depends on the program in question. A quiet quick death would be
the worst thing to do for a common office-like desktop application.

At the very least it should report to the user some indication of the problem,
along with an email to send bug reports to. It would be more user friendly to
at least stay alive, giving the user a change to salvage some sort of work
they were doing. Sure, things could be theoretically corrupted, but contrast
that with the clear certainty of losing all of one's work and the tradeoff
points become quite clear.

Do to absolutely nothing, leaving it up to some external judge/debugger
program, is in practice completely ridiculous.

-- 
Cheers,                                        The Rhythm is around me,
                                               The Rhythm has control.
Ray Blaak                                      The Rhythm is inside me,
rAYblaaK@STRIPCAPStelus.net                    The Rhythm has my soul.



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-10 18:12                               ` Georg Bauhaus
@ 2007-06-11  7:55                                 ` Dmitry A. Kazakov
  0 siblings, 0 replies; 69+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-11  7:55 UTC (permalink / raw)


On Sun, 10 Jun 2007 20:12:48 +0200, Georg Bauhaus wrote:

> On Sun, 2007-06-10 at 11:21 +0200, Dmitry A. Kazakov wrote: 

>> Oh my. "If you don't do that, then I ..." (:-))
> 
> "If you don't do that, then I might ..." is precisely the point of DbC.

In that context "do" was "respect the contract." DbC assumes that all
parties always do it, if they don't then we cannot apply any DbC reasoning
about what is going on: 42.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-11  4:13                                   ` Ray Blaak
@ 2007-06-11  7:58                                     ` Dmitry A. Kazakov
  2007-06-11 17:06                                       ` Ray Blaak
  0 siblings, 1 reply; 69+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-11  7:58 UTC (permalink / raw)


On Mon, 11 Jun 2007 04:13:52 GMT, Ray Blaak wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:

>> Right, this is why continuation in any form, including raising exceptions,
>> is unsafe. There must be an independent program [a judge] to handle the
>> case.
> 
> What to do depends on the program in question. A quiet quick death would be
> the worst thing to do for a common office-like desktop application.

Surely the best thing is to corrupt all open documents and ones in reach,
accompanied by system resources leakage. The second good is to pop up a
modal panic message dialog in an endless loop. That would show the customer
that guys really worked hard on fault tolerance...

> Do to absolutely nothing, leaving it up to some external judge/debugger
> program, is in practice completely ridiculous.

You took it out of context, which was: continuation is unsafe (=>
impossible).

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: Reconsidering assignment
  2007-06-10  9:21     ` Dmitry A. Kazakov
@ 2007-06-11  9:04       ` Maciej Sobczak
  2007-06-11 13:09         ` Dmitry A. Kazakov
  0 siblings, 1 reply; 69+ messages in thread
From: Maciej Sobczak @ 2007-06-11  9:04 UTC (permalink / raw)


On 10 Cze, 11:21, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> >> New subtypes can also be obtained through generalization, i.e. by lifting
> >> constraints.
>
> > Yes, but then they are not SUBtypes. :-)
>
> subtype /= subset. Especially if you consider Liskov-Wing definitions. They
> defines it in terms of substitutability. A more pragmatic definition would
> be:
>
> S is a subtype of T in an operation f when S inherits the interface of f.

I don't see how this might imply anything. If f cares about
preconditions on its arguments, then being a subtype means being a
subset (and if f doesn't care about preconditions then there is little
sense in implying any relation between T and S based on f).
Lifting constraints doesn't give subtypes. Supertype is the correct
term here.

> > BTW - the fact that I cannot make a subtype by selecting non-
> > contiguous subranges of enum values is really disappointing.
>
> That is because you cannot inherit "..", 'Succ and 'Pred. To have
> non-contiguous enumerations, you should have them as a base type/interface
> first.

Yes, this is what I expect:

type Color is (Black, Red, Green, Blue, White);

I don't want any "..", 'Succ nor 'Pred here.

> >> which were ambiguous:
>
> >>    X : Integer := 1 + 1;
>
> >> is it Positive'(1)+Positive'(1) or Integer'(1)+Integer'(1)? You will need
> >> complex preference rules to resolve this mess.
>
> > It's a compile-time expression with the value 2.
> > Not very complex. ;-)
>
> It is complex, because 1 (as any literal) is a function, an overloaded one.

No. Compile-time expression is not executed in the universe of
functions overloaded in the program. It can use completely separate
rules - what matters is the result and whether it fits in the given
type.

> >>>   S1 : String := "abc";

> >> S4 : String := Read_From_File;

> >> Safe_Swap(S1, S4); -- ?
>
> > Compiler should cowardly refuse it (that's what "conservative" means).
>
> No, this wouldn't be a typed system anymore.

Then let's make the constraint part of the type.

> S2 and S4 have exactly the
> same type.

Then let's make them different.

> If you want to distinguish something between legal and an illegal
> you need different types. Legality cannot depend on a constraint.

The whole point of my speculations is to elevate constraints to the
level where they could take part in legality resolutions. I hoped it
was clear.

> >>> Now - what am I missing? :-)
>
> >> That Constraint_Error is a valid outcome.

> As long as a correct program runs, everything it does is valid.

For the appropriate definitioin of "runs". :-)

> >> The problem is not that "-" of
> >> Integer is inherited by Positive.
>
> > Sure. Positive gets its own "-" by the same magic that gifted it to
> > Integer in the first place.
>
> And what does the magic say about 0-1?

It's not only "-". You can overflow the upper constraints as well.
This is, I admit, the place where the whole system gets clunky.
It would be insane to expect programmers to write explicit casts (to
satisfy the "innocent code doesn't lie") absolutely everywhere where
the result of the operation can go out of LHS constraints, because
that would basically hit every arithmetic operation, not only
"-" (except for modulo types, which would be the only "pure safe").
SPARK solves this outside of the type system, but that was not the
intention of my experiment.

So, I admit, the common arithmetics is a place where C_E seems to be
necessary as a "valid" outcome. If explicit casts would be used
everywhere to mark the possibility of having C_E, then we might as
well drop the casts and have this possibility implicitly:

A := Positive(B + C);  -- beware C_E, too much typing
X := Y + Z;            -- beware C_E anyway

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: Reconsidering assignment
  2007-06-11  9:04       ` Maciej Sobczak
@ 2007-06-11 13:09         ` Dmitry A. Kazakov
  0 siblings, 0 replies; 69+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-11 13:09 UTC (permalink / raw)


On Mon, 11 Jun 2007 02:04:19 -0700, Maciej Sobczak wrote:

> On 10 Cze, 11:21, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
> 
>>>> New subtypes can also be obtained through generalization, i.e. by lifting
>>>> constraints.
>>
>>> Yes, but then they are not SUBtypes. :-)
>>
>> subtype /= subset. Especially if you consider Liskov-Wing definitions. They
>> defines it in terms of substitutability. A more pragmatic definition would
>> be:
>>
>> S is a subtype of T in an operation f when S inherits the interface of f.
> 
> I don't see how this might imply anything. If f cares about
> preconditions on its arguments, then being a subtype means being a
> subset (and if f doesn't care about preconditions then there is little
> sense in implying any relation between T and S based on f).

1. Ada and other languages have subtypes, but to preconditions.

2. Program correctness (if you meant that following Liskov-Wing) has
nothing to do with subtyping. Correctness is a property of a given program.
Subtyping is a relation between types in a program, which occasionally
might be correct or incorrect. They tried to bind them and failed, because
types systems are too weak to express correctness.

But anyway, the domain sets of the types need not to be proper subsets of
each other in any of these two definitions. There might be some mapping
required, but no more than that. Consider Cartesian product, it is LSP
compatible. (Example: Ellipse inheriting x-axis from Circle).

> Lifting constraints doesn't give subtypes.

LSP certainly does. For example, int is a proper LSP subtype of const int.
Adding constraints is much more offending for LSP subtyping than lifting,
because it breaks in-operations, which are more common.

>>> BTW - the fact that I cannot make a subtype by selecting non-
>>> contiguous subranges of enum values is really disappointing.
>>
>> That is because you cannot inherit "..", 'Succ and 'Pred. To have
>> non-contiguous enumerations, you should have them as a base type/interface
>> first.
> 
> Yes, this is what I expect:
> 
> type Color is (Black, Red, Green, Blue, White);
> 
> I don't want any "..", 'Succ nor 'Pred here.

Then you should understand why I am arguing against that hard-wired stuff
(which includes assignment) in favor of abstract interfaces (of unordered /
ordered enumerations and whatever else). People designing Ada's
"enumeration class" considered some semantics to be applicable in all
cases. You do same presuming that ":=" has some God-written properties.

> No. Compile-time expression is not executed in the universe of
> functions overloaded in the program. It can use completely separate
> rules - what matters is the result and whether it fits in the given
> type.

Yuck, how many languages would you have in one? I don't want it. I want a
small regular predictable language.
 
> Then let's make the constraint part of the type.

In that case you will be unable to write programs where that part could
vary.

One of the great contributions Ada made to typed systems was dynamically
constrained types and generic programming in terms of those types. We need
not to go back to Pascal.

>> If you want to distinguish something between legal and an illegal
>> you need different types. Legality cannot depend on a constraint.
> 
> The whole point of my speculations is to elevate constraints to the
> level where they could take part in legality resolutions. I hoped it
> was clear.

but failed to propose a framework for that. Honestly, it is a very complex
problem of how to enforce statically known constraints to be evaluated at
compile time. Once solved, it would immensely simplify the language and the
libraries of. But beware, it might make generics useless! (:-))

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-09 12:32                       ` Simon Wright
  2007-06-09 18:38                         ` Dmitry A. Kazakov
@ 2007-06-11 14:15                         ` Bob Spooner
  2007-06-11 15:14                           ` Georg Bauhaus
  2007-06-11 19:50                           ` Simon Wright
  1 sibling, 2 replies; 69+ messages in thread
From: Bob Spooner @ 2007-06-11 14:15 UTC (permalink / raw)


"Simon Wright" <simon.j.wright@mac.com> wrote in message 
news:m27iqd8g04.fsf@mac.com...
> ... I agree that an exception message isn't of any use to the end user (I
> suppose they may grow to learn that some messages happen because of
> particular sequences of operations, and to avoid those sequences).
The exception message may be of use if it says that the problem is a missing 
data file that the user forgot to provide.
Bob 





^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-11 14:15                         ` Bob Spooner
@ 2007-06-11 15:14                           ` Georg Bauhaus
  2007-06-11 15:20                             ` (see below)
  2007-06-11 19:50                           ` Simon Wright
  1 sibling, 1 reply; 69+ messages in thread
From: Georg Bauhaus @ 2007-06-11 15:14 UTC (permalink / raw)


On Mon, 2007-06-11 at 10:15 -0400, Bob Spooner wrote:
> "Simon Wright" <simon.j.wright@mac.com> wrote in message 
> news:m27iqd8g04.fsf@mac.com...
> > ... I agree that an exception message isn't of any use to the end user (I
> > suppose they may grow to learn that some messages happen because of
> > particular sequences of operations, and to avoid those sequences).
> The exception message may be of use if it says that the problem is a missing 
> data file that the user forgot to provide.

No message at all leads to Kafka effects.





^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-11 15:14                           ` Georg Bauhaus
@ 2007-06-11 15:20                             ` (see below)
  2007-06-11 16:39                               ` Georg Bauhaus
  0 siblings, 1 reply; 69+ messages in thread
From: (see below) @ 2007-06-11 15:20 UTC (permalink / raw)


On 11/6/07 16:14, in article 1181574891.16521.1.camel@kartoffel, "Georg
Bauhaus" <rm.tsoh+bauhaus@maps.futureapps.de> wrote:

> On Mon, 2007-06-11 at 10:15 -0400, Bob Spooner wrote:
>> "Simon Wright" <simon.j.wright@mac.com> wrote in message
>> news:m27iqd8g04.fsf@mac.com...
>>> ... I agree that an exception message isn't of any use to the end user (I
>>> suppose they may grow to learn that some messages happen because of
>>> particular sequences of operations, and to avoid those sequences).
>> The exception message may be of use if it says that the problem is a missing
>> data file that the user forgot to provide.
> 
> No message at all leads to Kafka effects.

The user turns into a giant cockroach?

-- 
Bill Findlay
<surname><forename> chez blueyonder.co.uk





^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-11 15:20                             ` (see below)
@ 2007-06-11 16:39                               ` Georg Bauhaus
  0 siblings, 0 replies; 69+ messages in thread
From: Georg Bauhaus @ 2007-06-11 16:39 UTC (permalink / raw)


On Mon, 2007-06-11 at 16:20 +0100, (see below) wrote:
> On 11/6/07 16:14, in article 1181574891.16521.1.camel@kartoffel, "Georg
> Bauhaus" <rm.tsoh+bauhaus@maps.futureapps.de> wrote:
> 
> > On Mon, 2007-06-11 at 10:15 -0400, Bob Spooner wrote:
> >> "Simon Wright" <simon.j.wright@mac.com> wrote in message
> >> news:m27iqd8g04.fsf@mac.com...
> >>> ... I agree that an exception message isn't of any use to the end user (I
> >>> suppose they may grow to learn that some messages happen because of
> >>> particular sequences of operations, and to avoid those sequences).
> >> The exception message may be of use if it says that the problem is a missing
> >> data file that the user forgot to provide.
> > 
> > No message at all leads to Kafka effects.
> 
> The user turns into a giant cockroach?

To the bouncer, they might look like those, at some point.






^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-11  7:58                                     ` Dmitry A. Kazakov
@ 2007-06-11 17:06                                       ` Ray Blaak
  2007-06-11 19:57                                         ` Dmitry A. Kazakov
  0 siblings, 1 reply; 69+ messages in thread
From: Ray Blaak @ 2007-06-11 17:06 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> On Mon, 11 Jun 2007 04:13:52 GMT, Ray Blaak wrote:
> 
> > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> 
> >> Right, this is why continuation in any form, including raising exceptions,
> >> is unsafe. There must be an independent program [a judge] to handle the
> >> case.
> > 
> > What to do depends on the program in question. A quiet quick death would be
> > the worst thing to do for a common office-like desktop application.
> 
> Surely the best thing is to corrupt all open documents and ones in reach,
> accompanied by system resources leakage. The second good is to pop up a
> modal panic message dialog in an endless loop. That would show the customer
> that guys really worked hard on fault tolerance...

Ah, no. With decent exception handling (i.e. a sound central policy) in
practice apps tend to be able to survive gracefully. The guys really should be
working hard of fault tolerance.

Also, the possibility of corruption and leaks is only a possibility, and
trying to survive at least allows the user the possibility of the salvaging of
what they were doing.

> 
> > Do to absolutely nothing, leaving it up to some external judge/debugger
> > program, is in practice completely ridiculous.
> 
> You took it out of context, which was: continuation is unsafe (=>
> impossible).

I know the context, starting with "assertions should not cause unplanned
exceptions", and followed by "use the debugger to stop on such failures".

I can see this as a correct theoretical approach, but the problem is that both
items are not workable in practice. When an assertion is violated, control
flow *must* be aborted, since to continue is dangerous. Exceptions accomplish
this. But at the same time it is severely inconvenient to the user to just
crash the entire application. It is quite common that apps can set themselves
to a reasonably known state, and from there have some survivable work be
saved. If nothing else, one can try to save state to alternatve recovery files
to minimize chances of corruption of existing files. This is still a
controlled exit, better than simply stopping.

To be more clear: assertions *must* cause unplanned exceptions, and apps out
in the field cannot rely on a debugger.

Continuation is unsafe, but just stopping is not helpful either.

-- 
Cheers,                                        The Rhythm is around me,
                                               The Rhythm has control.
Ray Blaak                                      The Rhythm is inside me,
rAYblaaK@STRIPCAPStelus.net                    The Rhythm has my soul.



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: Reconsidering assignment
  2007-06-09 22:37   ` Reconsidering assignment Maciej Sobczak
  2007-06-10  9:21     ` Dmitry A. Kazakov
@ 2007-06-11 18:57     ` Randy Brukardt
  2007-06-11 21:12       ` Maciej Sobczak
  1 sibling, 1 reply; 69+ messages in thread
From: Randy Brukardt @ 2007-06-11 18:57 UTC (permalink / raw)


"Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message
news:1181428673.148991.76570@p77g2000hsh.googlegroups.com...
...
> > which were ambiguous:
> >
> >    X : Integer := 1 + 1;
> >
> > is it Positive'(1)+Positive'(1) or Integer'(1)+Integer'(1)? You will
need
> > complex preference rules to resolve this mess.
>
> It's a compile-time expression with the value 2.
> Not very complex. ;-)

Sorry, Dmitry is right; you seem to have missed his point. In order for this
to be "a compile-time expression", you need complex preference rules in your
type system. (That is, that "compile-time expressions" are preferred over
types that would cause some other kind of expression.) Such rules tend to be
very problematic in practice; they often have very counter-intuitive results
in some cases. Ada has very few of them for this reason, and the ones it has
do not include cases like this one.

It takes extreme care to design a self-consistent type system, and without
that care, it is impossible to say much of use on the topic.

                                 Randy.





^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-09 20:43                 ` Robert A Duff
  2007-06-10  9:21                   ` Dmitry A. Kazakov
@ 2007-06-11 19:18                   ` Randy Brukardt
  2007-06-12  6:55                     ` Jean-Pierre Rosen
  1 sibling, 1 reply; 69+ messages in thread
From: Randy Brukardt @ 2007-06-11 19:18 UTC (permalink / raw)


"Robert A Duff" <bobduff@shell01.TheWorld.com> wrote in message
news:wcck5uckgf7.fsf@shell01.TheWorld.com...
...
> >... When the parent task accepts it, the exception is propagated out of
> > the point of rendezvous in the parent, while the offending task finally
> > rests in peace. When the parent task does not have this entry, then it
> > (with all its children) is terminated. The process continues until
> > rendezvous accepted or else death of the main task.
>
> Hmm.  I guess the important thing is that the RM should define this
> situation (exception propagation reaches the end of the task body) as an
> error.  That would encourage implementations to print error messages,
> and debuggers to take control in such situations.
>
> Nothing prevents an implementation from printing an error message in
> this situation already -- but it's not encouraged by the RM, any more
> than encouraging the impl to print an error every time you assign 42 to
> a variable.

Ada 83 didn't have the concept of a bounded error, unfortunately, but this
would seem to be a place where it could have been profitably used (raising
Program_Error in the parent when waiting if the error is "detected"). The
problem is that "when waiting" is already too late (usually my programs have
deadlocked [or livelocked] by then). Some deadlocks are detected by our
runtime, but of course livelocks are just a program hang with no indication
why.

I'm not convinced that there is any decent solution to this problem
(printing messages can also deadlock the system, such as in the AdaIC
webserver, which can run headless). In any case, I consider a task without a
"when others" handler at the bottom (to do whatever is appropriate for the
application) broken.

                                       Randy.





^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-11 14:15                         ` Bob Spooner
  2007-06-11 15:14                           ` Georg Bauhaus
@ 2007-06-11 19:50                           ` Simon Wright
  1 sibling, 0 replies; 69+ messages in thread
From: Simon Wright @ 2007-06-11 19:50 UTC (permalink / raw)


"Bob Spooner" <rls19@psu.edu> writes:

> "Simon Wright" <simon.j.wright@mac.com> wrote in message 
> news:m27iqd8g04.fsf@mac.com...

>> ... I agree that an exception message isn't of any use to the end
>> user (I suppose they may grow to learn that some messages happen
>> because of particular sequences of operations, and to avoid those
>> sequences).

> The exception message may be of use if it says that the problem is a
> missing data file that the user forgot to provide.

With GNAT, the exception message would be something like
... NAME_ERROR ... which isn't a lot of help! If the programmer can go
to the trouble of reporting the missing file name, then he has quite
likely considered some sort of recovery mechanisms. I was thinking of
the sort of exception that hadn't been planned for.



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-11 17:06                                       ` Ray Blaak
@ 2007-06-11 19:57                                         ` Dmitry A. Kazakov
  0 siblings, 0 replies; 69+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-11 19:57 UTC (permalink / raw)


On Mon, 11 Jun 2007 17:06:19 GMT, Ray Blaak wrote:

> I know the context, starting with "assertions should not cause unplanned
> exceptions", and followed by "use the debugger to stop on such failures".

Bugs. The point is, to treat it as a failure, you have to invest some
efforts in the software infrastructure, to foresee the effect and possible
ways of handing.

> I can see this as a correct theoretical approach, but the problem is that both
> items are not workable in practice.

On the contrary, it has very practical consequences like documenting
exception contracts and designing exceptions in a way that would make
possible reasonable handling. For example, by removing side effects before
raising an exception.

All this does not apply to run-time assertions.

> Continuation is unsafe, but just stopping is not helpful either.

Right. Consider OS design. When an application fails, OS continues, the
application does not. If you want your software be fault-tolerant, design
it in a way, that potentially failing components could be independent
enough to survive each others fault. Never use assertions to check for
faults.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: Reconsidering assignment
  2007-06-11 18:57     ` Randy Brukardt
@ 2007-06-11 21:12       ` Maciej Sobczak
  2007-06-12  8:31         ` Dmitry A. Kazakov
  0 siblings, 1 reply; 69+ messages in thread
From: Maciej Sobczak @ 2007-06-11 21:12 UTC (permalink / raw)


On 11 Cze, 20:57, "Randy Brukardt" <r...@rrsoftware.com> wrote:

> > >    X : Integer := 1 + 1;

> > It's a compile-time expression with the value 2.
> > Not very complex. ;-)
>
> Sorry, Dmitry is right; you seem to have missed his point. In order for this
> to be "a compile-time expression", you need complex preference rules in your
> type system. (That is, that "compile-time expressions" are preferred over
> types that would cause some other kind of expression.)

Hm... indeed, that must be the case - there must be some logic to
allow the compiler to actually figure out that it is a compile-time
expression. Granted, such a logic might be a good candidate for the
optimizer (who wants function calls where the result can be immedately
available), but at the same time this is easiest to do when the type
system itself is very minimal.

I think there is time for some conclusions.
The major points I've learned in these discussions:

- Constraint_Error cannot be easily excluded with the use of legality
rules that are applied only locally. What I mean here is the rules
that can be checked only based on the static properties of names that
the compiler encounters in each expression (a type system, basically),
without information flow analysis and such.
- Unconstrained types in Ada can be used to "parameterize" whole
subprograms, even though these subprograms don't need to be proper
generics. Interestingly, no "implicit instantiation" is needed here
neither.

Thanks to all contributors and to Dmitry in particular.


Still (heck, that doesn't seem to be the end of discussion :-) ), the
earlier idea of expressing restrictions for subprogram parameters
looks interesting to me. The point is that subprogram overloading
operates on each parameter in isolation, whereas such restrictions
could add the possibility of selecting more convoluted subsets of the
whole relation. This is similar to treating the whole set of
parameters as a single record type and then constraining this single
record type for the purpose of overloading.
If the restriction is based on run-time properties of parameters, then
it doesn't provide anything that cannot be achieved with explicit if/
else at the beginning of the subprogram.
Consider:

procedure P(X, Y : Real) with X*X + Y*Y <= 1;
procedure P(X, Y : Real);

The idea was to have some assistance from the language for the proper
selection of overloaded P (one is for arguments that fall withing the
unit circle, and the other is for the rest). Here it doesn't give
anything fundamentally new, this can be achieved with if/else in a
single procedure.
On the other hand, restrictions for compile-time properties might be
more useful and can be for example an interesting optimization tool.
In C++ such effects are achieved with so called type traits and
(partial) template specializations. I wouldn't mind having this in
Ada.

--
Maciej Sobczak
http://www.msobczak.com/




^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: contracted exceptions
  2007-06-11 19:18                   ` Randy Brukardt
@ 2007-06-12  6:55                     ` Jean-Pierre Rosen
  0 siblings, 0 replies; 69+ messages in thread
From: Jean-Pierre Rosen @ 2007-06-12  6:55 UTC (permalink / raw)


Randy Brukardt a �crit :
> In any case, I consider a task without a
> "when others" handler at the bottom (to do whatever is appropriate for the
> application) broken.
> 
(Not missing an opportunity for a shameless plug)
Of course, AdaControl can check that every task *has* a "when other" 
handler.

-- 
---------------------------------------------------------
            J-P. Rosen (rosen@adalog.fr)
Visit Adalog's web site at http://www.adalog.fr



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: Reconsidering assignment
  2007-06-11 21:12       ` Maciej Sobczak
@ 2007-06-12  8:31         ` Dmitry A. Kazakov
  2007-06-12  9:31           ` Georg Bauhaus
  0 siblings, 1 reply; 69+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-12  8:31 UTC (permalink / raw)


On Mon, 11 Jun 2007 14:12:09 -0700, Maciej Sobczak wrote:

> Still (heck, that doesn't seem to be the end of discussion :-) ), the
> earlier idea of expressing restrictions for subprogram parameters
> looks interesting to me. The point is that subprogram overloading
> operates on each parameter in isolation, whereas such restrictions
> could add the possibility of selecting more convoluted subsets of the
> whole relation.

(Note that by allowing this you allow multiple-dispatch, with its more than
linear number of alternatives)

> This is similar to treating the whole set of
> parameters as a single record type and then constraining this single
> record type for the purpose of overloading.
> If the restriction is based on run-time properties of parameters, then
> it doesn't provide anything that cannot be achieved with explicit if/
> else at the beginning of the subprogram.
> Consider:
> 
> procedure P(X, Y : Real) with X*X + Y*Y <= 1;
> procedure P(X, Y : Real);
>
> The idea was to have some assistance from the language for the proper
> selection of overloaded P (one is for arguments that fall withing the
> unit circle, and the other is for the rest).

This cannot work because overloading resolution happens at compile-time,
while the conditions of matching, in your case are general run-time
expressions.

BTW, a similar mechanism exists for entry point barriers:

   entry P (X, Y : Real) when <condition>;

Though, note that for very strong reasons <condition> may not depend on the
entry point arguments.

Another objection is that it is again preferences and it is undecidable.
Consider:

   procedure P(X, Y : Real) when Halt (X);
   procedure P(X, Y : Real);

and it is ambiguous:

   procedure P(X, Y : Real) when X in -1..10;;
   procedure P(X, Y : Real) when X in -10..1;

which one to choose when X is 0?

Yet another point: P is a polymorphic subprogram. Various overloading are
implementations of. The condition clause controls the choice. Does not it
remind you anything? Make Real a class!

A general software design objection is that this breaks encapsulation. The
idea of type is that constraints like X*X+Y*Y<1 should be property of a
type. When you move them to procedures, you loose OO/ADT decomposition.

> Here it doesn't give
> anything fundamentally new, this can be achieved with if/else in a
> single procedure.

IMO there is great need in a language support for compile-time user-defined
expressions and decomposition subprograms into compile- and run-time parts.
The most obvious case is dimensioned expressions.

> On the other hand, restrictions for compile-time properties might be
> more useful and can be for example an interesting optimization tool.

Well, Optimizations are optional, a proper choice of P is not.

If you wanted to have an optimization tool, you should make both Ps in your
example legal:

   procedure P(X, Y : Real) when Memory_Is_Low;
   procedure P(X, Y : Real) when A_CPU_Core_Is_Free;

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: Reconsidering assignment
  2007-06-12  8:31         ` Dmitry A. Kazakov
@ 2007-06-12  9:31           ` Georg Bauhaus
  2007-06-12 10:03             ` Dmitry A. Kazakov
  0 siblings, 1 reply; 69+ messages in thread
From: Georg Bauhaus @ 2007-06-12  9:31 UTC (permalink / raw)


On Tue, 2007-06-12 at 10:31 +0200, Dmitry A. Kazakov wrote:
> On Mon, 11 Jun 2007 14:12:09 -0700, Maciej Sobczak wrote:

> > procedure P(X, Y : Real) with X*X + Y*Y <= 1;
> > procedure P(X, Y : Real);
> >
> > The idea was to have some assistance from the language for the proper
> > selection of overloaded P (one is for arguments that fall withing the
> > unit circle, and the other is for the rest).
> 
> This cannot work because overloading resolution happens at compile-time,
> while the conditions of matching, in your case are general run-time
> expressions.

As you explain further below, this is about template choice
computation by the compiler, I think.

> Yet another point: P is a polymorphic subprogram. Various overloading are
> implementations of. The condition clause controls the choice. Does not it
> remind you anything? Make Real a class!

Close to this is the Eiffel principle of using one name one and only
name for one entity, no overloading at all; if polymorphism is needed,
use overriding.

What about argument pattern matching?






^ permalink raw reply	[flat|nested] 69+ messages in thread

* Re: Reconsidering assignment
  2007-06-12  9:31           ` Georg Bauhaus
@ 2007-06-12 10:03             ` Dmitry A. Kazakov
  0 siblings, 0 replies; 69+ messages in thread
From: Dmitry A. Kazakov @ 2007-06-12 10:03 UTC (permalink / raw)


On Tue, 12 Jun 2007 11:31:37 +0200, Georg Bauhaus wrote:

> What about argument pattern matching?

Type inference? I don't like it. I prefer to see explicit ADT with its
operations.

BTW, what is the problem argument pattern matching is supposed to solve?
Multiple-dispatch? Then how patterns might help in fulfilling the
requirement that the dispatch never fails on any combination of arguments?
Comparing patterns (the formal languages of) is far more difficult. How
patterns get inherited? How to enforce execution of a defined part of the
constructor/destructor/procedure on all descendants using patterns? How to
compose a polymorphic body with them? etc.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 69+ messages in thread

end of thread, other threads:[~2007-06-12 10:03 UTC | newest]

Thread overview: 69+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-06-06 21:33 Reconsidering assignment Maciej Sobczak
2007-06-06 22:52 ` Ray Blaak
2007-06-07  7:15   ` Maciej Sobczak
2007-06-07 16:34     ` Ray Blaak
2007-06-07  7:10 ` Stefan Lucks
2007-06-07  7:32   ` Maciej Sobczak
2007-06-07 11:11     ` Stefan Lucks
2007-06-07 16:28   ` Ray Blaak
2007-06-07  9:27 ` Dmitry A. Kazakov
2007-06-07 16:54   ` contracted exceptions (was Re: Reconsidering assignment) Ray Blaak
2007-06-07 20:04     ` contracted exceptions Robert A Duff
2007-06-07 21:11       ` Ray Blaak
2007-06-07 23:44         ` Robert A Duff
2007-06-08  2:19       ` Randy Brukardt
2007-06-08  7:39         ` Dmitry A. Kazakov
2007-06-08  8:53           ` Ray Blaak
2007-06-08 12:08             ` Dmitry A. Kazakov
2007-06-08 17:31               ` Ray Blaak
2007-06-08 18:00                 ` Dmitry A. Kazakov
2007-06-08 18:20                   ` Georg Bauhaus
2007-06-08 18:56                     ` Dmitry A. Kazakov
2007-06-08 19:15                   ` Simon Wright
2007-06-09  0:14                     ` Randy Brukardt
2007-06-09  2:44                       ` Larry Kilgallen
2007-06-09  8:21                     ` Dmitry A. Kazakov
2007-06-09 12:32                       ` Simon Wright
2007-06-09 18:38                         ` Dmitry A. Kazakov
2007-06-09 21:04                           ` Simon Wright
2007-06-10  9:21                             ` Dmitry A. Kazakov
2007-06-10 11:49                               ` Simon Wright
2007-06-10 15:20                                 ` Dmitry A. Kazakov
2007-06-11  4:13                                   ` Ray Blaak
2007-06-11  7:58                                     ` Dmitry A. Kazakov
2007-06-11 17:06                                       ` Ray Blaak
2007-06-11 19:57                                         ` Dmitry A. Kazakov
2007-06-10 18:14                                 ` Georg Bauhaus
2007-06-10 18:12                               ` Georg Bauhaus
2007-06-11  7:55                                 ` Dmitry A. Kazakov
2007-06-11 14:15                         ` Bob Spooner
2007-06-11 15:14                           ` Georg Bauhaus
2007-06-11 15:20                             ` (see below)
2007-06-11 16:39                               ` Georg Bauhaus
2007-06-11 19:50                           ` Simon Wright
2007-06-08 11:26         ` Martin Krischik
2007-06-08 12:02         ` Robert A Duff
2007-06-08 11:22     ` contracted exceptions (was Re: Reconsidering assignment) Martin Krischik
2007-06-08 17:44       ` Ray Blaak
2007-06-08 12:10     ` contracted exceptions Robert A Duff
2007-06-08 15:56       ` Stefan Lucks
2007-06-08 20:27         ` Pascal Obry
2007-06-09  0:19           ` Randy Brukardt
2007-06-09 18:04             ` Robert A Duff
2007-06-09 18:37               ` Dmitry A. Kazakov
2007-06-09 20:43                 ` Robert A Duff
2007-06-10  9:21                   ` Dmitry A. Kazakov
2007-06-11 19:18                   ` Randy Brukardt
2007-06-12  6:55                     ` Jean-Pierre Rosen
2007-06-08 17:40       ` Ray Blaak
2007-06-09 18:14         ` Robert A Duff
2007-06-08 19:18       ` Simon Wright
2007-06-09 22:37   ` Reconsidering assignment Maciej Sobczak
2007-06-10  9:21     ` Dmitry A. Kazakov
2007-06-11  9:04       ` Maciej Sobczak
2007-06-11 13:09         ` Dmitry A. Kazakov
2007-06-11 18:57     ` Randy Brukardt
2007-06-11 21:12       ` Maciej Sobczak
2007-06-12  8:31         ` Dmitry A. Kazakov
2007-06-12  9:31           ` Georg Bauhaus
2007-06-12 10:03             ` Dmitry A. Kazakov

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