comp.lang.ada
 help / color / mirror / Atom feed
* Operation can be dispatching in only one type
@ 2009-11-13 20:12 xorque
  2009-11-13 20:34 ` Dmitry A. Kazakov
  2009-11-16 17:43 ` Adam Beneschan
  0 siblings, 2 replies; 132+ messages in thread
From: xorque @ 2009-11-13 20:12 UTC (permalink / raw)


Hello.

I'm trying to write an archive/directory abstraction in a similar vein
to PhysicsFS
but am at a bit of a loss as to how to design the archiver interface:

with Path;

package Archiver is

  type Archiver_t              is abstract tagged limited private;
  type Archiver_Class_Access_t is access Archiver_t'Class;

  procedure Init
    (Archiver : out Archiver_t) is abstract;

  function Can_Mount
    (Archiver : in Archiver_t;
     Path     : in Path.Real_t) return Boolean is abstract;

  type File_t              is abstract tagged limited private;
  type File_Class_Access_t is access File_t'Class;

  procedure Open
    (Archiver : in     Archiver_t;
     Path     : in     Path.Virtual_t;
     File     :    out File_t) is abstract;

  procedure Close
    (File : in out File_t) is abstract;

private

  type Archiver_t is abstract tagged limited null record;

  type File_t is abstract tagged limited null record;

end Archiver;

The idea of the above is that the main part of the library only deals
with
archivers and "files" (which might only really be pointers to entries
in Zip
files, for example) by 'Class.

The problem with the above is that:

archiver.ads:18:13: operation can be dispatching in only one type

Hopefully someone here knows a better way to handle this.



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

* Re: Operation can be dispatching in only one type
  2009-11-13 20:12 Operation " xorque
@ 2009-11-13 20:34 ` Dmitry A. Kazakov
  2009-11-13 20:43   ` xorque
  2009-11-13 20:44   ` xorque
  2009-11-16 17:43 ` Adam Beneschan
  1 sibling, 2 replies; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-11-13 20:34 UTC (permalink / raw)


On Fri, 13 Nov 2009 12:12:18 -0800 (PST), xorque wrote:

> I'm trying to write an archive/directory abstraction in a similar vein
> to PhysicsFS
> but am at a bit of a loss as to how to design the archiver interface:
> 
> with Path;
> 
> package Archiver is
> 
>   type Archiver_t              is abstract tagged limited private;
>   type Archiver_Class_Access_t is access Archiver_t'Class;
> 
>   procedure Init
>     (Archiver : out Archiver_t) is abstract;
> 
>   function Can_Mount
>     (Archiver : in Archiver_t;
>      Path     : in Path.Real_t) return Boolean is abstract;
> 
>   type File_t              is abstract tagged limited private;
>   type File_Class_Access_t is access File_t'Class;
> 
>   procedure Open
>     (Archiver : in     Archiver_t;
>      Path     : in     Path.Virtual_t;
>      File     :    out File_t) is abstract;
> 
>   procedure Close
>     (File : in out File_t) is abstract;
> 
> private
> 
>   type Archiver_t is abstract tagged limited null record;
> 
>   type File_t is abstract tagged limited null record;
> 
> end Archiver;
> 
> The idea of the above is that the main part of the library only deals with
> archivers and "files" (which might only really be pointers to entries in Zip
> files, for example) by 'Class.
> 
> The problem with the above is that:
> 
> archiver.ads:18:13: operation can be dispatching in only one type
> 
> Hopefully someone here knows a better way to handle this.

Ada does not support multiple dispatch of this form. For simplicity
consider it does not support MD at all.

According to your code Open is doubly dispatching in Archiver_t and File_t
arguments. That does not work (unfortunately). You have to choose one and
make another class-wide. E.g.

procedure Open
    (Archiver : Archiver_t'Class; -- Class-wide
     Path     : Virtual_t;
     File     : in out File_t) is abstract;

This would be a primitive operation of File_t only.

P.S. If you indeed have to do MD, you should emulate it manually, by
dispatching within Open to some primitive operation of Archiver_t.

P.P.S. Do not use access types unless you need them.

P.P.P.S. Replace tagged limited with Ada.Finalization.Limited_Controlled,
sooner or later you almost certainly will need finalization and
initialization.

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



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

* Re: Operation can be dispatching in only one type
  2009-11-13 20:34 ` Dmitry A. Kazakov
@ 2009-11-13 20:43   ` xorque
  2009-11-13 21:14     ` Dmitry A. Kazakov
  2009-11-13 20:44   ` xorque
  1 sibling, 1 reply; 132+ messages in thread
From: xorque @ 2009-11-13 20:43 UTC (permalink / raw)


Thanks for the response.

It may be that I don't want to design the interface like the above at
all.

The only real requirement is that:

Archivers use a common protocol: Code just sees operations
on Archiver_t'Class and doesn't know if it's reading from a Zip, RAR,
directory, etc.

Presumably, then, when I open a file using an operation from an
archiver, I can't know about the implementation of the actual file
as it's private to the archiver.

Hence, I've ended up with two private tagged types. Is there a better
way (I've not ignored your other suggestions, I'm just exploring other
possibilities first)?



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

* Re: Operation can be dispatching in only one type
  2009-11-13 20:34 ` Dmitry A. Kazakov
  2009-11-13 20:43   ` xorque
@ 2009-11-13 20:44   ` xorque
  1 sibling, 0 replies; 132+ messages in thread
From: xorque @ 2009-11-13 20:44 UTC (permalink / raw)


On Nov 13, 8:34 pm, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:
.>
> P.P.P.S. Replace tagged limited with Ada.Finalization.Limited_Controlled,
> sooner or later you almost certainly will need finalization and
> initialization.

Agreed. It was always intended, just not implemented there for
simplicity's
sake.



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

* Re: Operation can be dispatching in only one type
  2009-11-13 20:43   ` xorque
@ 2009-11-13 21:14     ` Dmitry A. Kazakov
  0 siblings, 0 replies; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-11-13 21:14 UTC (permalink / raw)


On Fri, 13 Nov 2009 12:43:42 -0800 (PST), xorque wrote:

> The only real requirement is that:
> 
> Archivers use a common protocol: Code just sees operations
> on Archiver_t'Class and doesn't know if it's reading from a Zip, RAR,
> directory, etc.
> 
> Presumably, then, when I open a file using an operation from an
> archiver, I can't know about the implementation of the actual file
> as it's private to the archiver.
> 
> Hence, I've ended up with two private tagged types. Is there a better
> way (I've not ignored your other suggestions, I'm just exploring other
> possibilities first)?

MD is customary replaced my mix-in:

1. Standard mix-in:

  type File_Type is
     abstract new Ada.Finalization.Limited_Controlled with null record;
  procedure Open
            (  File : in out File_Type;
               Path : String              
            )  is abstract;
  procedure Close (File : in out File_Type) is abstract;
  procedure Read ...;
  procedure Write ...;

Files know nothing about archives. Archive has a file as a mixin:

  type Archiver_Type (Transport : not null access File_Type'Class) is
     new Ada.Finalization.Limited_Controlled with null record;
  procedure Open (Archiver : in out Archiver_Type; Path : String);

Open of Archive_Type calls to Open of Archive.Transport. Same with other
operations. They all are defined in terms of the operations of File_Type.
Class through Archive.Transport are dispatching, because it is class-wide.

2. Generic mix-in.

You can put Archive in the hierarchy of File_Type. The implementation of
Archive_Type can be generic taking a descendant of File_Type and then
extending it in the generic body.

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



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

* Re: Operation can be dispatching in only one type
  2009-11-13 20:12 Operation " xorque
  2009-11-13 20:34 ` Dmitry A. Kazakov
@ 2009-11-16 17:43 ` Adam Beneschan
  2009-11-16 20:28   ` Dmitry A. Kazakov
  1 sibling, 1 reply; 132+ messages in thread
From: Adam Beneschan @ 2009-11-16 17:43 UTC (permalink / raw)


On Nov 13, 12:12 pm, xorque <xorquew...@googlemail.com> wrote:
> Hello.
>
> I'm trying to write an archive/directory abstraction in a similar vein
> to PhysicsFS
> but am at a bit of a loss as to how to design the archiver interface:
>
> with Path;
>
> package Archiver is
>
>   type Archiver_t              is abstract tagged limited private;
>   type Archiver_Class_Access_t is access Archiver_t'Class;
>
>   procedure Init
>     (Archiver : out Archiver_t) is abstract;
>
>   function Can_Mount
>     (Archiver : in Archiver_t;
>      Path     : in Path.Real_t) return Boolean is abstract;
>
>   type File_t              is abstract tagged limited private;
>   type File_Class_Access_t is access File_t'Class;
>
>   procedure Open
>     (Archiver : in     Archiver_t;
>      Path     : in     Path.Virtual_t;
>      File     :    out File_t) is abstract;
>
>   procedure Close
>     (File : in out File_t) is abstract;
>
> private
>
>   type Archiver_t is abstract tagged limited null record;
>
>   type File_t is abstract tagged limited null record;
>
> end Archiver;
>
> The idea of the above is that the main part of the library only deals
> with
> archivers and "files" (which might only really be pointers to entries
> in Zip
> files, for example) by 'Class.
>
> The problem with the above is that:
>
> archiver.ads:18:13: operation can be dispatching in only one type
>
> Hopefully someone here knows a better way to handle this.

I don't know what PhysicsFS is, so I'm not clear on what you are
trying to accomplish.

Maybe your plan is to define concrete types derived from Archive_T and
File_T that go together, in pairs.  For example, a programmer might
define one package Archive_1 that defines Archive_1_T and File_1_T,
and another user might write a package Archive_2 that defines
Archive_2_T and File_2_T, but the intent is that the two would be
dependent---i.e. you would always use Open with two objects that go
together, such as an object of type Archive_1_T with a File_1_T, or an
Archive_2_T with a File_2_T, but never with an Archive_1_T and a
File_2_T.  In that case, you would make one parameter classwide, as
Dmitry suggested:

procedure Open
    (Archiver : Archiver_t'Class; -- Class-wide
     Path     : Virtual_t;
     File     : in out File_t) is abstract;

Then an implementation would need to check manually to make sure the
type is correct:

procedure Open
     (Archive : Archiver_T'Class;
      Path    : Virtual_T;
      File    : in out File_1_T) is
begin
   if Archive not in Archive_1_T then
      raise <some exception> with "Open on File_1_T used with wrong
archiver class";
   end if;
   declare
      The_Arch : Archive_1_T renames Archive_1_T(Archive);
   begin
      ...
      ... and now you have an Archive_1_T and a File_1_T to work with.

(I haven't checked this to make sure it's correct.  But it would be
something like this.)

By the way, for a while I was considering requesting a language change
to allow this sort of restricted multiple dispatch, in cases where a
primitive operation of two types could be declared and inherited for
two derived types that are derived in the same package, and when
dispatching, the program would check to make sure the two actual types
really were declared in the same package.  This would avoid having to
deal with M x N combinations of types---something that I think is an
issue with MI---since it only deals with pairs (or triplets, etc.) of
types that are defined to "go together".  I could try to write a
proposal if there's enough interest, but I think it's too late to get
into the next language revision.

If your plan is that Archiver and File types be more independent,
though, what you may need to do is to pick one of the parameters to
Open, say Archive (as above) to be a class-wide type, and then provide
enough operations on Archiver_T so that an implementation of Open
could dispatch on Archive to do whatever needs to be done with the
archive.

If you have some other idea about the relationship between Archiver
and File, then you might need to give me more specifics about how you
intend your package to be used.

                                 -- Adam



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

* Re: Operation can be dispatching in only one type
  2009-11-16 17:43 ` Adam Beneschan
@ 2009-11-16 20:28   ` Dmitry A. Kazakov
  2009-11-16 20:32     ` Dmitry A. Kazakov
  2009-11-16 21:35     ` Adam Beneschan
  0 siblings, 2 replies; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-11-16 20:28 UTC (permalink / raw)


On Mon, 16 Nov 2009 09:43:06 -0800 (PST), Adam Beneschan wrote:

> By the way, for a while I was considering requesting a language change
> to allow this sort of restricted multiple dispatch, in cases where a
> primitive operation of two types could be declared and inherited for
> two derived types that are derived in the same package, and when
> dispatching, the program would check to make sure the two actual types
> really were declared in the same package.  This would avoid having to
> deal with M x N combinations of types---something that I think is an
> issue with MI---since it only deals with pairs (or triplets, etc.) of
> types that are defined to "go together".

But you still have these combinations independently on where you derive.
You allow the "diagonal" of the full dispatching table. I.e. the
combinations:

A1, B1,
A2, B2,
A3, B3

But other combinations are still there, because they can be spelt. It is
just so that they raise Constraint_Error. This "diagonal" behavior is what
we already have for multi-methods (a form of MD with only one hierarchy
A=B). I suppose this is one of the motivations of your proposal.

But the problem with "diagonal" dispatch is that it is inconsistent with
the idea of static typing. I would insist on the design rule that dispatch
shall never fail in a legal program. I.e. the compiler shall enforce all
possible combinations of types no later than at compile time. Further, it
shall not "invent" broken implementations. In "diagonal" dispatch it would
do (and does) exactly this, it would override A1, B2 with an implementation
raising Constraint_Error.

At the same time the case represented by "diagonal" dispatch is very
important in other situations, like parallel hierarchies of types. E.g.
when we wanted to force a new instance from B'Class for each new instance
from A'Class. But again that enforcement shall be static. BTW, it is not
multiple dispatch. Technically this is rather single dispatch where the
tuple of types (A, B) is considered as root of some class of tuples, in
which (A1, B1), (A2, B2) are instances. Presently we have nothing in the
language to handle this (except the jack-of-all-trades, generics). It would
be interesting to speculate how tuples can be supported in Ada, especially
their flattening in the arguments lists, and using tuples as multiple
results of a function.

> I could try to write a
> proposal if there's enough interest, but I think it's too late to get
> into the next language revision.

I am incredibly interested in MD (and in tuples as well), but I think we
should not touch it until we knew how to do it right.

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



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

* Re: Operation can be dispatching in only one type
  2009-11-16 20:28   ` Dmitry A. Kazakov
@ 2009-11-16 20:32     ` Dmitry A. Kazakov
  2009-11-16 21:35     ` Adam Beneschan
  1 sibling, 0 replies; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-11-16 20:32 UTC (permalink / raw)


On Mon, 16 Nov 2009 21:28:00 +0100, Dmitry A. Kazakov wrote:

> At the same time the case represented by "diagonal" dispatch is very
> important in other situations, like parallel hierarchies of types. E.g.
> when we wanted to force a new instance from B'Class for each new instance
> from A'Class. But again that enforcement shall be static. BTW, it is not
> multiple dispatch. Technically this is rather single dispatch where the
> tuple of types (A, B) is considered as root of some class of tuples, in
> which (A1, B1), (A2, B2) are instances. Presently we have nothing in the
> language to handle this (except the jack-of-all-trades, generics). It would
> be interesting to speculate how tuples can be supported in Ada, especially
> their flattening in the arguments lists, and using tuples as multiple
> results of a function.

I forgot to say, that in this case illegal combinations like A1, B2 are
statically illegal, because there would be no tuple (A1, B2) declared.

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



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

* Re: Operation can be dispatching in only one type
  2009-11-16 20:28   ` Dmitry A. Kazakov
  2009-11-16 20:32     ` Dmitry A. Kazakov
@ 2009-11-16 21:35     ` Adam Beneschan
  2009-11-16 22:28       ` Dmitry A. Kazakov
  1 sibling, 1 reply; 132+ messages in thread
From: Adam Beneschan @ 2009-11-16 21:35 UTC (permalink / raw)


On Nov 16, 12:28 pm, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:
> On Mon, 16 Nov 2009 09:43:06 -0800 (PST), Adam Beneschan wrote:
> > By the way, for a while I was considering requesting a language change
> > to allow this sort of restricted multiple dispatch, in cases where a
> > primitive operation of two types could be declared and inherited for
> > two derived types that are derived in the same package, and when
> > dispatching, the program would check to make sure the two actual types
> > really were declared in the same package.  This would avoid having to
> > deal with M x N combinations of types---something that I think is an
> > issue with MI---since it only deals with pairs (or triplets, etc.) of
> > types that are defined to "go together".
>
> But you still have these combinations independently on where you derive.
> You allow the "diagonal" of the full dispatching table. I.e. the
> combinations:
>
> A1, B1,
> A2, B2,
> A3, B3
>
> But other combinations are still there, because they can be spelt. It is
> just so that they raise Constraint_Error. This "diagonal" behavior is what
> we already have for multi-methods (a form of MD with only one hierarchy
> A=B). I suppose this is one of the motivations of your proposal.
>
> But the problem with "diagonal" dispatch is that it is inconsistent with
> the idea of static typing. I would insist on the design rule that dispatch
> shall never fail in a legal program. I.e. the compiler shall enforce all
> possible combinations of types no later than at compile time.

Since a call to a dispatching operation may have parameters that are
themselves of class-wide types, I don't think this is possible.

In Ada as it exists currently, you can declare a primitive operation
with two parameters of the same tagged type (maybe that's what you
meant by "multi-method"---sorry, I don't know the jargon).  E.g.

   type T is abstract tagged null record;
   procedure Some_Operation (Param_1 : T; Param_2 : T);

If you later call

   Some_Operation (X, Y);

and X is declared to be of type T1 (a descendant of T) and Y is
declared to be of type T2 (also a descendant of T), then the compiler
can statically determine that this will fail.  But if either X or Y
(or both) is declared to be of type T'Class, then the compiler can't
statically tell whether the dispatch will fail or not.  So a runtime
check is needed.  Similarly for the proposal I was thinking of making.


> Further, it
> shall not "invent" broken implementations. In "diagonal" dispatch it would
> do (and does) exactly this, it would override A1, B2 with an implementation
> raising Constraint_Error.
>
> At the same time the case represented by "diagonal" dispatch is very
> important in other situations, like parallel hierarchies of types. E.g.
> when we wanted to force a new instance from B'Class for each new instance
> from A'Class. But again that enforcement shall be static. BTW, it is not
> multiple dispatch. Technically this is rather single dispatch where the
> tuple of types (A, B) is considered as root of some class of tuples, in
> which (A1, B1), (A2, B2) are instances. Presently we have nothing in the
> language to handle this (except the jack-of-all-trades, generics). It would
> be interesting to speculate how tuples can be supported in Ada, especially
> their flattening in the arguments lists, and using tuples as multiple
> results of a function.
>
> > I could try to write a
> > proposal if there's enough interest, but I think it's too late to get
> > into the next language revision.
>
> I am incredibly interested in MD (and in tuples as well), but I think we
> should not touch it until we knew how to do it right.

I don't think the proposal I was considering was a solution to MD, but
rather to a smallish subset of MD-related problems---although it was a
subset I thought would be useful, and I may have run into a case in my
own code where I would have wanted to use it.

                            -- Adam



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

* Re: Operation can be dispatching in only one type
  2009-11-16 21:35     ` Adam Beneschan
@ 2009-11-16 22:28       ` Dmitry A. Kazakov
  2009-11-17 22:10         ` Adam Beneschan
  0 siblings, 1 reply; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-11-16 22:28 UTC (permalink / raw)


On Mon, 16 Nov 2009 13:35:00 -0800 (PST), Adam Beneschan wrote:

> On Nov 16, 12:28�pm, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
>> On Mon, 16 Nov 2009 09:43:06 -0800 (PST), Adam Beneschan wrote:
>>> By the way, for a while I was considering requesting a language change
>>> to allow this sort of restricted multiple dispatch, in cases where a
>>> primitive operation of two types could be declared and inherited for
>>> two derived types that are derived in the same package, and when
>>> dispatching, the program would check to make sure the two actual types
>>> really were declared in the same package. �This would avoid having to
>>> deal with M x N combinations of types---something that I think is an
>>> issue with MI---since it only deals with pairs (or triplets, etc.) of
>>> types that are defined to "go together".
>>
>> But you still have these combinations independently on where you derive.
>> You allow the "diagonal" of the full dispatching table. I.e. the
>> combinations:
>>
>> A1, B1,
>> A2, B2,
>> A3, B3
>>
>> But other combinations are still there, because they can be spelt. It is
>> just so that they raise Constraint_Error. This "diagonal" behavior is what
>> we already have for multi-methods (a form of MD with only one hierarchy
>> A=B). I suppose this is one of the motivations of your proposal.
>>
>> But the problem with "diagonal" dispatch is that it is inconsistent with
>> the idea of static typing. I would insist on the design rule that dispatch
>> shall never fail in a legal program. I.e. the compiler shall enforce all
>> possible combinations of types no later than at compile time.
> 
> Since a call to a dispatching operation may have parameters that are
> themselves of class-wide types, I don't think this is possible.

No, what I have in mind is that each time a new type is derived, we could
somehow ensure that the whole row M+1 (from N x M+1) is filled either by a
overriding or per a reasonable inheritance. The major problem is that we
cannot see all Ns when we do M+1.

The idea of deriving both types in one package looks like an attempt to
control the places where we can expand the table N x M. That is not enough
to enforce completeness of the table in the above sense.

There should be something more strong, but also more liberal in terms of
modularization. Obviously to derive from all types related via a shared
primitive operation in one package is awful (and sometimes just impossible
within the given parent-child hierarchy of packages).

> In Ada as it exists currently, you can declare a primitive operation
> with two parameters of the same tagged type (maybe that's what you
> meant by "multi-method"---sorry, I don't know the jargon).  E.g.
> 
>    type T is abstract tagged null record;
>    procedure Some_Operation (Param_1 : T; Param_2 : T);
> 
> If you later call
> 
>    Some_Operation (X, Y);
> 
> and X is declared to be of type T1 (a descendant of T) and Y is
> declared to be of type T2 (also a descendant of T), then the compiler
> can statically determine that this will fail.  But if either X or Y
> (or both) is declared to be of type T'Class, then the compiler can't
> statically tell whether the dispatch will fail or not.  So a runtime
> check is needed.  Similarly for the proposal I was thinking of making.

Yep, this is what I meant. The compiler should require to override *all*
combinations:

   type T2 is new T1 with ...;
   overriding
      procedure Some_Operation (X : T2; Y : T2);
        -- Error!

   overriding
      procedure Some_Operation (X : T2; Y : T2);
   overriding
      procedure Some_Operation (X : T1; Y : T2);
   overriding
      procedure Some_Operation (X : T2; Y : T1);
         -- OK

Yes, this is tedious, but the programmer should know what we does when he
declares a multi-method. This is the semantics of - there are n**2
combinations which do potentially different things. If there are only n
combinations, that is another case, which should *not* look MD, because it
is not. I think it should somehow use tuples instead. The error should
happen upon tuple construction, not in the call. For the reader it should
be clear that there is only one tag. I have no idea how to spell that
syntactically or by other means.

Al for "true" multi-methods I think we should support delegation in order
to control combinatorial explosion. For example:

1. declaration Some_Operation commutative;

2. explicit delegation of T2 x T1 to T1 x T2

   overriding
      procedure Some_Operation (X : T2; Y : T1)
         renames Some_Operation with (X => Y, Y => X);

3. delegation of T1 x T2 to T2 x T2 supplying a downcast conversion from T1
to T2

   overriding
      procedure Some_Operation (X : T1; Y : T2)
         renames Some_Operation with (X => (X with ...), Y => Y);

4. delegation of T2 x T2 to T1 x T2 (upcast)

   overriding
      procedure Some_Operation (X : T2; Y : T2)
         renames Some_Operation with (X => T1 (X), Y => Y);

etc.

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



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

* Re: Operation can be dispatching in only one type
  2009-11-16 22:28       ` Dmitry A. Kazakov
@ 2009-11-17 22:10         ` Adam Beneschan
  2009-11-18  9:46           ` Dmitry A. Kazakov
  2009-11-19  2:23           ` tmoran
  0 siblings, 2 replies; 132+ messages in thread
From: Adam Beneschan @ 2009-11-17 22:10 UTC (permalink / raw)


On Nov 16, 2:28 pm, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

>
> No, what I have in mind is that each time a new type is derived, we could
> somehow ensure that the whole row M+1 (from N x M+1) is filled either by a
> overriding or per a reasonable inheritance. The major problem is that we
> cannot see all Ns when we do M+1.
>
> The idea of deriving both types in one package looks like an attempt to
> control the places where we can expand the table N x M. That is not enough
> to enforce completeness of the table in the above sense.
>
> There should be something more strong, but also more liberal in terms of
> modularization. Obviously to derive from all types related via a shared
> primitive operation in one package is awful (and sometimes just impossible
> within the given parent-child hierarchy of packages).

....

> Yep, this is what I meant. The compiler should require to override *all*
> combinations:
>
>    type T2 is new T1 with ...;
>    overriding
>       procedure Some_Operation (X : T2; Y : T2);
>         -- Error!
>
>    overriding
>       procedure Some_Operation (X : T2; Y : T2);
>    overriding
>       procedure Some_Operation (X : T1; Y : T2);
>    overriding
>       procedure Some_Operation (X : T2; Y : T1);
>          -- OK
>
> Yes, this is tedious, but the programmer should know what we does when he
> declares a multi-method. This is the semantics of - there are n**2
> combinations which do potentially different things. If there are only n
> combinations, that is another case, which should *not* look MD, because it
> is not. I think it should somehow use tuples instead. The error should
> happen upon tuple construction, not in the call. For the reader it should
> be clear that there is only one tag. I have no idea how to spell that
> syntactically or by other means.

It appears to me that we're talking at cross-purposes.
I was trying to solve one particular class of problems;
you seem to be trying to solve the entire Multiple
Dispatch problem.  I believe that when I first thought
about making this proposal, I was assuming that a fully
general multiple dispatch wasn't ever going to be part
of the language, so I was thinking about an improvement
for one particular case I had run into.

Here's an example of the sort of problem I'm thinking
about: Suppose you want to define an abstract type that
represents a document, which could be a plain ASCII
text file, a Word document, a PDF file, etc., that all
have in common that they consist of sequences of
"characters" and "other elements of some sort".  Some
of the documents may also have formatting information
or other good stuff, but these won't be common to all
documents.

You want to write a package that deals with documents
and particularly with the text (characters) in the
documents.  The type of document (plain text, Word,
etc.) won't be known until run time.  Some of the
operations you want to provide are: search for given
text in the document, and return "markers" that point
to the beginning and end of the text that is found; and
move text from one point to another in the document.

A natural way to do this, it seems, would be to define
a Document as an abstract type, and let other packages
(Plaintext_Documents, Word_Documents, PDF_Documents,
etc.) define concrete types as extensions of that type
for plain text, Word documents, PDF documents, and so
on.  You also want to define, say, a Text_Region type
that represents a region of text in a document, and a
Marker type that represents a particular point in the
document text, between two characters.  The Text_Region
and Marker types should be abstract also, since we
don't know how they'd be implemented for different
document types; for a plain text document, a Marker is
probably just a string index, in essence, but the
Word_Documents and PDF_Documents might unpack a file
into some complex internal data structure when it reads
it, so a Marker for those document types might contain
pointers into the internal data structure, or
something.

So it seems natural to write the package like this
(along with other operations):

package Documents is

    type Document is abstract tagged private;
    type Text_Region is abstract tagged private;
    type Marker is abstract tagged private;

    function Search_For_Text (Doc : Document; Text : String)
               return Text_Region is abstract;
       -- I'm assuming here that it would return some sort of
       -- "no region" value if the text is not found
    function Beginning_Of (Reg : Text_Region) return Marker
       is abstract;
    function End_Of (Reg : Text_Region) return Marker
       is abstract;

    procedure Move_Text (Doc  : in out Document;
                         From : in Text_Region;
                         To   : in Marker)
       is abstract;

end Documents;

The last would cut the text represented by the From
region and move it to the point specified by "To".  (It
would be up to the packages to figure out how to move
formatting information or other information in an
appropriate way.)

Of course, Move_Text can't be declared because it is a
primitive operation of more than one tagged type.
Actually, none of the functions can be declared,
either, but I want to focus on the Move_Text procedure.
You might want to call Move_Text with a
Word_Documents.Document, Word_Documents.Text_Region,
and Word_Documents.Marker, or similarly with three
objects all with types from the PDF_Documents or
Plaintext_Documents package, but you would never want
to mix objects from two different packages.  And that
was the purpose of the proposal I was thinking of
making: to allow for restricted use of multiple
dispatch for cases like this (and this is a situation I
believe I've run into more than once), in which
Move_Text could be declared but could only be called if
the parameters' specific types all come from the same
package, checked at runtime if necessary.  The
Move_Text procedure would be inherited in each of the
other packages (Plaintext_Documents, etc.), with types
from that package, but there would not be any inherited
Move_Text that would involve types from different
packages.  (This was an idea I first thought about a
long time ago, but eventually abandoned; I really
hadn't thought about how to deal with the functions.)

There are workarounds, of course.  As I responded to
the original poster in this thread, you can make some
of the parameters to Move_Text class-wide, and the
concrete procedures would check to make sure the actual
tags for the class-wide parameters are correct---or
just doing a type conversion will do the check:

package body Word_Documents is

    overriding
    procedure Move_Text (Doc  : in out Document;
                         From : in Documents.Text_Region'Class;
                         To   : in Documents.Marker'Class) is
       X_From : Text_Region renames Text_Region(From);
       X_To   : Marker renames Marker(To);
       ...

I think that's correct.  Anyway, those will raise
Constraint_Error if the parameters are from the wrong
package.

However, I consider that to be a workaround (maybe
others don't think it's that bad), which is why I was
thinking about making this proposal---to make things
work more "naturally", without a workaround, in this
sort of situation that I've run into multiple times.
I'm not sure what your idea is trying to solve (other
than "making multiple dispatch perfect"); but even if
it does make general multiple dispatch available, your
way of doing things would not solve anything in this
sort of case, because you would require Move_Text to be
overridden for every possible combination of children
of the types, which makes it unusable and means that
even with your Grand Solution To Everything, those of
us who want to implement something like the above would
have to go back to using the workaround.

That's why I think we're not on the same page---we're
trying to solve two different and unrelated problems
that seem only superficially related.  Maybe we can't
solve them both.

                                  -- Adam





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

* Re: Operation can be dispatching in only one type
  2009-11-17 22:10         ` Adam Beneschan
@ 2009-11-18  9:46           ` Dmitry A. Kazakov
  2009-11-18 16:39             ` Adam Beneschan
  2009-11-19  2:23           ` tmoran
  1 sibling, 1 reply; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-11-18  9:46 UTC (permalink / raw)


On Tue, 17 Nov 2009 14:10:54 -0800 (PST), Adam Beneschan wrote:

> On Nov 16, 2:28�pm, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
> 
>> No, what I have in mind is that each time a new type is derived, we could
>> somehow ensure that the whole row M+1 (from N x M+1) is filled either by a
>> overriding or per a reasonable inheritance. The major problem is that we
>> cannot see all Ns when we do M+1.
>>
>> The idea of deriving both types in one package looks like an attempt to
>> control the places where we can expand the table N x M. That is not enough
>> to enforce completeness of the table in the above sense.
>>
>> There should be something more strong, but also more liberal in terms of
>> modularization. Obviously to derive from all types related via a shared
>> primitive operation in one package is awful (and sometimes just impossible
>> within the given parent-child hierarchy of packages).
> 
> ....
> 
>> Yep, this is what I meant. The compiler should require to override *all*
>> combinations:
>>
>> � �type T2 is new T1 with ...;
>> � �overriding
>> � � � procedure Some_Operation (X : T2; Y : T2);
>> � � � � -- Error!
>>
>> � �overriding
>> � � � procedure Some_Operation (X : T2; Y : T2);
>> � �overriding
>> � � � procedure Some_Operation (X : T1; Y : T2);
>> � �overriding
>> � � � procedure Some_Operation (X : T2; Y : T1);
>> � � � � �-- OK
>>
>> Yes, this is tedious, but the programmer should know what we does when he
>> declares a multi-method. This is the semantics of - there are n**2
>> combinations which do potentially different things. If there are only n
>> combinations, that is another case, which should *not* look MD, because it
>> is not. I think it should somehow use tuples instead. The error should
>> happen upon tuple construction, not in the call. For the reader it should
>> be clear that there is only one tag. I have no idea how to spell that
>> syntactically or by other means.
> 
> It appears to me that we're talking at cross-purposes.

No, it is the same problem of MD. It has some special cases like
multi-methods, which are simpler, but it is still MD. The example you
provided is full MD. You have three hierarchies:

   Document'Class, Text_Region'Class, Marker'Class

An operation can be primitive in any combinations of types from these
hierarchies.

> I was trying to solve one particular class of problems;
> you seem to be trying to solve the entire Multiple
> Dispatch problem.  I believe that when I first thought
> about making this proposal, I was assuming that a fully
> general multiple dispatch wasn't ever going to be part
> of the language, so I was thinking about an improvement
> for one particular case I had run into.
> 
> Here's an example of the sort of problem I'm thinking
> about: Suppose you want to define an abstract type that
> represents a document, which could be a plain ASCII
> text file, a Word document, a PDF file, etc., that all
> have in common that they consist of sequences of
> "characters" and "other elements of some sort".  Some
> of the documents may also have formatting information
> or other good stuff, but these won't be common to all
> documents.
> 
> You want to write a package that deals with documents
> and particularly with the text (characters) in the
> documents.  The type of document (plain text, Word,
> etc.) won't be known until run time.  Some of the
> operations you want to provide are: search for given
> text in the document, and return "markers" that point
> to the beginning and end of the text that is found; and
> move text from one point to another in the document.
> 
> A natural way to do this, it seems, would be to define
> a Document as an abstract type, and let other packages
> (Plaintext_Documents, Word_Documents, PDF_Documents,
> etc.) define concrete types as extensions of that type
> for plain text, Word documents, PDF documents, and so
> on.  You also want to define, say, a Text_Region type
> that represents a region of text in a document, and a
> Marker type that represents a particular point in the
> document text, between two characters.  The Text_Region
> and Marker types should be abstract also, since we
> don't know how they'd be implemented for different
> document types; for a plain text document, a Marker is
> probably just a string index, in essence, but the
> Word_Documents and PDF_Documents might unpack a file
> into some complex internal data structure when it reads
> it, so a Marker for those document types might contain
> pointers into the internal data structure, or
> something.
> 
> So it seems natural to write the package like this
> (along with other operations):
> 
> package Documents is
> 
>     type Document is abstract tagged private;
>     type Text_Region is abstract tagged private;
>     type Marker is abstract tagged private;
> 
>     function Search_For_Text (Doc : Document; Text : String)
>                return Text_Region is abstract;
>        -- I'm assuming here that it would return some sort of
>        -- "no region" value if the text is not found
>     function Beginning_Of (Reg : Text_Region) return Marker
>        is abstract;
>     function End_Of (Reg : Text_Region) return Marker
>        is abstract;
> 
>     procedure Move_Text (Doc  : in out Document;
>                          From : in Text_Region;
>                          To   : in Marker)
>        is abstract;
> 
> end Documents;
> 
> The last would cut the text represented by the From
> region and move it to the point specified by "To".  (It
> would be up to the packages to figure out how to move
> formatting information or other information in an
> appropriate way.)
> 
> Of course, Move_Text can't be declared because it is a
> primitive operation of more than one tagged type.
> Actually, none of the functions can be declared,
> either, but I want to focus on the Move_Text procedure.
> You might want to call Move_Text with a
> Word_Documents.Document, Word_Documents.Text_Region,
> and Word_Documents.Marker, or similarly with three
> objects all with types from the PDF_Documents or
> Plaintext_Documents package, but you would never want
> to mix objects from two different packages.

As an example consider these operations:

procedure Cut
          (  Doc       : in out Document;
             From      : in Text_Region;
             Clipboard : in out Document
          );
procedure Paste
          (  Clipboard : in Document;
             Doc       : in out Document;
             To        : in Marker
          );

> And that
> was the purpose of the proposal I was thinking of
> making: to allow for restricted use of multiple
> dispatch for cases like this (and this is a situation I
> believe I've run into more than once), in which
> Move_Text could be declared but could only be called if
> the parameters' specific types all come from the same
> package, checked at runtime if necessary.  The
> Move_Text procedure would be inherited in each of the
> other packages (Plaintext_Documents, etc.), with types
> from that package, but there would not be any inherited
> Move_Text that would involve types from different
> packages.  (This was an idea I first thought about a
> long time ago, but eventually abandoned; I really
> hadn't thought about how to deal with the functions.)

So if you derived ASCII_Text from Plain_Text you would lose Move_Text if
you forgot to derive from Text_Region and Marker?

> There are workarounds, of course.  As I responded to
> the original poster in this thread, you can make some
> of the parameters to Move_Text class-wide, and the
> concrete procedures would check to make sure the actual
> tags for the class-wide parameters are correct---or
> just doing a type conversion will do the check:
> 
> package body Word_Documents is
> 
>     overriding
>     procedure Move_Text (Doc  : in out Document;
>                          From : in Documents.Text_Region'Class;
>                          To   : in Documents.Marker'Class) is
>        X_From : Text_Region renames Text_Region(From);
>        X_To   : Marker renames Marker(To);
>        ...
> 
> I think that's correct.  Anyway, those will raise
> Constraint_Error if the parameters are from the wrong
> package.

(BTW, the jargon word is "covariance". Document, Text_Region and Marker are
said "covariant" in Move_Text.)

> However, I consider that to be a workaround (maybe
> others don't think it's that bad), which is why I was
> thinking about making this proposal---to make things
> work more "naturally", without a workaround, in this
> sort of situation that I've run into multiple times.
> I'm not sure what your idea is trying to solve (other
> than "making multiple dispatch perfect"); but even if
> it does make general multiple dispatch available, your
> way of doing things would not solve anything in this
> sort of case, because you would require Move_Text to be
> overridden for every possible combination of children
> of the types, which makes it unusable and means that
> even with your Grand Solution To Everything, those of
> us who want to implement something like the above would
> have to go back to using the workaround.

Consider again ASCII_Text derived from Plain_Text. Let we also derived from
Plain_Text_Region and Plain_Marker:

   Plain_Text <-- ASCII_Text
   Plain_Text_Region <-- ASCII_Region
   Plain_Marker <-- ASCII_Marker

Now, my concern is what happens with Move_To called on

   ASCII_Text, Text_Region, Plain_Marker

You say, it is Constraint_Error. The question what is the reason for this?
I don't see any. It is for the programmer to decide.

I you say the language forbids that, I say OK, but then that MUST be done
static.

Anyway your proposal would impose some draconian limitations on the
packages structure. E.g. it would be impossible to provide implementations
and different types of Marker in separate packages. Or consider a generic
implementing a Marker for the given document type. Would that work?

> That's why I think we're not on the same page---we're
> trying to solve two different and unrelated problems
> that seem only superficially related.  Maybe we can't
> solve them both.

Actually I considered both cases with the requirement of the constraint
being static. To summarize:

1. Full MD = no constraint => all combinations checked and required
2. SD on tuples = static constraint on the combinations

The case 2 has consequences, of course.

What I find totally inappropriate for a language like Ada is:

3. Dynamic constraint with run-time checks dropping arbitrary exceptions.

I think we should have learnt something from the "accessibility checks
disaster".

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



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

* Re: Operation can be dispatching in only one type
  2009-11-18  9:46           ` Dmitry A. Kazakov
@ 2009-11-18 16:39             ` Adam Beneschan
  2009-11-18 19:21               ` Dmitry A. Kazakov
  0 siblings, 1 reply; 132+ messages in thread
From: Adam Beneschan @ 2009-11-18 16:39 UTC (permalink / raw)


On Nov 18, 1:46 am, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> > It appears to me that we're talking at cross-purposes.
>
> No, it is the same problem of MD. It has some special cases like
> multi-methods, which are simpler, but it is still MD. The example you
> provided is full MD. You have three hierarchies:
>
>    Document'Class, Text_Region'Class, Marker'Class
>
> An operation can be primitive in any combinations of types from these
> hierarchies.

> > Here's an example of the sort of problem I'm thinking
> > about: Suppose you want to define an abstract type that
> > represents a document, which could be a plain ASCII
> > text file, a Word document, a PDF file, etc., that all
> > have in common that they consist of sequences of
> > "characters" and "other elements of some sort"....

> > Of course, Move_Text can't be declared because it is a
> > primitive operation of more than one tagged type.
> > Actually, none of the functions can be declared,
> > either, but I want to focus on the Move_Text procedure.
> > You might want to call Move_Text with a
> > Word_Documents.Document, Word_Documents.Text_Region,
> > and Word_Documents.Marker, or similarly with three
> > objects all with types from the PDF_Documents or
> > Plaintext_Documents package, but you would never want
> > to mix objects from two different packages.
>
> As an example consider these operations:
>
> procedure Cut
>           (  Doc       : in out Document;
>              From      : in Text_Region;
>              Clipboard : in out Document
>           );
> procedure Paste
>           (  Clipboard : in Document;
>              Doc       : in out Document;
>              To        : in Marker
>           );

Right, I wasn't envisioning this sort of operation that involved two
*different* documents of (potentially) two different types.  When I
started thinking about this idea, I had had some issues with programs
I was working on, but it was so long ago that I don't remember what
the exact problem was and I can't find it.  Whatever it was, it was
*not* a case where there would have been any operations involving two
different objects of two different child types.


> So if you derived ASCII_Text from Plain_Text you would lose Move_Text if
> you forgot to derive from Text_Region and Marker?

Most likely, I would have written the rules so that if you *do*
declare an operation like this of two (or more) different tagged
types, and if in some other package you don't derive from all those
types, it would be an error at that point.

Again, although I can see that someone might want to derive ASCII_Text
from Plain_Text, it wasn't something I considered at the time since it
wasn't germane to the type of problem I was running into.


> Consider again ASCII_Text derived from Plain_Text. Let we also derived from
> Plain_Text_Region and Plain_Marker:
>
>    Plain_Text <-- ASCII_Text
>    Plain_Text_Region <-- ASCII_Region
>    Plain_Marker <-- ASCII_Marker
>
> Now, my concern is what happens with Move_To called on
>
>    ASCII_Text, Text_Region, Plain_Marker
>
> You say, it is Constraint_Error. The question what is the reason for this?
> I don't see any. It is for the programmer to decide.
>
> I you say the language forbids that, I say OK, but then that MUST be done
> static.

I don't see a practical reason why that would be necessary.  And I
have a major objection, at least to what I think you're proposing.
Suppose someone at some organization declares a package with some
abstract types.  Another organization is developing a large
application.  Since this is a large application, it's divided into
several parts with one part being given to one team, another part to
another team, and so on, working independently.  The idea is that as
long as each team can develop its part of the application that works
according to some "contract", then you should be able to put the
pieces together and get the whole thing to work.  Suppose that two or
three of those teams decide to use this library package and derives
child types from those abstract types.  This shouldn't be an issue for
teams working independently, but your idea would make it an issue,
because in order for the program to compile, you would require that
somebody write useless versions of the inherited operations for every
possible combination of derived types, even when the derived types
come from two different teams working independently.  Sounds like a
needless burden to me.


> Anyway your proposal would impose some draconian limitations on the
> packages structure. E.g. it would be impossible to provide implementations
> and different types of Marker in separate packages. Or consider a generic
> implementing a Marker for the given document type. Would that work?

1) Keep in mind that I wasn't trying to solve the whole world, just
one subset of the problem.  The way I envisioned it would, I think,
have been fairly simple to generate code for and wouldn't be a huge
implementation burden, nor would it have imposed a huge burden on
programmers.  (I could be wrong, since there are some cases I didn't
think about, particularly involving tag-indeterminate function
calls.)  I realize that my proposal wasn't going to solve everything,
but my feeling is that if you can solve a subset of a problem simply,
and solving the entire problem would be orders of magnitude more
complex, then the fact that there will still be unsolved issues isn't
a valid reason not to solve the narrower problem.  (That would be
called "letting the perfect be the enemy of the good enough".  And
even with the limitations you think are draconian, I think it would
have been good enough for the types of problems I was encountering.)
Unless we envision that the larger problem *will* be addressed at some
point and the solution to the smaller problem might interfere with the
larger solution.  But at the time, I didn't see any reason to believe
that the general "multiple dispatch" case will ever be addressed.
Maybe it still won't.

2) I didn't finish thinking everything through before I abandoned the
idea, so I didn't consider things like generics.  Also, it's possible
that there might have been a way to address some of your objections
without significantly adding to the implementation burden.

> What I find totally inappropriate for a language like Ada is:
>
> 3. Dynamic constraint with run-time checks dropping arbitrary exceptions.
>
> I think we should have learnt something from the "accessibility checks
> disaster".

OK, I don't understand this.  First, I don't understand what about
accessibility checks was a disaster; and second, I don't see what's
wrong with runtime checks in cases where it's too hard for a compiler
to figure out at compile time whether something will go wrong.  Is
this another case of letting the perfect be the enemy of the good
enough?

                                 -- Adam







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

* Re: Operation can be dispatching in only one type
  2009-11-18 16:39             ` Adam Beneschan
@ 2009-11-18 19:21               ` Dmitry A. Kazakov
  2009-11-19  0:27                 ` Randy Brukardt
  2009-11-19 16:04                 ` Adam Beneschan
  0 siblings, 2 replies; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-11-18 19:21 UTC (permalink / raw)


On Wed, 18 Nov 2009 08:39:14 -0800 (PST), Adam Beneschan wrote:

> On Nov 18, 1:46�am, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
> 
> Again, although I can see that someone might want to derive ASCII_Text
> from Plain_Text, it wasn't something I considered at the time since it
> wasn't germane to the type of problem I was running into.

So, in effect you want a depth-1 hierarchy, like we have for the protected
interfaces?

>> Consider again ASCII_Text derived from Plain_Text. Let we also derived from
>> Plain_Text_Region and Plain_Marker:
>>
>> � �Plain_Text <-- ASCII_Text
>> � �Plain_Text_Region <-- ASCII_Region
>> � �Plain_Marker <-- ASCII_Marker
>>
>> Now, my concern is what happens with Move_To called on
>>
>> � �ASCII_Text, Text_Region, Plain_Marker
>>
>> You say, it is Constraint_Error. The question what is the reason for this?
>> I don't see any. It is for the programmer to decide.
>>
>> I you say the language forbids that, I say OK, but then that MUST be done
>> static.
> 
> I don't see a practical reason why that would be necessary.  And I
> have a major objection, at least to what I think you're proposing.
> Suppose someone at some organization declares a package with some
> abstract types.  Another organization is developing a large
> application.  Since this is a large application, it's divided into
> several parts with one part being given to one team, another part to
> another team, and so on, working independently.  The idea is that as
> long as each team can develop its part of the application that works
> according to some "contract", then you should be able to put the
> pieces together and get the whole thing to work.  Suppose that two or
> three of those teams decide to use this library package and derives
> child types from those abstract types.  This shouldn't be an issue for
> teams working independently, but your idea would make it an issue,
> because in order for the program to compile, you would require that
> somebody write useless versions of the inherited operations for every
> possible combination of derived types, even when the derived types
> come from two different teams working independently.  Sounds like a
> needless burden to me.

No, it is not a burden it is a mere consequence of a decision made earlier.
If the abstract types are Printer and Contents with the joint operation
Print (the classic example of MD), you *have* to implement all
combinations. It is not a question. The question is how to make the
language helping us in doing this work safely and efficiently.

I have no idea how to do this while keeping it modular. But that does not
change the fact that all combinations have to be defined. To silently
define some of them as Constraint_Error is a very bad idea for the language
like Ada.

>> What I find totally inappropriate for a language like Ada is:
>>
>> 3. Dynamic constraint with run-time checks dropping arbitrary exceptions.
>>
>> I think we should have learnt something from the "accessibility checks
>> disaster".
> 
> OK, I don't understand this.  First, I don't understand what about
> accessibility checks was a disaster;

Because they are the major contributor to hours spent on debugging
unhandled exceptions.

> and second, I don't see what's
> wrong with runtime checks in cases where it's too hard for a compiler
> to figure out at compile time whether something will go wrong.

Accessibility checks are known for being false positive. Same with MD, it
is not a semantic error to cross types in an operation. It is an
*artificial* error introduced by the language designer, because it would be
too difficult to do it otherwise (e.g. right (:-)). Then the very same
designer finds his own error too difficult to detect at compile time! I
have no problem with the former, but do not accept the latter.

> Is
> this another case of letting the perfect be the enemy of the good
> enough?

There exist lots of imperfect languages already. But Ada must be perfect!
(:-))

Returning to the case where we do not want cross combinations. I thought
about it and came to the conclusion that this is single dispatch (tags are
synchronous). I think we should approach this differently.

Let us consider an example were dispatching table is semantically
"diagonal":

   type Object is limited interface ...;
   type Handle is interface ...;

Each time we derive from Object, we want a new Handle. This is IMO a better
example than Document x Region x Marker.

Note that here the issue of packages is especially important. Most likely
we wanted to place Objects into private packages, making only Handles
public.

Most operations on Object and Handle are same and have only one controlled
argument. I am tempted to say that Handle should also implement Object.

   type Handle is interface and Object ...;

But there are two cross operations:

   function Ref (X : Object) return Handle is abstract;
   function Target (X : Handle) return access Object is abstract;

The same problem more complicated. How to add

   type Readonly_Handle is interface ...;

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



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

* Re: Operation can be dispatching in only one type
  2009-11-18 19:21               ` Dmitry A. Kazakov
@ 2009-11-19  0:27                 ` Randy Brukardt
  2009-11-19  2:11                   ` Robert A Duff
  2009-11-19  8:50                   ` Dmitry A. Kazakov
  2009-11-19 16:04                 ` Adam Beneschan
  1 sibling, 2 replies; 132+ messages in thread
From: Randy Brukardt @ 2009-11-19  0:27 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:1wtsriaxu0s4s$.ikwnnz5teukp$.dlg@40tude.net...
...
>> OK, I don't understand this.  First, I don't understand what about
>> accessibility checks was a disaster;
>
> Because they are the major contributor to hours spent on debugging
> unhandled exceptions.

That seems odd to me. I rather *like* getting unhandled exceptions, because 
it is almost always easy to see what the problem is from the exception name 
and the traceback. (And all of my long-running programs have systems to 
record this in the case of an unexpected exception.) It's the incorrect 
results, compiler bugs (where the code is right, but the wrong thing 
happens), and crashes that cause "hours of debugging".

OTOH, doing something that even generates a runtime accessibility check is a 
bug IMHO (it's what Bob Duff calls a "tripping hazard" - a latent problem 
that will bite you when someone does something unconventional -- in that 
sense it is just like the bug of assigning a string parameter has lower 
bound 1); it would be useful if the compiler could optionally point out such 
places so you could fix them.

                                             Randy.






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

* Re: Operation can be dispatching in only one type
  2009-11-19  0:27                 ` Randy Brukardt
@ 2009-11-19  2:11                   ` Robert A Duff
  2009-11-19 15:57                     ` Adam Beneschan
  2009-11-19  8:50                   ` Dmitry A. Kazakov
  1 sibling, 1 reply; 132+ messages in thread
From: Robert A Duff @ 2009-11-19  2:11 UTC (permalink / raw)


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

> OTOH, doing something that even generates a runtime accessibility check is a 
> bug IMHO (it's what Bob Duff calls a "tripping hazard"...

I didn't invent the term.  ;-)

I think I first heard it from OSHA regulations, when I was working in a
factory making "real stuff" instead of software.  For example, I just 
found this by googling "OSHA tripping hazard":

  Extension cords that could cause a tripping hazard.

  This is an easy area for OSHA to find violations while auditing most
  organizations.  Extension cords are a major cause of tripping and fall
  hazards and therefore are under a microscope. Extension cords shall
  not be found passing through hallways, windows and other areas which
  could cause a tripping hazard. ... and train employees how to use the cords
  without creating a tripping hazard. 29 CFR 1910.310 &
  1910.305(G)(2)(iii)

>... - a latent problem 
> that will bite you when someone does something unconventional -- in that 
> sense it is just like the bug of assigning a string parameter has lower 
> bound 1); it would be useful if the compiler could optionally point out such 
> places so you could fix them.

My objection to run-time accessibility checks is that you can't pin the
blame on a particular line of code:

    procedure P (X : access T);

P either stores the access value in a long-lived global data structure
(in which case P(Local'Access) is a bad idea in clients)
or P does not do that
(in which case P(Local'Access) is just fine).
The author of P knows which one is the case,
but has no way (other than comments) to communicate this to
the author of the client.
I've never seen a case where P decides at run time which it is.

So we have a run-time check on something that is known at
compile time (by the person who wrote P), and should be
known at compile time (by the person who wrote the client).
Yes, it's a tripping hazard.

And when the exception is raised, we don't know whether P
or client-of-P is at fault.

- Bob



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

* Re: Operation can be dispatching in only one type
  2009-11-17 22:10         ` Adam Beneschan
  2009-11-18  9:46           ` Dmitry A. Kazakov
@ 2009-11-19  2:23           ` tmoran
  2009-11-19  8:32             ` Dmitry A. Kazakov
  1 sibling, 1 reply; 132+ messages in thread
From: tmoran @ 2009-11-19  2:23 UTC (permalink / raw)


> package Documents is
>
>     type Document is abstract tagged private;
>     type Text_Region is abstract tagged private;
>     type Marker is abstract tagged private;
>   ...
>     procedure Move_Text (Doc  : in out Document;
>                          From : in Text_Region;
>                          To   : in Marker)
>        is abstract;

  There's really no way at compile time to require a particular
relationship between two (or more) arbitrary parameters to a procedure.
If that's necessary, you usually combine them into a single object that's
a single parameter.  Thus if a Document could have up to 10 defined
Text_Regions and 20 Markers one could say

      type Document is abstract tagged private;
      -- Presumably includes an array or list of appropriate Text_Region
      -- descriptors and of Marker descriptors.

      type Text_Region_Ids is range 1 .. 10;
      type Marker_Ids is range 1 .. 20;

      procedure Move_Text (Doc  : in out Document;
                           From : in Text_Region_Ids;
                           To   : in Marker_Ids)
         is abstract;



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

* Re: Operation can be dispatching in only one type
  2009-11-19  2:23           ` tmoran
@ 2009-11-19  8:32             ` Dmitry A. Kazakov
  0 siblings, 0 replies; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-11-19  8:32 UTC (permalink / raw)


On Thu, 19 Nov 2009 02:23:07 +0000 (UTC), tmoran@acm.org wrote:

>> package Documents is
>>
>>     type Document is abstract tagged private;
>>     type Text_Region is abstract tagged private;
>>     type Marker is abstract tagged private;
>>   ...
>>     procedure Move_Text (Doc  : in out Document;
>>                          From : in Text_Region;
>>                          To   : in Marker)
>>        is abstract;
> 
>   There's really no way at compile time to require a particular
> relationship between two (or more) arbitrary parameters to a procedure.
> If that's necessary, you usually combine them into a single object that's
> a single parameter.

Yes, this is why I consider these cases single dispatch on a tuple of
types. It is like

   type Editing is interface (Document, Region, Marker);

And the operations are in fact defined on Editing, which has only one tag.

> Thus if a Document could have up to 10 defined
> Text_Regions and 20 Markers one could say
> 
>       type Document is abstract tagged private;
>       -- Presumably includes an array or list of appropriate Text_Region
>       -- descriptors and of Marker descriptors.
> 
>       type Text_Region_Ids is range 1 .. 10;
>       type Marker_Ids is range 1 .. 20;
> 
>       procedure Move_Text (Doc  : in out Document;
>                            From : in Text_Region_Ids;
>                            To   : in Marker_Ids)
>          is abstract;

It is not ADT. ID does not have finalization and cannot refer to a specific
Document. You will not be able to transparently manage Regions and Markers.

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



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

* Re: Operation can be dispatching in only one type
  2009-11-19  0:27                 ` Randy Brukardt
  2009-11-19  2:11                   ` Robert A Duff
@ 2009-11-19  8:50                   ` Dmitry A. Kazakov
  2009-11-19 23:54                     ` Randy Brukardt
  1 sibling, 1 reply; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-11-19  8:50 UTC (permalink / raw)


On Wed, 18 Nov 2009 18:27:42 -0600, Randy Brukardt wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
> news:1wtsriaxu0s4s$.ikwnnz5teukp$.dlg@40tude.net...
> ...
>>> OK, I don't understand this.  First, I don't understand what about
>>> accessibility checks was a disaster;
>>
>> Because they are the major contributor to hours spent on debugging
>> unhandled exceptions.
> 
> That seems odd to me. I rather *like* getting unhandled exceptions, because 
> it is almost always easy to see what the problem is from the exception name 
> and the traceback.

Only theoretically. Practically, the existing handlers of "legal"
exceptions get perplexed, the stack gets wound up causing a cascade of
exceptions in Finalize's.

> OTOH, doing something that even generates a runtime accessibility check is a 
> bug 

Isn't it an advise to use only 'Unchecked_Access? (:-))

I think it is a problem that the code containing 'Access or upcast pointer
type conversions is "suspicious", a subject of careful inspection for false
positives upon accessibility check:

   Upcast_Ptr (P)   -- Unsafe
   P.all'Access        -- Unsafe
   P.all'Unchecked_Access   -- "Safe"

> IMHO (it's what Bob Duff calls a "tripping hazard" - a latent problem 
> that will bite you when someone does something unconventional -- in that 
> sense it is just like the bug of assigning a string parameter has lower 
> bound 1); it would be useful if the compiler could optionally point out such 
> places so you could fix them.

The difference is that for string bound there is a way to do it safe and
for 'Access there is none (and I also agree with Robert's response.)

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



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

* Re: Operation can be dispatching in only one type
  2009-11-19  2:11                   ` Robert A Duff
@ 2009-11-19 15:57                     ` Adam Beneschan
  2009-11-19 19:39                       ` Robert A Duff
  0 siblings, 1 reply; 132+ messages in thread
From: Adam Beneschan @ 2009-11-19 15:57 UTC (permalink / raw)


On Nov 18, 6:11 pm, Robert A Duff <bobd...@shell01.TheWorld.com>
wrote:

> My objection to run-time accessibility checks is that you can't pin the
> blame on a particular line of code:
>
>     procedure P (X : access T);
>
> P either stores the access value in a long-lived global data structure
> (in which case P(Local'Access) is a bad idea in clients)
> or P does not do that
> (in which case P(Local'Access) is just fine).
> The author of P knows which one is the case,
> but has no way (other than comments) to communicate this to
> the author of the client.
> I've never seen a case where P decides at run time which it is.

Since I'm too lazy to look, I'm hoping you know this off the top of
your head: is there anything in the AI's about preconditions that
would allow something to be caught when P is called rather than later
in the body of P?  I thought there were also some proposed attributes
that could test accessibility levels.

                                  -- Adam



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

* Re: Operation can be dispatching in only one type
  2009-11-18 19:21               ` Dmitry A. Kazakov
  2009-11-19  0:27                 ` Randy Brukardt
@ 2009-11-19 16:04                 ` Adam Beneschan
  1 sibling, 0 replies; 132+ messages in thread
From: Adam Beneschan @ 2009-11-19 16:04 UTC (permalink / raw)


On Nov 18, 11:21 am, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> Returning to the case where we do not want cross combinations. I thought
> about it and came to the conclusion that this is single dispatch (tags are
> synchronous). I think we should approach this differently.

OK, this makes a lot of sense---the kind of thing I'm thinking of does
seem a lot more related to "single dispatch" than to the sort of
multiple dispatch in your earlier example involving a Printer and
Contents.  I haven't yet looked over the rest of your idea carefully
yet...  But at least I think we understand each other now.

                             -- Adam



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

* Re: Operation can be dispatching in only one type
  2009-11-19 15:57                     ` Adam Beneschan
@ 2009-11-19 19:39                       ` Robert A Duff
  2009-11-19 23:43                         ` Randy Brukardt
  0 siblings, 1 reply; 132+ messages in thread
From: Robert A Duff @ 2009-11-19 19:39 UTC (permalink / raw)


Adam Beneschan <adam@irvine.com> writes:

> On Nov 18, 6:11�pm, Robert A Duff <bobd...@shell01.TheWorld.com>
> wrote:
>
>> My objection to run-time accessibility checks is that you can't pin the
>> blame on a particular line of code:
>>
>> � � procedure P (X : access T);
>>
>> P either stores the access value in a long-lived global data structure
>> (in which case P(Local'Access) is a bad idea in clients)
>> or P does not do that
>> (in which case P(Local'Access) is just fine).
>> The author of P knows which one is the case,
>> but has no way (other than comments) to communicate this to
>> the author of the client.
>> I've never seen a case where P decides at run time which it is.
>
> Since I'm too lazy to look, I'm hoping you know this off the top of
> your head: is there anything in the AI's about preconditions that
> would allow something to be caught when P is called rather than later
> in the body of P?  I thought there were also some proposed attributes
> that could test accessibility levels.

Such things have been discussed.  We're probably going to have
preconditions, and I seem to recall discussing some way to query the
necessary accessibility-level info.

But I think perhaps the best solution is to use a named access type,
or an 'in out' parameter, in most cases.  Functions are going to allow
'in out' parameters (probably), so the need for access parameters
is much diminished.

- Bob




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

* Re: Operation can be dispatching in only one type
  2009-11-19 19:39                       ` Robert A Duff
@ 2009-11-19 23:43                         ` Randy Brukardt
  0 siblings, 0 replies; 132+ messages in thread
From: Randy Brukardt @ 2009-11-19 23:43 UTC (permalink / raw)


"Robert A Duff" <bobduff@shell01.TheWorld.com> wrote in message 
news:wcctywq1ezh.fsf@shell01.TheWorld.com...
> Adam Beneschan <adam@irvine.com> writes:
...
>> Since I'm too lazy to look, I'm hoping you know this off the top of
>> your head: is there anything in the AI's about preconditions that
>> would allow something to be caught when P is called rather than later
>> in the body of P?  I thought there were also some proposed attributes
>> that could test accessibility levels.
>
> Such things have been discussed.  We're probably going to have
> preconditions, and I seem to recall discussing some way to query the
> necessary accessibility-level info.

Memberships most likely will be extended to include accessibility checks. 
But I can't off-hand figure out how that could be used to do a library-level 
accessibility check short of declaring a named library-level access type to 
use in the membership. In that case, you probably should have just used the 
named type in the parameter in the first place and need no precondition (at 
least for that).

                             Randy.





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

* Re: Operation can be dispatching in only one type
  2009-11-19  8:50                   ` Dmitry A. Kazakov
@ 2009-11-19 23:54                     ` Randy Brukardt
  2009-11-20  8:34                       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 132+ messages in thread
From: Randy Brukardt @ 2009-11-19 23:54 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:1iipp3bn16fe2.yqa1gz1ru17a$.dlg@40tude.net...
> On Wed, 18 Nov 2009 18:27:42 -0600, Randy Brukardt wrote:
>
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>> news:1wtsriaxu0s4s$.ikwnnz5teukp$.dlg@40tude.net...
>> ...
>>>> OK, I don't understand this.  First, I don't understand what about
>>>> accessibility checks was a disaster;
>>>
>>> Because they are the major contributor to hours spent on debugging
>>> unhandled exceptions.
>>
>> That seems odd to me. I rather *like* getting unhandled exceptions, 
>> because
>> it is almost always easy to see what the problem is from the exception 
>> name
>> and the traceback.
>
> Only theoretically. Practically, the existing handlers of "legal"
> exceptions get perplexed, the stack gets wound up causing a cascade of
> exceptions in Finalize's.

That might be true in general, but definitely not in this case: a handler 
for Program_Error is *always* wrong (unless it is a global handler for *any* 
exception), as Program_Error always represents a program bug. So I don't see 
how "existing" handlers can be confused.

It is necessary to treat all Adjust and Finalize routines like task bodies 
in that they need a "when others" handler -- otherwise the exceptions are 
sucked up and you get completely lost. Our programming standard requires 
such handlers (generally, they output Exception_Information to the logging 
facility - and almost every significant Ada system needs some sort of 
logging facility).

...
> The difference is that for string bound there is a way to do it safe and
> for 'Access there is none (and I also agree with Robert's response.)

Well, Ada 2012 (or whatever it will be called) should help that out by 
giving you a way to compare accessibilites (via memberships). So at least 
you will be able to make checks to avoid the problem. Better than nothing, 
but still not ideal. The better way to avoid the problem is to never, ever 
use anonymous access types. (Named access types have checks that are always 
made at compile-time for most compilers -- but not Janus/Ada, because of 
generic sharing.)

                                       Randy.





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

* Re: Operation can be dispatching in only one type
  2009-11-19 23:54                     ` Randy Brukardt
@ 2009-11-20  8:34                       ` Dmitry A. Kazakov
  2009-11-20 10:58                         ` Jean-Pierre Rosen
                                           ` (2 more replies)
  0 siblings, 3 replies; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-11-20  8:34 UTC (permalink / raw)


On Thu, 19 Nov 2009 17:54:40 -0600, Randy Brukardt wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
> news:1iipp3bn16fe2.yqa1gz1ru17a$.dlg@40tude.net...
>> On Wed, 18 Nov 2009 18:27:42 -0600, Randy Brukardt wrote:
>>
>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>>> news:1wtsriaxu0s4s$.ikwnnz5teukp$.dlg@40tude.net...
>>> ...
>>>>> OK, I don't understand this.  First, I don't understand what about
>>>>> accessibility checks was a disaster;
>>>>
>>>> Because they are the major contributor to hours spent on debugging
>>>> unhandled exceptions.
>>>
>>> That seems odd to me. I rather *like* getting unhandled exceptions, because
>>> it is almost always easy to see what the problem is from the exception name
>>> and the traceback.
>>
>> Only theoretically. Practically, the existing handlers of "legal"
>> exceptions get perplexed, the stack gets wound up causing a cascade of
>> exceptions in Finalize's.
> 
> That might be true in general, but definitely not in this case: a handler 
> for Program_Error is *always* wrong (unless it is a global handler for *any* 
> exception), as Program_Error always represents a program bug. So I don't see 
> how "existing" handlers can be confused.

exception
   when Error : others =>
      some cleanup  -- This usually becomes a problem
      raise;

> It is necessary to treat all Adjust and Finalize routines like task bodies 
> in that they need a "when others" handler -- otherwise the exceptions are 
> sucked up and you get completely lost. Our programming standard requires 
> such handlers (generally, they output Exception_Information to the logging 
> facility - and almost every significant Ada system needs some sort of 
> logging facility).

Yes, but this does not help. Upon exception propagation (Constraint_Error),
you get some objects finalized. This in turn causes a snowball of
exceptions in finalized objects, because no design is robust to hold any
error at any place. In the end you have a huge log of meaningless messages,
which only complicate debugging. Sometimes I which Ada had "halt at once"
statement which would stop all tasks and hold any I/O.

But of course the proper solution would be contracted exceptions.

>> The difference is that for string bound there is a way to do it safe and
>> for 'Access there is none (and I also agree with Robert's response.)
> 
> Well, Ada 2012 (or whatever it will be called) should help that out by 
> giving you a way to compare accessibilites (via memberships). So at least 
> you will be able to make checks to avoid the problem. Better than nothing, 
> but still not ideal. The better way to avoid the problem is to never, ever 
> use anonymous access types. (Named access types have checks that are always 
> made at compile-time for most compilers -- but not Janus/Ada, because of 
> generic sharing.)

The problem is not bound to only anonymous types. It also appears when you
convert access types. The source type (or both) might be a formal generic
parameter, so you cannot statically ensure that a "local" pointer is
converted no a "less local" one. Pool specific pointers need to be
converted though one target object is derived from another. Here everything
is broken: generic contract, meaningless conversion, meaningless check,
meaningless exception.

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



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

* Re: Operation can be dispatching in only one type
  2009-11-20  8:34                       ` Dmitry A. Kazakov
@ 2009-11-20 10:58                         ` Jean-Pierre Rosen
  2009-11-21  6:02                         ` Randy Brukardt
  2009-11-22  5:45                         ` xorque
  2 siblings, 0 replies; 132+ messages in thread
From: Jean-Pierre Rosen @ 2009-11-20 10:58 UTC (permalink / raw)


Dmitry A. Kazakov a �crit :
> Sometimes I which Ada had "halt at once"
> statement which would stop all tasks and hold any I/O.
> 
Aborting the main task comes quite close to that wish, except that
controlled objects are finalized. But OTOH, you have these people who
want to be absolutely sure that objects get finalized under any
circumstance...

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



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

* Re: Operation can be dispatching in only one type
  2009-11-20  8:34                       ` Dmitry A. Kazakov
  2009-11-20 10:58                         ` Jean-Pierre Rosen
@ 2009-11-21  6:02                         ` Randy Brukardt
  2009-11-21 13:07                           ` Dmitry A. Kazakov
  2009-11-22  5:45                         ` xorque
  2 siblings, 1 reply; 132+ messages in thread
From: Randy Brukardt @ 2009-11-21  6:02 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:18wh86jvjvoe0.cofxcc8udm6q$.dlg@40tude.net...
> On Thu, 19 Nov 2009 17:54:40 -0600, Randy Brukardt wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>> news:1iipp3bn16fe2.yqa1gz1ru17a$.dlg@40tude.net...
...
>> That might be true in general, but definitely not in this case: a handler
>> for Program_Error is *always* wrong (unless it is a global handler for 
>> *any*
>> exception), as Program_Error always represents a program bug. So I don't 
>> see
>> how "existing" handlers can be confused.
>
> exception
>   when Error : others =>
>      some cleanup  -- This usually becomes a problem
>      raise;

If that's the case, "some cleanup" is seriously flawed. An "others" handler 
has to always work no matter what condition come into it, and in particular 
cannot depend on the code/data it surrounds to be in any particular state. 
The clean up code needs to be aware that data structures may be corrupt; if 
it isn't it of course will cascade errors and generally make a mess -- but 
in that case it is just junk code doing more harm than good.

I believe this particular pattern ("others" handler containing explicit 
cleanup) usually represents a bad design. Clients (or even the implementers 
of ADTs) often forget to include the cleanup where it is needed. These days, 
I try to put all needed cleanup into the ADTs, so that they get cleaned up 
no matter what -- finalization is pretty much the only certainty in Ada. And 
in that case, you don't need these kind of exception handlers.

>> It is necessary to treat all Adjust and Finalize routines like task 
>> bodies
>> in that they need a "when others" handler -- otherwise the exceptions are
>> sucked up and you get completely lost. Our programming standard requires
>> such handlers (generally, they output Exception_Information to the 
>> logging
>> facility - and almost every significant Ada system needs some sort of
>> logging facility).
>
> Yes, but this does not help. Upon exception propagation 
> (Constraint_Error),
> you get some objects finalized. This in turn causes a snowball of
> exceptions in finalized objects, because no design is robust to hold any
> error at any place. In the end you have a huge log of meaningless 
> messages,
> which only complicate debugging.

That can happen, but it usually indicates too much coupling between objects 
and/or too little concern about the implications of errors. Finalize 
routines should never, ever propagate an exception, and need to be written 
to avoid that - that means avoiding assumptions about other objects. If 
that's not done, of course you get messy cascades of errors. I realize that 
it isn't completely possible to avoid these things, but it can be minimized.

And the huge log of messages doesn't matter, you only need the first one 
(presuming every "others" handler logs the data). That's the place the 
exception was raised, and the information tells you how it got to that 
point; just ignore the rest of the log (in that sense it is just like fixing 
syntax errors in most compilers -- the correction isn't good enough to find 
more than the first error if it is at all significant).

> Sometimes I which Ada had "halt at once"
> statement which would stop all tasks and hold any I/O.

Janus/Ada does have such a thing (always did, it was the first thing 
implemented on CP/M back in 1980). It works because (to date) we don't use 
operating systems facilities for tasking, exception handling, or 
finalization. But it is pretty dangerous, and really can be used only to 
instantly shut down a misbehaving system -- but of course if there is any 
real resource management being handled by finalization, you could leak 
resources such that you don't get them back easily (the obvious example is 
temporary files, which won't be cleaned up in that scenario).

> But of course the proper solution would be contracted exceptions.

I don't see how that would help. The problem is used "others" when you 
really need to list the exceptions that you are expecting. If the compiler 
is smart enough to be able to prove that no bounded errors occur (and no 
constraint violations either), maybe that would do some good, but I doubt 
that you will see such compilers anytime soon. In the absence of that, you 
have to put Program_Error, Constraint_Error, and Storage_Error into every 
contract, so you don't gain much.

>>> The difference is that for string bound there is a way to do it safe and
>>> for 'Access there is none (and I also agree with Robert's response.)
>>
>> Well, Ada 2012 (or whatever it will be called) should help that out by
>> giving you a way to compare accessibilites (via memberships). So at least
>> you will be able to make checks to avoid the problem. Better than 
>> nothing,
>> but still not ideal. The better way to avoid the problem is to never, 
>> ever
>> use anonymous access types. (Named access types have checks that are 
>> always
>> made at compile-time for most compilers -- but not Janus/Ada, because of
>> generic sharing.)
>
> The problem is not bound to only anonymous types. It also appears when you
> convert access types. The source type (or both) might be a formal generic
> parameter, so you cannot statically ensure that a "local" pointer is
> converted no a "less local" one. Pool specific pointers need to be
> converted though one target object is derived from another. Here 
> everything
> is broken: generic contract, meaningless conversion, meaningless check,
> meaningless exception.

In this case, whether a check will fail is known statically for any compiler 
that generates generics via macro substitution (that is all Ada compilers 
other than Janus/Ada). I can hardly imagine that there exists a compiler 
that will generate "raise Program_Error" unconditionally without generating 
a warning! So this is an academic concern at best (I don't think you're 
using Janus/Ada) -- yes, you can ignore the warnings and run such a program, 
but there isn't any reason to actually do so unless you're running an ACATS 
test. (And if you do the conversion in the generic specification, the 
compiler is required to reject the program.)

                       Randy.







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

* Re: Operation can be dispatching in only one type
  2009-11-21  6:02                         ` Randy Brukardt
@ 2009-11-21 13:07                           ` Dmitry A. Kazakov
  0 siblings, 0 replies; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-11-21 13:07 UTC (permalink / raw)


On Sat, 21 Nov 2009 00:02:59 -0600, Randy Brukardt wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
> news:18wh86jvjvoe0.cofxcc8udm6q$.dlg@40tude.net...
>> On Thu, 19 Nov 2009 17:54:40 -0600, Randy Brukardt wrote:
>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>>> news:1iipp3bn16fe2.yqa1gz1ru17a$.dlg@40tude.net...
> ...
>>> That might be true in general, but definitely not in this case: a handler
>>> for Program_Error is *always* wrong (unless it is a global handler for *any*
>>> exception), as Program_Error always represents a program bug. So I don't 
>>> see how "existing" handlers can be confused.
>>
>> exception
>>   when Error : others =>
>>      some cleanup  -- This usually becomes a problem
>>      raise;
> 
> If that's the case, "some cleanup" is seriously flawed. An "others" handler 
> has to always work no matter what condition come into it, and in particular 
> cannot depend on the code/data it surrounds to be in any particular state. 
> The clean up code needs to be aware that data structures may be corrupt; if 
> it isn't it of course will cascade errors and generally make a mess -- but 
> in that case it is just junk code doing more harm than good.

Right, "others" stands for all "legal" exceptions propagating out of the
body, which the programmer was unable to specify, because it is too much
work to do. The problem is that "illegal" exceptions indicating broken
program do not belong here, and because of the lack of contracts you cannot
separate them. The pattern is wrong, but there is no other.

> I believe this particular pattern ("others" handler containing explicit 
> cleanup) usually represents a bad design. Clients (or even the implementers 
> of ADTs) often forget to include the cleanup where it is needed. These days, 
> I try to put all needed cleanup into the ADTs, so that they get cleaned up 
> no matter what -- finalization is pretty much the only certainty in Ada. And 
> in that case, you don't need these kind of exception handlers.

I agree, but that only moves cleanup from one place to another (Finalize).
There is no way to get rid of it. Within Finalize cleanup has even more
chances to get perplexed, because in Ada you cannot know whether Finalize
was called upon normal leaving the scope due to an exception propagation.
Further the Ada's construction model is not enough fine to fully
accommodate this pattern.

For accessibility checks it could also aggravate the problem because
accessibility is not invariant to moving from one body to another. The same
code might be OK or not OK within different bodies.

> And the huge log of messages doesn't matter, you only need the first one 
> (presuming every "others" handler logs the data).

No it will be the last one (it is a stack of errors which gets unwound),
but most likely it will be consumed by something else, like Program_Error.
That is a reason for the "wrong" pattern with "others". Yes it is bad, but
it lets you to log Exception_Information *before* things explode.

>> But of course the proper solution would be contracted exceptions.
> 
> I don't see how that would help. The problem is used "others" when you 
> really need to list the exceptions that you are expecting. If the compiler 
> is smart enough to be able to prove that no bounded errors occur (and no 
> constraint violations either), maybe that would do some good, but I doubt 
> that you will see such compilers anytime soon. In the absence of that, you 
> have to put Program_Error, Constraint_Error, and Storage_Error into every 
> contract, so you don't gain much.

It should be more intelligent than Java. For example, "I don't do
Storage_Error if there is N (static value) free bytes of stack", "I don't
raise Program_Error from Initialize/Finalize" etc.

An important issue to me is exception contract bound to some precondition,
which ensures absence of specified exceptions. When an exception happens,
it is not range error, or accessibility check to blame, but the
precondition violated.

>>>> The difference is that for string bound there is a way to do it safe and
>>>> for 'Access there is none (and I also agree with Robert's response.)
>>>
>>> Well, Ada 2012 (or whatever it will be called) should help that out by
>>> giving you a way to compare accessibilites (via memberships). So at least
>>> you will be able to make checks to avoid the problem. Better than nothing,
>>> but still not ideal. The better way to avoid the problem is to never, ever
>>> use anonymous access types. (Named access types have checks that are always
>>> made at compile-time for most compilers -- but not Janus/Ada, because of
>>> generic sharing.)
>>
>> The problem is not bound to only anonymous types. It also appears when you
>> convert access types. The source type (or both) might be a formal generic
>> parameter, so you cannot statically ensure that a "local" pointer is
>> converted no a "less local" one. Pool specific pointers need to be
>> converted though one target object is derived from another. Here everything
>> is broken: generic contract, meaningless conversion, meaningless check,
>> meaningless exception.
> 
> In this case, whether a check will fail is known statically for any compiler 
> that generates generics via macro substitution (that is all Ada compilers 
> other than Janus/Ada). I can hardly imagine that there exists a compiler 
> that will generate "raise Program_Error" unconditionally without generating 
> a warning!

Yes it generates that warning, and the warning is ignored. Any warning is
ignored, that is one the most fundamental principle of modern software
design. (:-))

The code was modified to X.all'Unchecked_Access. Everybody is happy?

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



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

* Re: Operation can be dispatching in only one type
  2009-11-20  8:34                       ` Dmitry A. Kazakov
  2009-11-20 10:58                         ` Jean-Pierre Rosen
  2009-11-21  6:02                         ` Randy Brukardt
@ 2009-11-22  5:45                         ` xorque
  2009-11-22 11:25                           ` Georg Bauhaus
  2 siblings, 1 reply; 132+ messages in thread
From: xorque @ 2009-11-22  5:45 UTC (permalink / raw)


I have to say I'm quite impressed that my question started so much
discussion.

For this (minor) project, I tried a multitude of different approaches
and ended up
with one that appeared safe, right until it ended up causing GNAT to
have some
sort of heart attack:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42140

After some five or six attempts with different methods, I think I'm at
the point
where I've given up on the idea of using more than one tagged type for
this and
will likely just expose opaque integer identifiers.

The problem was really one of state rather than dispatching, for me. I
wanted one
'archiver' type to dispatch operations that were stateless ("Can this
archiver open
this archive?"), one type to hold per-archive state (the state of an
open archive)
and one type to hold per-file state (a Stream_IO.File_Type handle or
an offset into
an open zip file).

I believe I sketched an example of the kind of interface I wanted (in
more or less
completely invalid Ada-ish pseudocode):

  Archive : access Archiver.Archive_t'Class;
  File    : access Archiver.File_t'Class;

  for Index in Archivers'Range loop
    if Archiver.Can_Mount
      (Archiver => Archivers (Index),
       Path     => "file.zip") then

      Archive := Archiver.Open_Archive
        (Archiver => Archivers (Index),
         Path     => "file.zip");

      File := Archiver.Open
        (Archive => Archive,
         Path    => "/directory/file.txt");

      Archiver.Close (File);
      Archiver.Close_Archive (Archive);
    end if;
  end loop;

This interface would have been entirely internal as somebody actually
using
the code would have used it through another layer (removing the
requirement
to test against different archivers and in effect making it impossible
to tell that
there are even multiple packages involved).

To the poster that didn't know what PhysicsFS was:

http://icculus.org/physfs/

A small example of how the interface is used (note that the fact that
there are
multiple archivers involved is completely hidden):

http://icculus.org/physfs/physfstut.txt

Regards,
xw



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

* Re: Operation can be dispatching in only one type
  2009-11-22  5:45                         ` xorque
@ 2009-11-22 11:25                           ` Georg Bauhaus
  2009-11-22 11:30                             ` xorque
  2009-11-22 16:25                             ` Dmitry A. Kazakov
  0 siblings, 2 replies; 132+ messages in thread
From: Georg Bauhaus @ 2009-11-22 11:25 UTC (permalink / raw)


On 11/22/09 6:45 AM, xorque wrote:
>
> For this (minor) project, I tried a multitude of different approaches
> and ended up
> with one that appeared safe, right until it ended up causing GNAT to
> have some
> sort of heart attack:
>
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42140

Do you get segmentation fault with GNAT run in Ada mode?
(Currently, this would mean options -gnato -fstack-check
and no -gnatp, I think.)

What happens if you name the access-to-String type used for
a component of Archive_t, i.e. something like

   type String_a is access String;
   subtype File_Name_a is String_a;

   type Archive_t is new Ada.Finalization.Limited_Controlled with record
     Name : File_Name_a;
     File : Stream_IO.File_Type;
   end record;





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

* Re: Operation can be dispatching in only one type
  2009-11-22 11:25                           ` Georg Bauhaus
@ 2009-11-22 11:30                             ` xorque
  2009-11-22 16:25                             ` Dmitry A. Kazakov
  1 sibling, 0 replies; 132+ messages in thread
From: xorque @ 2009-11-22 11:30 UTC (permalink / raw)


On Nov 22, 11:25 am, Georg Bauhaus <rm-
host.bauh...@maps.futureapps.de> wrote:
> >http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42140
>
> Do you get segmentation fault with GNAT run in Ada mode?
> (Currently, this would mean options -gnato -fstack-check
> and no -gnatp, I think.)

Yes, I actually always compile code with the following:

-O2 -g -fstack-check -gnatw.eHeFT -gnatVa -gnato -gnata
-gnatW8 -gnatiw -gnaty2aAbdefhiklnprStu

(Although without -O2 when actually writing code, though).

> What happens if you name the access-to-String type used for
> a component of Archive_t, i.e. something like

No change, unfortunately.

Regards,
xw



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

* Re: Operation can be dispatching in only one type
  2009-11-22 11:25                           ` Georg Bauhaus
  2009-11-22 11:30                             ` xorque
@ 2009-11-22 16:25                             ` Dmitry A. Kazakov
  2009-11-22 16:27                               ` xorque
  1 sibling, 1 reply; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-11-22 16:25 UTC (permalink / raw)


On Sun, 22 Nov 2009 12:25:40 +0100, Georg Bauhaus wrote:

> On 11/22/09 6:45 AM, xorque wrote:
>>
>> For this (minor) project, I tried a multitude of different approaches
>> and ended up
>> with one that appeared safe, right until it ended up causing GNAT to
>> have some
>> sort of heart attack:
>>
>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=42140
> 
> Do you get segmentation fault with GNAT run in Ada mode?
> (Currently, this would mean options -gnato -fstack-check
> and no -gnatp, I think.)

The code is broken. It creates a temporal object and takes an access to its
component. The obtained pointer is dangling.

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



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

* Re: Operation can be dispatching in only one type
  2009-11-22 16:25                             ` Dmitry A. Kazakov
@ 2009-11-22 16:27                               ` xorque
  2009-11-22 16:42                                 ` Dmitry A. Kazakov
  0 siblings, 1 reply; 132+ messages in thread
From: xorque @ 2009-11-22 16:27 UTC (permalink / raw)


On Nov 22, 4:25 pm, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:
> The code is broken. It creates a temporal object and takes an access to its
> component. The obtained pointer is dangling.
>

Not sure which part of the code you're referring to here.

Regards,
xw



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

* Re: Operation can be dispatching in only one type
  2009-11-22 16:27                               ` xorque
@ 2009-11-22 16:42                                 ` Dmitry A. Kazakov
  2009-11-22 16:52                                   ` xorque
  0 siblings, 1 reply; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-11-22 16:42 UTC (permalink / raw)


On Sun, 22 Nov 2009 08:27:59 -0800 (PST), xorque wrote:

> On Nov 22, 4:25�pm, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
>> The code is broken. It creates a temporal object and takes an access to its
>> component. The obtained pointer is dangling.
> 
> Not sure which part of the code you're referring to here.

The function Open_Archive returns a new object. In Main you call it and
then apply the function Stream to the result. Stream returns an access to
the component File of the temporal object created by Open_Archive. Then
this object is destroyed and a dangling pointer is assigned to S. When you
call Integer'Inpit on S, it accesses a garbage.

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



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

* Re: Operation can be dispatching in only one type
  2009-11-22 16:42                                 ` Dmitry A. Kazakov
@ 2009-11-22 16:52                                   ` xorque
  2009-11-22 17:41                                     ` Dmitry A. Kazakov
  0 siblings, 1 reply; 132+ messages in thread
From: xorque @ 2009-11-22 16:52 UTC (permalink / raw)


On Nov 22, 4:42 pm, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:
> On Sun, 22 Nov 2009 08:27:59 -0800 (PST), xorque wrote:
> > Not sure which part of the code you're referring to here.
>
> The function Open_Archive returns a new object. In Main you call it and
> then apply the function Stream to the result. Stream returns an access to
> the component File of the temporal object created by Open_Archive. Then
> this object is destroyed and a dangling pointer is assigned to S. When you
> call Integer'Inpit on S, it accesses a garbage.

Ah, I see what you mean.

In the process of trying to save the result of Open_Archive so that I
can test
if this problem still occurs, I've run into another problem:

  A : Archiver.Archiver_t;
  O : constant Archiver.Archive_t := Archiver.Archive_t
(Archiver.Open_Archive (A, "file.zip"));
  S : constant Stream_IO.Stream_Access := Archiver.Stream (O);

main.adb:9:46: illegal context for call to function with limited
result

I have to admit to not understanding that error.



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

* Re: Operation can be dispatching in only one type
  2009-11-22 16:52                                   ` xorque
@ 2009-11-22 17:41                                     ` Dmitry A. Kazakov
  2009-11-22 18:03                                       ` xorque
  0 siblings, 1 reply; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-11-22 17:41 UTC (permalink / raw)


On Sun, 22 Nov 2009 08:52:05 -0800 (PST), xorque wrote:

> On Nov 22, 4:42�pm, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
>> On Sun, 22 Nov 2009 08:27:59 -0800 (PST), xorque wrote:
>>> Not sure which part of the code you're referring to here.
>>
>> The function Open_Archive returns a new object. In Main you call it and
>> then apply the function Stream to the result. Stream returns an access to
>> the component File of the temporal object created by Open_Archive. Then
>> this object is destroyed and a dangling pointer is assigned to S. When you
>> call Integer'Inpit on S, it accesses a garbage.
> 
> Ah, I see what you mean.
> 
> In the process of trying to save the result of Open_Archive so that I
> can test
> if this problem still occurs, I've run into another problem:
> 
>   A : Archiver.Archiver_t;
>   O : constant Archiver.Archive_t := Archiver.Archive_t
> (Archiver.Open_Archive (A, "file.zip"));
>   S : constant Stream_IO.Stream_Access := Archiver.Stream (O);
> 
> main.adb:9:46: illegal context for call to function with limited
> result
> 
> I have to admit to not understanding that error.

And I don't understand your design. If Archive is a Stream derive then it
from Root_Stream_Type. If it deals with a stream then pass
Root_Stream_Type'Class to the operations that need it.

But never ever return pointers to components without an urgent need.

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



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

* Re: Operation can be dispatching in only one type
  2009-11-22 17:41                                     ` Dmitry A. Kazakov
@ 2009-11-22 18:03                                       ` xorque
  2009-11-22 18:08                                         ` xorque
                                                           ` (2 more replies)
  0 siblings, 3 replies; 132+ messages in thread
From: xorque @ 2009-11-22 18:03 UTC (permalink / raw)


On Nov 22, 5:41 pm, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:
> On Sun, 22 Nov 2009 08:52:05 -0800 (PST), xorque wrote:
>
> > I have to admit to not understanding that error.
>
> And I don't understand your design. If Archive is a Stream derive then it
> from Root_Stream_Type. If it deals with a stream then pass
> Root_Stream_Type'Class to the operations that need it.

The design is both irrelevant and obsolete. I'm just trying to find
out if
the problem is *definitely* that code so that I can close a bug in the
GCC tracker.

> But never ever return pointers to components without an urgent need.

Is it possible to save the return value of Open_Archive, or not?

Regards,
xw




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

* Re: Operation can be dispatching in only one type
  2009-11-22 18:03                                       ` xorque
@ 2009-11-22 18:08                                         ` xorque
  2009-11-22 18:28                                         ` Dmitry A. Kazakov
  2009-11-23  7:48                                         ` Georg Bauhaus
  2 siblings, 0 replies; 132+ messages in thread
From: xorque @ 2009-11-22 18:08 UTC (permalink / raw)


If it's not already obvious, I'm aware that there's a bug in the above
code but am
not currently convinced that it's the cause of *this* crash as the
crash occurs
before the archive is finalized.



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

* Re: Operation can be dispatching in only one type
  2009-11-22 18:03                                       ` xorque
  2009-11-22 18:08                                         ` xorque
@ 2009-11-22 18:28                                         ` Dmitry A. Kazakov
  2009-11-22 18:41                                           ` xorque
  2009-11-22 21:47                                           ` Robert A Duff
  2009-11-23  7:48                                         ` Georg Bauhaus
  2 siblings, 2 replies; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-11-22 18:28 UTC (permalink / raw)


On Sun, 22 Nov 2009 10:03:22 -0800 (PST), xorque wrote:

> On Nov 22, 5:41�pm, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
> wrote:
>> On Sun, 22 Nov 2009 08:52:05 -0800 (PST), xorque wrote:
>>
>>> I have to admit to not understanding that error.
>>
>> And I don't understand your design. If Archive is a Stream derive then it
>> from Root_Stream_Type. If it deals with a stream then pass
>> Root_Stream_Type'Class to the operations that need it.
> 
> The design is both irrelevant and obsolete. I'm just trying to find out if
> the problem is *definitely* that code so that I can close a bug in the
> GCC tracker.

The problem semantically is that you convert type, which would/should
create a copy of a limited object.

Within a declaration ":=" denotes initialization. You may not convert
anything initializing a limited object.

Proper ways to go:

O : constant Archiver.Archive_t'Class :=
    Archiver.Open_Archive (A, "file.zip");

or

O :Archiver.Archive_t'Class renames
    Archiver.Open_Archive (A, "file.zip");

or (with type casing, which is a *view* conversion)

O : Archiver.Archive_t renames
     Archiver.Archive_t (Archiver.Open_Archive (A, "file.zip"));

>> But never ever return pointers to components without an urgent need.
> 
> Is it possible to save the return value of Open_Archive, or not?

No, the type is limited it does not have "values", which can be saved
(copied). You can create an object initialized in a way that its state
would correspond to the desired value.

P.S. ":=" for initialization of limited objects might look misleading (and
does look misleading to me), but that would be another discussion on Ada
design, in which nobody would agree with me. So I prefer not to go into it.

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



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

* Re: Operation can be dispatching in only one type
  2009-11-22 18:28                                         ` Dmitry A. Kazakov
@ 2009-11-22 18:41                                           ` xorque
  2009-11-22 21:47                                           ` Robert A Duff
  1 sibling, 0 replies; 132+ messages in thread
From: xorque @ 2009-11-22 18:41 UTC (permalink / raw)


On Nov 22, 6:28 pm, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:
> On Sun, 22 Nov 2009 10:03:22 -0800 (PST), xorque wrote:
>
> The problem semantically is that you convert type, which would/should
> create a copy of a limited object...
> <snipped>
>

Ok, thanks for the explanation.

I made the change you suggest to initialize ("save") the archive and
the crash
doesn't occur. I've closed the bug on the GCC due to the discussion of
the
bug becoming confused between two issues (one of them - this one -
invalid
and another that's definitely valid).

Regards,
xw




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

* Re: Operation can be dispatching in only one type
  2009-11-22 18:28                                         ` Dmitry A. Kazakov
  2009-11-22 18:41                                           ` xorque
@ 2009-11-22 21:47                                           ` Robert A Duff
  2009-11-23  3:42                                             ` stefan-lucks
  2009-11-23  8:52                                             ` Dmitry A. Kazakov
  1 sibling, 2 replies; 132+ messages in thread
From: Robert A Duff @ 2009-11-22 21:47 UTC (permalink / raw)


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

> P.S. ":=" for initialization of limited objects might look misleading (and
> does look misleading to me), but that would be another discussion on Ada
> design, in which nobody would agree with me. So I prefer not to go into it.

Well, I would agree.

Ada uses the term "assignment" to refer to both "initial assignment /
initialization" and "assignment_statement / overwriting".
I'd prefer to use different symbols for the two.
We're not going to change Ada in that regard, for compatibility reasons,
but I'm thinking in my hobby language design to use the term "assignment"
for the initial one, and "reassignment" for the subsequent overwriting
one, and use different symbols for the two.

So, for a limited type, "assignment" is legal, "reassignment" is not.

What do you think?

- Bob



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

* Re: Operation can be dispatching in only one type
  2009-11-22 21:47                                           ` Robert A Duff
@ 2009-11-23  3:42                                             ` stefan-lucks
  2009-11-30 20:36                                               ` Robert A Duff
  2009-11-23  8:52                                             ` Dmitry A. Kazakov
  1 sibling, 1 reply; 132+ messages in thread
From: stefan-lucks @ 2009-11-23  3:42 UTC (permalink / raw)


On Sun, 22 Nov 2009, Robert A Duff wrote:

> Ada uses the term "assignment" to refer to both "initial assignment /
> initialization" and "assignment_statement / overwriting".
> I'd prefer to use different symbols for the two.
> We're not going to change Ada in that regard, for compatibility reasons,
> but I'm thinking in my hobby language design to use the term "assignment"
> for the initial one, and "reassignment" for the subsequent overwriting
> one, and use different symbols for the two.
> 
> So, for a limited type, "assignment" is legal, "reassignment" is not.

Distinguishing the two different operations which are written as ":=" in 
Ada by using different words and even different symbols would make a lot of 
sense. 

But it is quite a standard notion to write "assignment" for overwriting 
the current value of a variable by a new value. This notion is widely 
used, much beyond Ada. You would likely confuse people by calling that 
operation a "reassignment" and using "assignment" for anther kind of 
operation. Please don't do that!

Better use "assignment" for the overwriting operation, and another word 
(such as "initial assignment", "constructive assignment", "inisignment", 
... a native English speaker might find better words) for the type of 
assignment that does not overwrite an existing value, and which is allowed 
for limited types.

So long

-- 
------ Stefan Lucks   --  Bauhaus-University Weimar  --   Germany  ------
               Stefan dot Lucks at uni minus weimar dot de
------  I  love  the  taste  of  Cryptanalysis  in  the  morning!  ------




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

* Re: Operation can be dispatching in only one type
  2009-11-22 18:03                                       ` xorque
  2009-11-22 18:08                                         ` xorque
  2009-11-22 18:28                                         ` Dmitry A. Kazakov
@ 2009-11-23  7:48                                         ` Georg Bauhaus
  2009-11-23  7:58                                           ` Georg Bauhaus
  2 siblings, 1 reply; 132+ messages in thread
From: Georg Bauhaus @ 2009-11-23  7:48 UTC (permalink / raw)


On 11/22/09 7:03 PM, xorque wrote:
> On Nov 22, 5:41 pm, "Dmitry A. Kazakov"<mail...@dmitry-kazakov.de>
> wrote:
>> On Sun, 22 Nov 2009 08:52:05 -0800 (PST), xorque wrote:
>>
>>> I have to admit to not understanding that error.
>>
>> And I don't understand your design. If Archive is a Stream derive then it
>> from Root_Stream_Type. If it deals with a stream then pass
>> Root_Stream_Type'Class to the operations that need it.
>
> The design is both irrelevant and obsolete. I'm just trying to find
> out if
> the problem is *definitely* that code so that I can close a bug in the
> GCC tracker.

A seg fault is definitely not the answer I would expect
from an Ada program that was compiled by GNAT in Ada mode.
Even when a temporary is involved in dereferencing.

Also, there are some of the "usual suspects" in the code,
like others =>,  return ... do ... end.  No reason to
close the report, I think.





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

* Re: Operation can be dispatching in only one type
  2009-11-23  7:48                                         ` Georg Bauhaus
@ 2009-11-23  7:58                                           ` Georg Bauhaus
  0 siblings, 0 replies; 132+ messages in thread
From: Georg Bauhaus @ 2009-11-23  7:58 UTC (permalink / raw)


On 11/23/09 8:48 AM, I wrote:

> Also, there are some of the "usual suspects" in the code,
> like others =>, return ... do ... end. No reason to
others => {box}
Thunderbird post-Shredder still early release makes
  Character'Val(60) & Character'Val(62)
vanish, sorry.
> close the report, I think.
>
>




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

* Re: Operation can be dispatching in only one type
  2009-11-22 21:47                                           ` Robert A Duff
  2009-11-23  3:42                                             ` stefan-lucks
@ 2009-11-23  8:52                                             ` Dmitry A. Kazakov
  2009-11-30 20:43                                               ` Robert A Duff
  1 sibling, 1 reply; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-11-23  8:52 UTC (permalink / raw)


On Sun, 22 Nov 2009 16:47:21 -0500, Robert A Duff wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> 
>> P.S. ":=" for initialization of limited objects might look misleading (and
>> does look misleading to me), but that would be another discussion on Ada
>> design, in which nobody would agree with me. So I prefer not to go into it.
> 
> Well, I would agree.
> 
> Ada uses the term "assignment" to refer to both "initial assignment /
> initialization" and "assignment_statement / overwriting".
> I'd prefer to use different symbols for the two.
> We're not going to change Ada in that regard, for compatibility reasons,
> but I'm thinking in my hobby language design to use the term "assignment"
> for the initial one, and "reassignment" for the subsequent overwriting
> one, and use different symbols for the two.
> 
> So, for a limited type, "assignment" is legal, "reassignment" is not.
> 
> What do you think?

I would prefer conventional:

allocation
construction (initialization)
assignment
destruction (finalization)
deallocation

Semantically a limited object is never assigned. Its state comes into
existence per construction and disappears per destruction.

The word assignment for most people is associated with state change,
assuming that there was some state before. So

   X : T := F (Y);

looks equivalent to

   X : T;
begin
   X := F (Y);

But they are not. I would prefer proper constructors, e.g.

   X : T (Y); -- Y is a constraint of T, parameter of the constructor

I don't like functions returning limited objects.

But there also are two other forms of standard assignments. Depending on
whether the left part is available:

   procedure ":=" (Left : in out T; Right : T);

and

   function ":=" (Right : T) return T;

Ada uses the second form, but obviously there are important cases where the
first form is preferable (and conversely).

And further, there are three variants per each concerning dispatch:

   procedure ":=" (Left : in out T; Right : T);  -- Full MD
   procedure ":=" (Left : in out T; Right : T'Class);  -- Target-controlled
   procedure ":=" (Left : in out T'Class; Right : T);  -- Source-controlled

It would be difficult to sort this out! (:-))

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



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

* Re: Operation can be dispatching in only one type
  2009-11-23  3:42                                             ` stefan-lucks
@ 2009-11-30 20:36                                               ` Robert A Duff
  2009-11-30 23:54                                                 ` (see below)
  2009-12-01 12:13                                                 ` Georg Bauhaus
  0 siblings, 2 replies; 132+ messages in thread
From: Robert A Duff @ 2009-11-30 20:36 UTC (permalink / raw)


stefan-lucks@see-the.signature writes:

> On Sun, 22 Nov 2009, Robert A Duff wrote:
>
>> Ada uses the term "assignment" to refer to both "initial assignment /
>> initialization" and "assignment_statement / overwriting".
>> I'd prefer to use different symbols for the two.
>> We're not going to change Ada in that regard, for compatibility reasons,
>> but I'm thinking in my hobby language design to use the term "assignment"
>> for the initial one, and "reassignment" for the subsequent overwriting
>> one, and use different symbols for the two.
>> 
>> So, for a limited type, "assignment" is legal, "reassignment" is not.
>
> Distinguishing the two different operations which are written as ":=" in 
> Ada by using different words and even different symbols would make a lot of 
> sense. 

I definitely want to use different symbols as well as different words.
But I'm not sure what symbols to choose.  Maybe := and :== .

I want to allow:

    X : Integer;
    
    if ... then
        X := 0; -- initialize (what I want to call "assign")
    else
        X := 1; -- initialize (what I want to call "assign")
    end if;
    
    while ... loop
        X :== X + 1; -- overwriting (what I want to call "reassign")
        ...
    end loop;

> But it is quite a standard notion to write "assignment" for overwriting 
> the current value of a variable by a new value.

Well, the term is used in many non-functional languages for both cases:
overwriting junk-bits with a value, and overwriting a
previously-assigned value with a value.  This is presumably because
in those languages, there's no important difference between the two.

In functional languages, the term "single assignment" is sometimes used,
which means you can initialize a variable, but you can never overwrite.

>... This notion is widely 
> used, much beyond Ada. You would likely confuse people by calling that 
> operation a "reassignment" and using "assignment" for anther kind of 
> operation. Please don't do that!

Well, the word "reassignment" contains the word "assignment" -- it means
"to assign again".  I don't see why that would be confusing.

Ada (to keep this slightly on topic ;-)) of course uses "assignment"
for both kinds: initialization and assignment_statement.  I find
that confusing, because you'd think "assignment_statement" is the (only)
thing that does "assignment".

> Better use "assignment" for the overwriting operation, and another word 
> (such as "initial assignment", "constructive assignment", "inisignment", 
> ... a native English speaker might find better words) for the type of 
> assignment that does not overwrite an existing value, and which is allowed 
> for limited types.

Thanks for the advice, but I'm not sure I'm convinced to take it.

If we agree that there are two different kinds of things called
"assignment" in common languages, I don't see why one should deserve the
term "assignment" in preference to the other...

- Bob



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

* Re: Operation can be dispatching in only one type
  2009-11-23  8:52                                             ` Dmitry A. Kazakov
@ 2009-11-30 20:43                                               ` Robert A Duff
  2009-12-01  9:00                                                 ` Dmitry A. Kazakov
  0 siblings, 1 reply; 132+ messages in thread
From: Robert A Duff @ 2009-11-30 20:43 UTC (permalink / raw)


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

> The word assignment for most people is associated with state change,
> assuming that there was some state before. So
>
>    X : T := F (Y);
>
> looks equivalent to
>
>    X : T;
> begin
>    X := F (Y);
>
> But they are not.

Right.  I think they should be equivalent.  My solution is to use
two different symbols for (initial) assignment and (subsequent)
reassignment.

>... I would prefer proper constructors, e.g.
>
>    X : T (Y); -- Y is a constraint of T, parameter of the constructor
>
> I don't like functions returning limited objects.

I know you don't, but I don't understand why.

Using named functions as constructors has a big advantage -- you can
have more than one, and you can give them meaningful names.

For example:

    X : Sequence := Empty_Seq;
    Y : Sequence := Singleton_Seq (Item => 123);
    Z : Sequence := Make_Sequence (Length => 123);

With discriminants, what does the 123 mean?  You have to pick one.

> But there also are two other forms of standard assignments. Depending on
> whether the left part is available:
>
>    procedure ":=" (Left : in out T; Right : T);
>
> and
>
>    function ":=" (Right : T) return T;
>
> Ada uses the second form, but obviously there are important cases where the
> first form is preferable (and conversely).
>
> And further, there are three variants per each concerning dispatch:
>
>    procedure ":=" (Left : in out T; Right : T);  -- Full MD
>    procedure ":=" (Left : in out T; Right : T'Class);  -- Target-controlled
>    procedure ":=" (Left : in out T'Class; Right : T);  -- Source-controlled
>
> It would be difficult to sort this out! (:-))

Yeah, I'm not sure what the right answer is.

- Bob



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

* Re: Operation can be dispatching in only one type
  2009-11-30 20:36                                               ` Robert A Duff
@ 2009-11-30 23:54                                                 ` (see below)
  2009-12-01 12:13                                                 ` Georg Bauhaus
  1 sibling, 0 replies; 132+ messages in thread
From: (see below) @ 2009-11-30 23:54 UTC (permalink / raw)


On 30/11/2009 20:36, in article wcc8wdn697e.fsf@shell01.TheWorld.com,
"Robert A Duff" <bobduff@shell01.TheWorld.com> wrote:

> stefan-lucks@see-the.signature writes:

>> Distinguishing the two different operations which are written as ":=" in
>> Ada by using different words and even different symbols would make a lot of
>> sense. 
 
> I definitely want to use different symbols as well as different words.
> But I'm not sure what symbols to choose.  Maybe := and :== .
> 
> I want to allow:
> 
>     X : Integer;
>     
>     if ... then
>         X := 0; -- initialize (what I want to call "assign")
>     else
>         X := 1; -- initialize (what I want to call "assign")
>     end if;
>     
>     while ... loop
>         X :== X + 1; -- overwriting (what I want to call "reassign")
>         ...
>     end loop;

What is wrong with the terms "initialize" and "assign", respectively?

   X : Integer initially if ... then 0 else 1 end if;
   Y : Integer constant  if ... then 1 else 2 end if;
   
   while ... loop
      X := X + Y; -- assign
      ...
   end loop;

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





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

* Re: Operation can be dispatching in only one type
  2009-12-01  9:00                                                 ` Dmitry A. Kazakov
@ 2009-12-01  5:45                                                   ` stefan-lucks
  2009-12-01 11:12                                                     ` Dmitry A. Kazakov
  0 siblings, 1 reply; 132+ messages in thread
From: stefan-lucks @ 2009-12-01  5:45 UTC (permalink / raw)


On Tue, 1 Dec 2009, Dmitry A. Kazakov wrote:

> On Mon, 30 Nov 2009 15:43:21 -0500, Robert A Duff wrote:

> > Right.  I think they should be equivalent.  My solution is to use
> > two different symbols for (initial) assignment and (subsequent)
> > reassignment.
> 
> But they cannot be, otherwise the semantics of ":=" would depend on the
> things done before:
> 
>     X : T;
> begin
>     X := F (Y); -- Initialization

No, at this point of time, X has been initialised to *some* value, even if 
the value itself is undefined. So this is just a proper assignment. 

>     X : T;
> begin
>     X := Z;
>     X := F (Y); -- [Re]assignment

That is a proper assignment, as well. The only difference is that we 
can be sure the before-assignment value of X is defined (assuming the 
value of Z is a defined one).  

An initialisation would be

     X : T ::= F(Y);
  begin
     ...

But you are right, Dmitry, nobody would not want to distinguish an
assignment to overwrite a potentially undefined value from an assignment 
ovwerwriting a previously defined value.

-- 
------ Stefan Lucks   --  Bauhaus-University Weimar  --   Germany  ------
               Stefan dot Lucks at uni minus weimar dot de
------  I  love  the  taste  of  Cryptanalysis  in  the  morning!  ------




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

* Re: Operation can be dispatching in only one type
  2009-12-01 11:12                                                     ` Dmitry A. Kazakov
@ 2009-12-01  8:01                                                       ` stefan-lucks
  2009-12-01 13:37                                                         ` Dmitry A. Kazakov
  2009-12-15 23:54                                                         ` Robert A Duff
  0 siblings, 2 replies; 132+ messages in thread
From: stefan-lucks @ 2009-12-01  8:01 UTC (permalink / raw)


On Tue, 1 Dec 2009, Dmitry A. Kazakov wrote:

> On Tue, 1 Dec 2009 06:45:16 +0100, stefan-lucks@see-the.signature wrote:
> 
> > On Tue, 1 Dec 2009, Dmitry A. Kazakov wrote:
> > 
> >> On Mon, 30 Nov 2009 15:43:21 -0500, Robert A Duff wrote:
> > 
> >>> Right.  I think they should be equivalent.  My solution is to use
> >>> two different symbols for (initial) assignment and (subsequent)
> >>> reassignment.
> >> 
> >> But they cannot be, otherwise the semantics of ":=" would depend on the
> >> things done before:
> >> 
> >>     X : T;
> >> begin
> >>     X := F (Y); -- Initialization
> > 
> > No, at this point of time, X has been initialised to *some* value, even if 
> > the value itself is undefined. So this is just a proper assignment. 
> 
> You should say that to Bob, because this is exactly my point.

No!

You just moved to a different topic:

[...]
> Initialization /= construction does not fit into this picture.

The issue was 

  initialisation /= assignment (*)

and the fact that in Ada both look syntactically the same. You seem to be 
the first to mention "construction" at all.

BTW, I don't think initialisation and construction are actually identical, 
even though they have to be performed in close temporal proximity. If 
construction fails, this is a Storage_Error. A failed Initialisation is 
much more powerful -- it can raise any of your favourite exceptions. ;-)


---------
Footnote:
(*) I prefer to avoid the word "reassignment", which Bob would use. 



-- 
------ Stefan Lucks   --  Bauhaus-University Weimar  --   Germany  ------
               Stefan dot Lucks at uni minus weimar dot de
------  I  love  the  taste  of  Cryptanalysis  in  the  morning!  ------




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

* Re: Operation can be dispatching in only one type
  2009-11-30 20:43                                               ` Robert A Duff
@ 2009-12-01  9:00                                                 ` Dmitry A. Kazakov
  2009-12-01  5:45                                                   ` stefan-lucks
  0 siblings, 1 reply; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-12-01  9:00 UTC (permalink / raw)


On Mon, 30 Nov 2009 15:43:21 -0500, Robert A Duff wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> 
>> The word assignment for most people is associated with state change,
>> assuming that there was some state before. So
>>
>>    X : T := F (Y);
>>
>> looks equivalent to
>>
>>    X : T;
>> begin
>>    X := F (Y);
>>
>> But they are not.
> 
> Right.  I think they should be equivalent.  My solution is to use
> two different symbols for (initial) assignment and (subsequent)
> reassignment.

But they cannot be, otherwise the semantics of ":=" would depend on the
things done before:

    X : T;
begin
    X := F (Y); -- Initialization

    X : T;
begin
    X := Z;
    X := F (Y); -- [Re]assignment

This is unacceptable, because it is untyped. The semantics of ":=" must be
solely defined by the types and, maybe, be the context (declarative vs.
imperative (as it is now). I don't like even the second part.

>>... I would prefer proper constructors, e.g.
>>
>>    X : T (Y); -- Y is a constraint of T, parameter of the constructor
>>
>> I don't like functions returning limited objects.
> 
> I know you don't, but I don't understand why.

Because they cannot return anything, so a "return statement" is invented
together with an infinite chain of other unholy things bending and twisting
otherwise clear and established notions.

> Using named functions as constructors has a big advantage -- you can
> have more than one, and you can give them meaningful names.
> 
> For example:
> 
>     X : Sequence := Empty_Seq;
>     Y : Sequence := Singleton_Seq (Item => 123);
>     Z : Sequence := Make_Sequence (Length => 123);
> 
> With discriminants, what does the 123 mean?  You have to pick one.

No problem:

   X : Sequence;
   Y : Sequence (Item => 123);
   Z : Sequence (Length => 123);

In my imaginary world public discriminant (as well as a public record
component) is only an interface, therefore it is no problem for a type have
any collection of public discriminant sets. They are just like other
operations, you could overload them if necessary.

>> But there also are two other forms of standard assignments. Depending on
>> whether the left part is available:
>>
>>    procedure ":=" (Left : in out T; Right : T);
>>
>> and
>>
>>    function ":=" (Right : T) return T;
>>
>> Ada uses the second form, but obviously there are important cases where the
>> first form is preferable (and conversely).
>>
>> And further, there are three variants per each concerning dispatch:
>>
>>    procedure ":=" (Left : in out T; Right : T);  -- Full MD
>>    procedure ":=" (Left : in out T; Right : T'Class);  -- Target-controlled
>>    procedure ":=" (Left : in out T'Class; Right : T);  -- Source-controlled
>>
>> It would be difficult to sort this out! (:-))
> 
> Yeah, I'm not sure what the right answer is.

I think that assignment should be considered a plain primitive procedure
with no special treatment. Initialization has in my view nothing to do with
it. The language should visually separate both.

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



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

* Re: Operation can be dispatching in only one type
  2009-12-01  5:45                                                   ` stefan-lucks
@ 2009-12-01 11:12                                                     ` Dmitry A. Kazakov
  2009-12-01  8:01                                                       ` stefan-lucks
  0 siblings, 1 reply; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-12-01 11:12 UTC (permalink / raw)


On Tue, 1 Dec 2009 06:45:16 +0100, stefan-lucks@see-the.signature wrote:

> On Tue, 1 Dec 2009, Dmitry A. Kazakov wrote:
> 
>> On Mon, 30 Nov 2009 15:43:21 -0500, Robert A Duff wrote:
> 
>>> Right.  I think they should be equivalent.  My solution is to use
>>> two different symbols for (initial) assignment and (subsequent)
>>> reassignment.
>> 
>> But they cannot be, otherwise the semantics of ":=" would depend on the
>> things done before:
>> 
>>     X : T;
>> begin
>>     X := F (Y); -- Initialization
> 
> No, at this point of time, X has been initialised to *some* value, even if 
> the value itself is undefined. So this is just a proper assignment. 

You should say that to Bob, because this is exactly my point.

An object is *always* constructed <=> initialized before it can ever be
used in any way (provided the language is typed <=> at any point of its
existence any object has a definite type and only the operations defined
for the type are available to the object). Initialization /= construction
does not fit into this picture.

>>     X : T;
>> begin
>>     X := Z;
>>     X := F (Y); -- [Re]assignment
> 
> That is a proper assignment, as well. The only difference is that we 
> can be sure the before-assignment value of X is defined (assuming the 
> value of Z is a defined one).  
> 
> An initialisation would be
> 
>      X : T ::= F(Y);
>   begin
>      ...
> 
> But you are right, Dmitry, nobody would not want to distinguish an
> assignment to overwrite a potentially undefined value from an assignment 
> ovwerwriting a previously defined value.

Of course I am! (:-))

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



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

* Re: Operation can be dispatching in only one type
  2009-11-30 20:36                                               ` Robert A Duff
  2009-11-30 23:54                                                 ` (see below)
@ 2009-12-01 12:13                                                 ` Georg Bauhaus
  2009-12-01 12:23                                                   ` Georg Bauhaus
                                                                     ` (2 more replies)
  1 sibling, 3 replies; 132+ messages in thread
From: Georg Bauhaus @ 2009-12-01 12:13 UTC (permalink / raw)


Robert A Duff schrieb:
> stefan-lucks@see-the.signature writes:
> 
>> On Sun, 22 Nov 2009, Robert A Duff wrote:
>>
>>> Ada uses the term "assignment" to refer to both "initial assignment /
>>> initialization" and "assignment_statement / overwriting".
>>> I'd prefer to use different symbols for the two.
>>> We're not going to change Ada in that regard, for compatibility reasons,
>>> but I'm thinking in my hobby language design to use the term "assignment"
>>> for the initial one, and "reassignment" for the subsequent overwriting
>>> one, and use different symbols for the two.
>>>
>>> So, for a limited type, "assignment" is legal, "reassignment" is not.
>> Distinguishing the two different operations which are written as ":=" in 
>> Ada by using different words and even different symbols would make a lot of 
>> sense. 
> 
> I definitely want to use different symbols as well as different words.

Am I correct in assuming that one important part of this argument
is about referring to the value stored for some variable before
this store has a "reasonable" value? (Where "reasonable" does not
currently have a meaning that can be inferred from the LRM, I guess.)

If so, and presuming the programming language Ada is very much,
and explicitly, about storing and manipulating bits in registers,
memory words, ... of digital computers in a strongly typed fashion:
In this case I would know the use of being carried away by functional,
uhm, phantasm, pardon the expression.  Rather, why not have Ada turn
warnings about "uninitialized" variables into a rule like Java's?

Then we could rely on the language: compilers will detect
uninitialized variables provided these do not have a pragma/keyword/...
to say that uninitialized is what the programmer wants.
Some fancy means to tell the compiler that this variable
does indeed have a good first value like pragma Import.

   X : [constant] Car; -- default init,
                       -- undefined,
                       -- junk bits. Doesn't matter
   --  *no* pragma Import (Ada, X);

begin

   Spare := X.Tire (5); -- would become illegal,
           -- as no value has been assigned yet.
           -- Currently, we get a warning

   if Fast then
      X := Ferrari.Make (...);
   else
      X := Fiat.Make (...);
   end if;

   Spare := X.Tire (5);


Does the phrase "first value" make sense?



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

* Re: Operation can be dispatching in only one type
  2009-12-01 12:13                                                 ` Georg Bauhaus
@ 2009-12-01 12:23                                                   ` Georg Bauhaus
  2009-12-01 12:44                                                     ` Georg Bauhaus
  2009-12-01 13:48                                                   ` Dmitry A. Kazakov
  2009-12-01 23:51                                                   ` Randy Brukardt
  2 siblings, 1 reply; 132+ messages in thread
From: Georg Bauhaus @ 2009-12-01 12:23 UTC (permalink / raw)


Georg Bauhaus schrieb:

> In this case I would know the use of being carried away by functional,
> uhm, phantasm, pardon the expression.

There is a "not" after "would", sorry.



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

* Re: Operation can be dispatching in only one type
  2009-12-01 12:23                                                   ` Georg Bauhaus
@ 2009-12-01 12:44                                                     ` Georg Bauhaus
  0 siblings, 0 replies; 132+ messages in thread
From: Georg Bauhaus @ 2009-12-01 12:44 UTC (permalink / raw)


Georg Bauhaus schrieb:
> Georg Bauhaus schrieb:
> 
>> In this case I would know the use of being carried away by functional,
>> uhm, phantasm, pardon the expression.
> 
> There is a "not" after "would", sorry.

It's missing in fact.  I'll get something to eat...



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

* Re: Operation can be dispatching in only one type
  2009-12-01  8:01                                                       ` stefan-lucks
@ 2009-12-01 13:37                                                         ` Dmitry A. Kazakov
  2009-12-15 23:54                                                         ` Robert A Duff
  1 sibling, 0 replies; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-12-01 13:37 UTC (permalink / raw)


On Tue, 1 Dec 2009 09:01:11 +0100, stefan-lucks@see-the.signature wrote:

> BTW, I don't think initialisation and construction are actually identical, 
> even though they have to be performed in close temporal proximity. If 
> construction fails, this is a Storage_Error.

No, it is Program_Error in Ada.

Construction /= allocation. Here I repeat the object's life cycle as I see
it:

allocation
   construction (=initialization)
      use (includes assignment and all public operations)
   destruction (=finalization)
deallocation

> A failed Initialisation is 
> much more powerful -- it can raise any of your favourite exceptions. ;-)

Well, I think it is possible to roll back an initialization, though it was
not attempted in Ada.

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



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

* Re: Operation can be dispatching in only one type
  2009-12-01 12:13                                                 ` Georg Bauhaus
  2009-12-01 12:23                                                   ` Georg Bauhaus
@ 2009-12-01 13:48                                                   ` Dmitry A. Kazakov
  2009-12-01 15:02                                                     ` Georg Bauhaus
  2009-12-01 23:51                                                   ` Randy Brukardt
  2 siblings, 1 reply; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-12-01 13:48 UTC (permalink / raw)


On Tue, 01 Dec 2009 13:13:29 +0100, Georg Bauhaus wrote:

> Then we could rely on the language: compilers will detect
> uninitialized variables provided these do not have a pragma/keyword/...
> to say that uninitialized is what the programmer wants.
> Some fancy means to tell the compiler that this variable
> does indeed have a good first value like pragma Import.
> 
>    X : [constant] Car; -- default init,

The error is here!
>                        -- undefined,
>                        -- junk bits. Doesn't matter
>    --  *no* pragma Import (Ada, X);
> 
> begin
> 
>    Spare := X.Tire (5); -- would become illegal,

Not here!

-------------------------
Anyway, you cannot do that because:

   if HALT (P) then
     X := Z;
   end if;
   Y := X;  -- Is this legal?

> Does the phrase "first value" make sense?

An object shall not have invalid values. All values are valid if the
language is typed. Enforcing user-defined construction including
prohibition of certain kinds of construction (e.g. per default constructor)
is a different story.

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



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

* Re: Operation can be dispatching in only one type
  2009-12-01 13:48                                                   ` Dmitry A. Kazakov
@ 2009-12-01 15:02                                                     ` Georg Bauhaus
  2009-12-01 16:18                                                       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 132+ messages in thread
From: Georg Bauhaus @ 2009-12-01 15:02 UTC (permalink / raw)


Dmitry A. Kazakov schrieb:
> On Tue, 01 Dec 2009 13:13:29 +0100, Georg Bauhaus wrote:
> 
>> Then we could rely on the language: compilers will detect
>> uninitialized variables provided these do not have a pragma/keyword/...
>> to say that uninitialized is what the programmer wants.
>> Some fancy means to tell the compiler that this variable
>> does indeed have a good first value like pragma Import.
>>
>>    X : [constant] Car; -- default init,
> 
> The error is here!
>>                        -- undefined,
>>                        -- junk bits. Doesn't matter
>>    --  *no* pragma Import (Ada, X);
>>
>> begin
>>
>>    Spare := X.Tire (5); -- would become illegal,
> 
> Not here!

Why? Nothing needs to have happened in between the X's
declaration and the first reference made to it.


> -------------------------
> Anyway, you cannot do that because:
> 
>    if HALT (P) then
>      X := Z;
>    end if;
>    Y := X;  -- Is this legal?


(HALT is a run-time issue that has no impact here.)
While this snippet would not be legal as is (on purpose!),
Ada's case coverage rules can make the programmer write a
legal program easily: write an else branch!
The compiler can then decide that a value will be assigned
in either branch.

If nothing is to be assigned this can only be for
the reason that the variable is imported, or has a
value already.
In the former case an unchecked conversion involving only
the variable will do; syntactic sugar might be nice to have.

  if HALT (P) then
      X := Z;
  else
      !X;
  end if;

One might even omit the else branch without loss
when Ada forces saying that the variable is imported.


>> Does the phrase "first value" make sense?
> 
> An object shall not have invalid values. All values are valid if the
> language is typed. Enforcing user-defined construction including
> prohibition of certain kinds of construction (e.g. per default constructor)
> is a different story.
> 

If you feed this to a Java compiler you will see how it is done.
The Java compiler will not accept a reference to a variable's
component when the variable may not have been initialized.


import java.math.BigInteger;

public class Dummy
{

    enum TireColor {
        Black, White
    };

    class Tire
    {
        TireColor rim_color;
    }

    public static void main(String[] args)
    {
        Tire spare;
        TireColor its_color;
        final BigInteger P; // some program's number

        P = BigInteger.valueOf(Long.parseLong(args[0]));

        if (HALT(P)) {
            spare = new Tire();
        }
        // this line not accepted by a Java compiler:
        its_color = spare.rim_color;  //  <-----

    }

    static boolean HALT(BigInteger gn)
    {
        // dummy
        if (gn.equals(BigInteger.ZERO))
            return true;
        return HALT(gn.add(BigInteger.ONE));
    }
}



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

* Re: Operation can be dispatching in only one type
  2009-12-01 15:02                                                     ` Georg Bauhaus
@ 2009-12-01 16:18                                                       ` Dmitry A. Kazakov
  2009-12-01 17:52                                                         ` Georg Bauhaus
  0 siblings, 1 reply; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-12-01 16:18 UTC (permalink / raw)


On Tue, 01 Dec 2009 16:02:21 +0100, Georg Bauhaus wrote:

> Dmitry A. Kazakov schrieb:
>> On Tue, 01 Dec 2009 13:13:29 +0100, Georg Bauhaus wrote:
>> 
>>> Then we could rely on the language: compilers will detect
>>> uninitialized variables provided these do not have a pragma/keyword/...
>>> to say that uninitialized is what the programmer wants.
>>> Some fancy means to tell the compiler that this variable
>>> does indeed have a good first value like pragma Import.
>>>
>>>    X : [constant] Car; -- default init,
>> 
>> The error is here!
>>>                        -- undefined,
>>>                        -- junk bits. Doesn't matter
>>>    --  *no* pragma Import (Ada, X);
>>>
>>> begin
>>>
>>>    Spare := X.Tire (5); -- would become illegal,
>> 
>> Not here!
> 
> Why?

Because X is illegal right after begin:

IF accessing X is illegal THEN the corresponding operation does not belong
to the type of X THEN the type of X is not Car. q.e.d.

(Provided, we are talking about a typed language)

>> -------------------------
>> Anyway, you cannot do that because:
>> 
>>    if HALT (P) then
>>      X := Z;
>>    end if;
>>    Y := X;  -- Is this legal?
> 
> (HALT is a run-time issue that has no impact here.)

If you cannot decide if X is "initialized", then you cannot decode whether
the program is legal. However you could define some set of pragmatic rules
with either many false positives or many false negatives, or even mixed.
These rules will be most likely observed as arbitrary by laymen. I don't
think the issue deserves this.

> While this snippet would not be legal as is (on purpose!),
> Ada's case coverage rules can make the programmer write a
> legal program easily: write an else branch!

And this one:

procedure Foo (X : in out Car);
   ...
begin
   Foo (X);
   Y := X; -- Is this legal?

Probably, already the call to Foo is illegal? And if Foo were declared as

procedure Foo (X : out Car);

>>> Does the phrase "first value" make sense?
>> 
>> An object shall not have invalid values. All values are valid if the
>> language is typed. Enforcing user-defined construction including
>> prohibition of certain kinds of construction (e.g. per default constructor)
>> is a different story. 
> 
> If you feed this to a Java compiler you will see how it is done.
> The Java compiler will not accept a reference to a variable's
> component when the variable may not have been initialized.

I consider this model wrong. It is better not to introduce inappropriate
values rather than trying to catch them later. Java does not have
constrained types, so I can understand why they go this way. I think it is
better to ensure that a declared value is initialized at the declaration
point. I also think that forward uninitialized declarations represent bad
style, e.g.:

function Foo (...) return Bar is
   Result : Bar;
begin
   ...
   if ... then
      raise Baz;
   end if;
   ...
   Result := ...;
   ...
   return Result;
end Foo;

I understand the motivation to declare Result uninitialized (because we
could leave Foo via an exception), but I don't like this.

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



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

* Re: Operation can be dispatching in only one type
  2009-12-01 16:18                                                       ` Dmitry A. Kazakov
@ 2009-12-01 17:52                                                         ` Georg Bauhaus
  2009-12-01 18:47                                                           ` Dmitry A. Kazakov
  0 siblings, 1 reply; 132+ messages in thread
From: Georg Bauhaus @ 2009-12-01 17:52 UTC (permalink / raw)


Dmitry A. Kazakov schrieb:
> On Tue, 01 Dec 2009 16:02:21 +0100, Georg Bauhaus wrote:
> 
>> Dmitry A. Kazakov schrieb:
>>> On Tue, 01 Dec 2009 13:13:29 +0100, Georg Bauhaus wrote:
>>>
>>>> Then we could rely on the language: compilers will detect
>>>> uninitialized variables provided these do not have a pragma/keyword/...
>>>> to say that uninitialized is what the programmer wants.
>>>> Some fancy means to tell the compiler that this variable
>>>> does indeed have a good first value like pragma Import.
>>>>
>>>>    X : [constant] Car; -- default init,
>>> The error is here!
>>>>                        -- undefined,
>>>>                        -- junk bits. Doesn't matter
>>>>    --  *no* pragma Import (Ada, X);
>>>>
>>>> begin
>>>>
>>>>    Spare := X.Tire (5); -- would become illegal,
>>> Not here!
>> Why?
> 
> Because X is illegal right after begin:
> 
> IF accessing X is illegal THEN the corresponding operation does not belong
> to the type of X THEN the type of X is not Car. q.e.d.

But the implications of this proof are purely formal,
and not relevant before X is used.
There is no way to perform an operation involving X in
its own declaration.

The difference in views would be that your laws say Don't
create objects that could be used illegally if there
were uses that can't be there, though, but for formal reasons.
Whereas Java's ruling says (at compile time) Your program
cannot be accepted because this object cannot be in
a legal state here. The variable may not have been assigned
a value.


> (Provided, we are talking about a typed language)

I think there is more in what you say than what is covered
by the words "typed language"?

>>> -------------------------
>>> Anyway, you cannot do that because:
>>>
>>>    if HALT (P) then
>>>      X := Z;
>>>    end if;
>>>    Y := X;  -- Is this legal?
>> (HALT is a run-time issue that has no impact here.)
> 
> If you cannot decide if X is "initialized",

But I can decide whether (and when!) X is "initialized"!
The compiler does not need to run HALT in order
to see that X may not have been initialized when the condition
is not true.  The program is not accepted because it may lack
an assignment to X before Y := X for much simpler reasons.

In fact, SPARK marks it as error.  I made a simple example,
a procedure that does or does not assign depending
on an unknown Boolean Condition parameter:


   1  package body Asgn is
   2
   3     procedure Exmpl (Condition: Boolean; Result : out Integer) is
   4        X : Integer;
   5     begin
   6        if Condition then
   7           X := 42;
   8        end if;
   9
  10        Result := X / 2;
                      ^1
??? (  1)  Flow Error        :501: Expression contains reference(s) to
variable X,
           which may have an undefined value.

  11     end Exmpl;

??? (  2)  Flow Error        :602: The undefined initial value of X may be
used in
           the derivation of Result.

  12
  13  end Asgn;

What the new rule would do is merge the two messages into one
message about X that may not have a value yet: An "undefined
initial value" MUST not be used like it is used on line 10.
The (different) Ada language rule will forbid.


>> While this snippet would not be legal as is (on purpose!),
>> Ada's case coverage rules can make the programmer write a
>> legal program easily: write an else branch!
> 
> And this one:
> 
> procedure Foo (X : in out Car);
>    ...
> begin
>    Foo (X);
>    Y := X; -- Is this legal?

Yes, this is legal, because Foo is called with X having been
assigned a value.  It cannot be otherwise, the recursion has to
start somewhere.  It can only start with an actual parameter
that has a value (again, the compiler can check this).


> And if Foo were declared as
> 
> procedure Foo (X : out Car);


We'd have roughly the same as this:

    X : Car;
begin
    X := Foo_as_function;  -- now X can be used

I see no operational problem.  Is there one?


>>>> Does the phrase "first value" make sense?
>>> An object shall not have invalid values. All values are valid if the
>>> language is typed. Enforcing user-defined construction including
>>> prohibition of certain kinds of construction (e.g. per default constructor)
>>> is a different story. 
>> If you feed this to a Java compiler you will see how it is done.
>> The Java compiler will not accept a reference to a variable's
>> component when the variable may not have been initialized.
> 
> I consider this model wrong. It is better not to introduce inappropriate
> values rather than trying to catch them later.

The Java rule works at compile time. No value is introduced at any
time during compilation.  Nothing to catch.  A reference to a
variable in source text is permitted if and only if the compiler can show,
by following simple compile time rules, that a value has been assigned
to the variable or constant prior to referencing.  It need not evaluate
calls (i.e. run the program) to arrive at a decision.

> Java does not have
> constrained types, so I can understand why they go this way.

Ehm, I don't see the connection here.  Which one is it?

When I declare

   X : Some_Type(Some_Constraint);
begin
   -- X may need further "initilization", and assigments, since
   -- Some_Type is an "open minded" type of a varying nature,
   -- not a fixed value. Its objects accumulate values.

> I also think that forward uninitialized declarations represent bad
> style, e.g.:
> 
> function Foo (...) return Bar is
>    Result : Bar;
> begin
>    ...
>    if ... then
>       raise Baz;
>    end if;
>    ...
>    Result := ...;
>    ...
>    return Result;
> end Foo;
> 
> I understand the motivation to declare Result uninitialized (because we
> could leave Foo via an exception), but I don't like this.
> 

But assigning the first value when declaring X won't help
when the initialization can raise exceptions.  How could this change?

When the body of Foo gradually operates on Result to produce
its final state (in a safe way because no reference can be
made to Result or its parts without prior assignments), why
should I pretend that any valid initial value for Result,
provided by an initialization expression, is
better than its default value?  (Assuming that I cannot
refer to "invalid" components of objects because the compiler
will simply reject a program that might try.)




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

* Re: Operation can be dispatching in only one type
  2009-12-01 17:52                                                         ` Georg Bauhaus
@ 2009-12-01 18:47                                                           ` Dmitry A. Kazakov
  2009-12-01 21:53                                                             ` John B. Matthews
  2009-12-02  1:13                                                             ` Georg Bauhaus
  0 siblings, 2 replies; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-12-01 18:47 UTC (permalink / raw)


On Tue, 01 Dec 2009 18:52:15 +0100, Georg Bauhaus wrote:

> Dmitry A. Kazakov schrieb:
>> On Tue, 01 Dec 2009 16:02:21 +0100, Georg Bauhaus wrote:
>> 
>>> Dmitry A. Kazakov schrieb:
>>>> On Tue, 01 Dec 2009 13:13:29 +0100, Georg Bauhaus wrote:
>>>>
>>>>> Then we could rely on the language: compilers will detect
>>>>> uninitialized variables provided these do not have a pragma/keyword/...
>>>>> to say that uninitialized is what the programmer wants.
>>>>> Some fancy means to tell the compiler that this variable
>>>>> does indeed have a good first value like pragma Import.
>>>>>
>>>>>    X : [constant] Car; -- default init,
>>>> The error is here!
>>>>>                        -- undefined,
>>>>>                        -- junk bits. Doesn't matter
>>>>>    --  *no* pragma Import (Ada, X);
>>>>>
>>>>> begin
>>>>>
>>>>>    Spare := X.Tire (5); -- would become illegal,
>>>> Not here!
>>> Why?
>> 
>> Because X is illegal right after begin:
>> 
>> IF accessing X is illegal THEN the corresponding operation does not belong
>> to the type of X THEN the type of X is not Car. q.e.d.
> 
> But the implications of this proof are purely formal,
> and not relevant before X is used.

They are relevant to the declaration of X. It cannot be declared of Car, if
it is not.

> There is no way to perform an operation involving X in
> its own declaration.

But it can be used right after the declaration.

> The difference in views would be that your laws say Don't
> create objects that could be used illegally if there
> were uses that can't be there, though, but for formal reasons.
> Whereas Java's ruling says (at compile time) Your program
> cannot be accepted because this object cannot be in
> a legal state here.

No, Java says, that it self failed to prove that this object is in a state
the programmer might want. This is an absolutely informal statement,
because Java cannot have any idea about what the programmer actually
wanted. The only basis for reasoning might be the object type. But that
tells nothing. So Java speculates that the default constructor is somewhat
worse than copy constructor. Why does it so? Did programmer told this the
compiler? No he didn't. Yes, it might be the case, but then why not to
allow the programmer to say exactly this: do not allow default constructors
for this type? I would even make this a default. E.g. if the programmer
does not explicitly allow default constructors they are forbidden. So

   X : T;  -- Is always illegal unless I do some actions

>> (Provided, we are talking about a typed language)
> 
> I think there is more in what you say than what is covered
> by the words "typed language"?

properly typed language! (:-))
 
>> And this one:
>> 
>> procedure Foo (X : in out Car);
>>    ...
>> begin
>>    Foo (X);
>>    Y := X; -- Is this legal?
> 
> Yes, this is legal, because Foo is called with X having been
> assigned a value.

But Foo might read X in its body before updating it. It can leave it
untouched etc.

>> And if Foo were declared as
>> 
>> procedure Foo (X : out Car);
> 
> We'd have roughly the same as this:
> 
>     X : Car;
> begin
>     X := Foo_as_function;  -- now X can be used
> 
> I see no operational problem.  Is there one?

There is one, Foo might leave X unchanged, unless you introduce further
special rules for out parameters. It will be interesting:

begin
   begin
      Foo (X);
   exception
      when Baz =>
           null;
   end;
   Y := X; -- Is this legal?

Ada does not specify what happens with out parameters updated before an
exception gets raised in the body of Foo:

procedure Foo (X : out Car) is
begin
   if HALT (p) then
      raise Baz;  -- Is this legal?
   else
      X := Merzedes;
   end if;
end Foo;

>>>>> Does the phrase "first value" make sense?
>>>> An object shall not have invalid values. All values are valid if the
>>>> language is typed. Enforcing user-defined construction including
>>>> prohibition of certain kinds of construction (e.g. per default constructor)
>>>> is a different story. 
>>> If you feed this to a Java compiler you will see how it is done.
>>> The Java compiler will not accept a reference to a variable's
>>> component when the variable may not have been initialized.
>> 
>> I consider this model wrong. It is better not to introduce inappropriate
>> values rather than trying to catch them later.
> 
> The Java rule works at compile time. No value is introduced at any
> time during compilation.  Nothing to catch.

Of course there is something to catch. The compiler has to do this. So the
question is at which cost, how many false positives and negatives it will
find? How scalable is this feature for more elaborated types?

>> Java does not have
>> constrained types, so I can understand why they go this way.
> 
> Ehm, I don't see the connection here.  Which one is it?
> 
> When I declare
> 
>    X : Some_Type(Some_Constraint);
> begin
>    -- X may need further "initilization", and assigments, since
>    -- Some_Type is an "open minded" type of a varying nature,
>    -- not a fixed value. Its objects accumulate values.

I mean constraints in a wider sense. For example:

   Some_Time (<>)

e.g. a subtype that would require explicit initialization.

>> I also think that forward uninitialized declarations represent bad
>> style, e.g.:
>> 
>> function Foo (...) return Bar is
>>    Result : Bar;
>> begin
>>    ...
>>    if ... then
>>       raise Baz;
>>    end if;
>>    ...
>>    Result := ...;
>>    ...
>>    return Result;
>> end Foo;
>> 
>> I understand the motivation to declare Result uninitialized (because we
>> could leave Foo via an exception), but I don't like this.
> 
> But assigning the first value when declaring X won't help
> when the initialization can raise exceptions.  How could this change?

I don't follow you. My example illustrated a situation where an
uninitialized value might be an advantage, because one possible outcome of
Foo is exception propagation, in which case leaving Result raw could save
some vital nanoseconds of execution time. I don't buy this.

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



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

* Re: Operation can be dispatching in only one type
  2009-12-01 18:47                                                           ` Dmitry A. Kazakov
@ 2009-12-01 21:53                                                             ` John B. Matthews
  2009-12-02  0:32                                                               ` Georg Bauhaus
  2009-12-02  1:13                                                             ` Georg Bauhaus
  1 sibling, 1 reply; 132+ messages in thread
From: John B. Matthews @ 2009-12-01 21:53 UTC (permalink / raw)


In article <wof0ewwkyzy0$.13398rnn8cmje$.dlg@40tude.net>,
 "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote:

> On Tue, 01 Dec 2009 18:52:15 +0100, Georg Bauhaus wrote:
> 
> > Dmitry A. Kazakov schrieb:
> >> On Tue, 01 Dec 2009 16:02:21 +0100, Georg Bauhaus wrote:
[...]
> >>> If you feed this to a Java compiler you will see how it is done. 
> >>> The Java compiler will not accept a reference to a variable's 
> >>> component when the variable may not have been initialized.
> >> 
> >> I consider this model wrong. It is better not to introduce 
> >> inappropriate values rather than trying to catch them later.
> > 
> > The Java rule works at compile time. No value is introduced at any 
> > time during compilation.  Nothing to catch.
> 
> Of course there is something to catch. The compiler has to do this. 
> So the question is at which cost, how many false positives and 
> negatives it will find? How scalable is this feature for more 
> elaborated types?

If I may amplify on this, the Java compiler rejects the assignment to 
its_color because it's a local variable, which must have an explicit 
value before use [1]. Once Tire's constructor completes, the value of 
spare.rim_color has the default value null [1]. The compiler need only 
check that its_color has been assigned in the current scope [2]. In 
Georg Bauhaus' example, the constructor is invoked in a nested scope.

In Ada, I get a warning that '"Spare" is read but never assigned.' 

type Tire_Color is (Black, White);
type Tire is record
   Rim_Color : Tire_Color;
end record;
Spare : Tire;

If I throw in "for Tire_Color use (Black => 1, White => 2)," the 
implicit initial value [3] of Rim_Color is not valid for Tire_Color. 
It's "a bounded error to evaluate the value of such an object [4]," and 
I get CONSTRAINT_ERROR at run-time.

The Java compiler doesn't warn that spare.rim_color is null by default; 
the Ada compiler doesn't warn that Spare.Rim_Color is invalid by 
default. In either language, I have to either accept the default initial 
values or specify them. I sense I'm missing something.

[1]<http://java.sun.com/docs/books/jls/third_edition/html/typesValues.htm
l#4.12.5>
[2]<http://java.sun.com/docs/books/jls/third_edition/html/defAssign.html#
25979>
[2]<http://www.adaic.com/standards/05rm/html/RM-3-3-1.html>
[3]<http://www.adaic.com/standards/05rm/html/RM-13-9-1.html>
-- 
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>



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

* Re: Operation can be dispatching in only one type
  2009-12-01 12:13                                                 ` Georg Bauhaus
  2009-12-01 12:23                                                   ` Georg Bauhaus
  2009-12-01 13:48                                                   ` Dmitry A. Kazakov
@ 2009-12-01 23:51                                                   ` Randy Brukardt
  2 siblings, 0 replies; 132+ messages in thread
From: Randy Brukardt @ 2009-12-01 23:51 UTC (permalink / raw)


"Georg Bauhaus" <rm.dash-bauhaus@futureapps.de> wrote in message 
news:4b150869$0$6732$9b4e6d93@newsspool2.arcor-online.net...
...
> If so, and presuming the programming language Ada is very much,
> and explicitly, about storing and manipulating bits in registers,
> memory words, ... of digital computers in a strongly typed fashion:
> In this case I would know the use of being carried away by functional,
> uhm, phantasm, pardon the expression.  Rather, why not have Ada turn
> warnings about "uninitialized" variables into a rule like Java's?

Two obvious reasons:
(1) Compatibility. Adding such a rule to Ada would ensure that 98% of 
existing Ada code would not compile. This is too fundamental a capability to 
take such an incompatibility.
(2) Ada has a design goal of being implementable in a single pass compiler. 
A correllary of that goal is that legality rules cannot require flow 
analysis. Which means that any rule would have to be essentially the same as 
the one Dmitry is proposing: initialization is required in most cases; 
delayed initialization is OK only if it is unconditional. One has to think 
that using a conditional expression (as in Ada 2012 and in GNAT extensions) 
to initialize would be better than constructing some complex rules to allow 
initialization such as the one Bob suggested initially.

One can certainly make the argument that the original design of Ada should 
have taken this problem more seriously (indeed, I think it is one of the 
worst mistakes of the original design team), but that doesn't make it any 
more likely that the language will be changed here.

Probably the best that we could do today would be to add an Annex H 
restriction against default initialized objects that could have invalid 
values. (You'd want to allow well-defined default initialization as occurs 
for access types, it doesn't present a problem.) Then a particular project 
could require the use of that pragma and thus program in a safer Ada subset. 
(We could also help by making it easier to define default initial values for 
types other record types.)

                                               Randy.






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

* Re: Operation can be dispatching in only one type
  2009-12-01 21:53                                                             ` John B. Matthews
@ 2009-12-02  0:32                                                               ` Georg Bauhaus
  2009-12-02 11:18                                                                 ` John B. Matthews
  0 siblings, 1 reply; 132+ messages in thread
From: Georg Bauhaus @ 2009-12-02  0:32 UTC (permalink / raw)


On 12/1/09 10:53 PM, John B. Matthews wrote:

> If I may amplify on this, the Java compiler rejects the assignment to
> its_color because it's a local variable, which must have an explicit
> value before use [1]. Once Tire's constructor completes, the value of
> spare.rim_color has the default value null [1]. The compiler need only
> check that its_color has been assigned in the current scope [2]. In
> Georg Bauhaus' example, the constructor is invoked in a nested scope.
>
> In Ada, I get a warning that '"Spare" is read but never assigned.'
>
> type Tire_Color is (Black, White);
> type Tire is record
>     Rim_Color : Tire_Color;
> end record;
> Spare : Tire;
>
> If I throw in "for Tire_Color use (Black =>  1, White =>  2)," the
> implicit initial value [3] of Rim_Color is not valid for Tire_Color.
> It's "a bounded error to evaluate the value of such an object [4]," and
> I get CONSTRAINT_ERROR at run-time.
>
> The Java compiler doesn't warn that spare.rim_color is null by default;
> the Ada compiler doesn't warn that Spare.Rim_Color is invalid by
> default. In either language, I have to either accept the default initial
> values or specify them. I sense I'm missing something.

The Java rule I had been thinking of starts from less emphasis
on what the default initial (Ada) value of a (local) variable
might be, given current Ada rules.  Rather, in the sequence
of statements below the compiler would just not accept the reference
to the .Rim_Color component of Spare.  The meaning of the
declaration Spare : Tire needs to be understood as slightly changed,
to exclude (or ignore) default initialization.

    Spare : Tire;
begin
    -- Here, whatever Spare is, or whichever side effects its
    -- declaration may have, it is not used between
    -- its declaration and the line following the if statement.
    -- Therefore, we are free to think of it as something
    -- or as nothing, or as something to become a Tire when
    -- necessary.  A virtual object, perhaps. (Otherwise, use
    -- syntax to indicate that  there is something important
    -- going on in default init; or, for compatibility, when
    -- nothing important is going on.)

    if Some_Condition then
       Spare := Make_a_Tire;
    end if;
    Its_Color := Spare.Rim_Color;  -- illegal


A simple rule would now be a copy of the Java rule which is
quoted below.  Just assume that Spare has no value.
Just like the last line is not accepted by SPARK or
by Java (the corresponding Java source line).  The warning
which some Ada compilers will issue (that Spare may not have
been assigned a value) is then turned into an error.
As might be expected in Ada, some syntax might be in
order to say that default initialization does
provide an initial value that warrants the safe use of the
variable after the if statement (or is needed for its
side effects, but this is another story, I guess).

Another case is when a declared variable is used in
a declaration of another variable following it,

    Spare   : Tire;
    Another : Tire := Spare;  -- might become illegal
begin
    ...

Illegal unless it is specified that Spare does have
a valid Tire value.  Or, oddly, that Another "inherits" the
unknown state of Spare WRT being initialized or not.

This is the Java rule I had in mind. I found it thanks to the
link you have supplied:
"A Java compiler must carry out a specific conservative flow
  analysis to make sure that, for every access of a local
  variable or blank final field f, f is definitely assigned
  before the access; otherwise a compile-time error must occur."


> [2]<http://java.sun.com/docs/books/jls/third_edition/html/defAssign.html#
> 25979>



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

* Re: Operation can be dispatching in only one type
  2009-12-01 18:47                                                           ` Dmitry A. Kazakov
  2009-12-01 21:53                                                             ` John B. Matthews
@ 2009-12-02  1:13                                                             ` Georg Bauhaus
  2009-12-02  9:07                                                               ` Dmitry A. Kazakov
  1 sibling, 1 reply; 132+ messages in thread
From: Georg Bauhaus @ 2009-12-02  1:13 UTC (permalink / raw)


On 12/1/09 7:47 PM, Dmitry A. Kazakov wrote:


> It cannot be declared of Car, if it is not.

Which brings us (or me, at least) to the problem of whether or
not the meaning of an Ada program (or a sequential subprogram)
will change if object X really  "is" after "begin" or whether
its physical existence is allowed start just before actual
use. :-)  X might show its existence through side effects
of its default initialization.
Rather implicit if the effect is important.


>> There is no way to perform an operation involving X in
>> its own declaration.
>
> But it can be used right after the declaration.

Sure, but it isn't used, and the compiler will make sure
it isn't unless it has a value.

> why not to
> allow the programmer to say exactly this: do not allow default constructors
> for this type? I would even make this a default. E.g. if the programmer
> does not explicitly allow default constructors they are forbidden. So
>
>     X : T;  -- Is always illegal unless I do some actions

Or maybe this could mean that if there is no explict specification
of actions associated with the declaration, X must be
considered uninitialized in the following text.
Some syntax might be nice to have.


> Ada does not specify what happens with out parameters updated before an
> exception gets raised in the body of Foo:
>
> procedure Foo (X : out Car) is
> begin
>     if HALT (p) then
>        raise Baz;  -- Is this legal?
>     else
>        X := Merzedes;
>     end if;
> end Foo;

If we were to integrate exceptions into normal control
flow like Java does?  Here is what Java does when the
constructor may raise an exception (taking the role of Foo
above):

         if (some_condition) {
	    try {
		spare = new Dummy.Tire();
	    } catch (Exception e) {
		;
	    }
	    // this line not accepted by a Java compiler:
	    its_color = spare.rim_color;  //  <-----
         }
         // this line not accepted by a Java compiler:
         its_color = spare.rim_color;  //  <-----


> Of course there is something to catch. The compiler has to do this. So the
> question is at which cost, how many false positives and negatives it will
> find? How scalable is this feature for more elaborated types?

 From the Java point of view, there are no false positives
or negatives.  The rule is pretty clear, I think.
Assuming that Ada programmers will be able to say
"is initialized" for just a variable declaration, there
should not be any false positives or negatives.
There could be more reliance on the programmer, though,
not sure.

>  My example illustrated a situation where an
> uninitialized value might be an advantage, because one possible outcome of
> Foo is exception propagation, in which case leaving Result raw could save
> some vital nanoseconds of execution time. I don't buy this.

Whether the out mode variable had been initialized in the
body or not, the exceptional situation might have destroyed
the value of the out mode parameter.  A variable would not
be considered initialized, I'd think, in an exception handler,
unless the programmer says so (or assigns a value).



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

* Re: Operation can be dispatching in only one type
  2009-12-02  1:13                                                             ` Georg Bauhaus
@ 2009-12-02  9:07                                                               ` Dmitry A. Kazakov
  2009-12-02 12:35                                                                 ` John B. Matthews
  2009-12-03  5:29                                                                 ` Randy Brukardt
  0 siblings, 2 replies; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-12-02  9:07 UTC (permalink / raw)


On Wed, 02 Dec 2009 02:13:14 +0100, Georg Bauhaus wrote:

> On 12/1/09 7:47 PM, Dmitry A. Kazakov wrote:
> 
>> It cannot be declared of Car, if it is not.
> 
> Which brings us (or me, at least) to the problem of whether or
> not the meaning of an Ada program (or a sequential subprogram)
> will change if object X really  "is" after "begin" or whether
> its physical existence is allowed start just before actual
> use. :-)  X might show its existence through side effects
> of its default initialization.
> Rather implicit if the effect is important.

Ada rules are rather complex, the object exists right after its
declaration, but its existence is somewhat sleepy, a larva, not yet the
butterfly:

Consider the following:

   task type A is
      entry Hey;
   end A;
   type T (Greeting : access A) is
      new Ada.Finalization.Limited_Controlled with null record;
   overriding procedure Initialize (X : in out T);

   task body A is
   begin
      accept Hey;
   end A;
   
   procedure Initialize (X : in out T) is
   begin
      X.Greeting.Hey;
   end Initialize;

With the above:

   declare
      X : aliased A;
      Y : T (X'Access);  -- This is a deadlock!
   begin

The object X (a task) is not completely initialized when Y's Initialize is
called. This is one of nasty problems with tasks as objects.

And in general I think that many feel uncomfortable with Ada declarations
being executable. I have no clear idea how to approach this problem,
though.

>>> There is no way to perform an operation involving X in
>>> its own declaration.
>>
>> But it can be used right after the declaration.
> 
> Sure, but it isn't used, and the compiler will make sure
> it isn't unless it has a value.

That erodes the concept of scope, which idea is that the object is usable
anywhere within its scope.

>> Ada does not specify what happens with out parameters updated before an
>> exception gets raised in the body of Foo:
>>
>> procedure Foo (X : out Car) is
>> begin
>>     if HALT (p) then
>>        raise Baz;  -- Is this legal?
>>     else
>>        X := Merzedes;
>>     end if;
>> end Foo;
> 
> If we were to integrate exceptions into normal control
> flow like Java does?

Contracted exceptions is a way to move the check down the code.

Consider an invalid initial value, which is legal. Its validness is rather
determined by outcome of some operations, e.g. reading it causes
Constraint_Error. Then, with exception contracts, if you declared the
program as not raising Constraint_Error, then the program with an invalid
initial value could become illegal if Constraint_Error is not caught:

declare
   raise no Constraint_Error; -- Imaginary syntax
   X : Car;
begin
   Print (X.Tire);
end; -- Illegal, this block might rise Constraint_Error

declare
   raise no Constraint_Error;
   X : Valid_Car; -- Illegal require initialization by a valid value
begin
   Print (X.Tire);
end; -- Legal now, but fails at the declaration point

declare
   raise no Constraint_Error;
   X : Valid_Car := My_Car; -- A valid value
begin
   Print (X.Tire);
end; -- No Constraint_Error

>> Of course there is something to catch. The compiler has to do this. So the
>> question is at which cost, how many false positives and negatives it will
>> find? How scalable is this feature for more elaborated types?
> 
>  From the Java point of view, there are no false positives
> or negatives.

Of course there are, because it is a halting problem. So you need some
optimistic or pessimistic estimation of:

if False then
   Print (X.Tire); -- Is this illegal? If yes, that is a false positive
end if;

[Also see Randy's points]

>>  My example illustrated a situation where an
>> uninitialized value might be an advantage, because one possible outcome of
>> Foo is exception propagation, in which case leaving Result raw could save
>> some vital nanoseconds of execution time. I don't buy this.
> 
> Whether the out mode variable had been initialized in the
> body or not, the exceptional situation might have destroyed
> the value of the out mode parameter.  A variable would not
> be considered initialized, I'd think, in an exception handler,
> unless the programmer says so (or assigns a value).

No the problem is whether to treat a call to the body as legal. The problem
is that you could not rely on its contract (out Car), in order to be able
to decide whether this call would "initialize" the object.

BTW, you consider ":=" as an initialization, but why? Where is a guaranty
that it initializes the object by a "valid" value? I feel that very concept
is somewhat inconsistent with ADT.

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



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

* Re: Operation can be dispatching in only one type
  2009-12-02  0:32                                                               ` Georg Bauhaus
@ 2009-12-02 11:18                                                                 ` John B. Matthews
  2009-12-02 14:29                                                                   ` Jean-Pierre Rosen
  0 siblings, 1 reply; 132+ messages in thread
From: John B. Matthews @ 2009-12-02 11:18 UTC (permalink / raw)


In article <4b15b59b$0$7632$9b4e6d93@newsspool1.arcor-online.net>,
 Georg Bauhaus <rm-host.bauhaus@maps.futureapps.de> wrote:

[...]
> The Java rule I had been thinking of starts from less emphasis on 
> what the default initial (Ada) value of a (local) variable might be, 
> given current Ada rules.  Rather, in the sequence of statements below 
> the compiler would just not accept the reference to the .Rim_Color 
> component of Spare.  The meaning of the declaration Spare : Tire 
> needs to be understood as slightly changed, to exclude (or ignore) 
> default initialization.
> 
>     Spare : Tire;
> begin
>     -- Here, whatever Spare is, or whichever side effects its
>     -- declaration may have, it is not used between
>     -- its declaration and the line following the if statement.
>     -- Therefore, we are free to think of it as something
>     -- or as nothing, or as something to become a Tire when
>     -- necessary.  A virtual object, perhaps. (Otherwise, use
>     -- syntax to indicate that  there is something important
>     -- going on in default init; or, for compatibility, when
>     -- nothing important is going on.)
> 
>     if Some_Condition then
>        Spare := Make_a_Tire;
>     end if;
>     Its_Color := Spare.Rim_Color;  -- illegal
> 
> 
> A simple rule would now be a copy of the Java rule which is
> quoted below.  Just assume that Spare has no value.
> Just like the last line is not accepted by SPARK or
> by Java (the corresponding Java source line).  The warning
> which some Ada compilers will issue (that Spare may not have
> been assigned a value) is then turned into an error.

Ah, I see. Nothing in the present Ada specification _requires_
such a warning.

> As might be expected in Ada, some syntax might be in
> order to say that default initialization does
> provide an initial value that warrants the safe use of the
> variable after the if statement (or is needed for its
> side effects, but this is another story, I guess).
> 
> Another case is when a declared variable is used in
> a declaration of another variable following it,
> 
>     Spare   : Tire;
>     Another : Tire := Spare;  -- might become illegal
> begin
>     ...
> 
> Illegal unless it is specified that Spare does have
> a valid Tire value.  Or, oddly, that Another "inherits" the
> unknown state of Spare WRT being initialized or not.
> 
> This is the Java rule I had in mind. I found it thanks to the
> link you have supplied:
> "A Java compiler must carry out a specific conservative flow
>   analysis to make sure that, for every access of a local
>   variable or blank final field f, f is definitely assigned
>   before the access; otherwise a compile-time error must occur."

I can see the appeal of adding such an analysis to Ada.

<http://java.sun.com/docs/books/jls/third_edition/html/defAssign.html>

-- 
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>



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

* Re: Operation can be dispatching in only one type
  2009-12-02  9:07                                                               ` Dmitry A. Kazakov
@ 2009-12-02 12:35                                                                 ` John B. Matthews
  2009-12-02 13:35                                                                   ` Dmitry A. Kazakov
  2009-12-03  5:23                                                                   ` Randy Brukardt
  2009-12-03  5:29                                                                 ` Randy Brukardt
  1 sibling, 2 replies; 132+ messages in thread
From: John B. Matthews @ 2009-12-02 12:35 UTC (permalink / raw)


In article <1jcbtmi5rztyp$.norvlhez9i9$.dlg@40tude.net>,
 "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote:

Georg Bauhaus wrote:

> >  From the Java point of view, there are no false positives
> > or negatives.
> 
> Of course there are, because it is a halting problem. So you need 
> some optimistic or pessimistic estimation of:
> 
> if False then
>    Print (X.Tire); -- Is this illegal? If yes, that is a false positive
> end if;

It would be indeterminate but for doing "a specific conservative flow 
analysis." In the specific cases of boolean constant expressions and if 
statements,

  if (true) { spare = new Tire(); } // spare assigned
  if (1 == 1) { spare = new Tire(); } // spare assigned
  if (false) { spare = new Tire(); } // spare unassigned
  if (1 == 2) { spare = new Tire(); } // spare unassigned
  if (always()) { spare = new Tire(); } // spare unassigned

  static boolean always() { return true; }

In particular, spare remains unassigned even though the function 
always() is always true.

In Ada, a certain compiler may warn 'variable "N" is assigned but never 
read' for the following:

N : Integer;
if False then N := 1; end if;

I'm not especially advocating applying the Java rules to Ada, but I like 
the warning.

<http://java.sun.com/docs/books/jls/third_edition/html/defAssign.html>

-- 
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>



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

* Re: Operation can be dispatching in only one type
  2009-12-02 12:35                                                                 ` John B. Matthews
@ 2009-12-02 13:35                                                                   ` Dmitry A. Kazakov
  2009-12-03  5:23                                                                   ` Randy Brukardt
  1 sibling, 0 replies; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-12-02 13:35 UTC (permalink / raw)


On Wed, 02 Dec 2009 07:35:39 -0500, John B. Matthews wrote:

> In article <1jcbtmi5rztyp$.norvlhez9i9$.dlg@40tude.net>,
>  "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote:
> 
> Georg Bauhaus wrote:
> 
>>>  From the Java point of view, there are no false positives
>>> or negatives.
>> 
>> Of course there are, because it is a halting problem. So you need 
>> some optimistic or pessimistic estimation of:
>> 
>> if False then
>>    Print (X.Tire); -- Is this illegal? If yes, that is a false positive
>> end if;
> 
> It would be indeterminate but for doing "a specific conservative flow 
> analysis." In the specific cases of boolean constant expressions and if 
> statements,
> 
>   if (true) { spare = new Tire(); } // spare assigned
>   if (1 == 1) { spare = new Tire(); } // spare assigned
>   if (false) { spare = new Tire(); } // spare unassigned
>   if (1 == 2) { spare = new Tire(); } // spare unassigned
>   if (always()) { spare = new Tire(); } // spare unassigned
> 
>   static boolean always() { return true; }
> 
> In particular, spare remains unassigned even though the function 
> always() is always true.
> 
> In Ada, a certain compiler may warn 'variable "N" is assigned but never 
> read' for the following:
> 
> N : Integer;
> if False then N := 1; end if;
> 
> I'm not especially advocating applying the Java rules to Ada, but I like 
> the warning.

Yes, warning is nice.

The problem is with making it an error as Georg suggests (and Java does).
An error (and its complement "no error") require much more careful
definition. "Initialized" is too shaky for that, but for all I find
"unassigned" inconsistent with strong typing. A typed object is always
assigned because it cannot have any values other than of its type. If we
wanted an object to have *certain* values, e.g. "any value different from
the default one", then a naive analysis a-la Java is too little to me. I
would prefer full blown pre-, postconditions and invariants for such a
case.

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



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

* Re: Operation can be dispatching in only one type
  2009-12-02 11:18                                                                 ` John B. Matthews
@ 2009-12-02 14:29                                                                   ` Jean-Pierre Rosen
  2009-12-02 15:35                                                                     ` Georg Bauhaus
  0 siblings, 1 reply; 132+ messages in thread
From: Jean-Pierre Rosen @ 2009-12-02 14:29 UTC (permalink / raw)


John B. Matthews a écrit :
>> This is the Java rule I had in mind. I found it thanks to the
>> link you have supplied:
>> "A Java compiler must carry out a specific conservative flow
>>   analysis to make sure that, for every access of a local
>>   variable or blank final field f, f is definitely assigned
>>   before the access; otherwise a compile-time error must occur."
> 
> I can see the appeal of adding such an analysis to Ada.
> 
> <http://java.sun.com/docs/books/jls/third_edition/html/defAssign.html>
> 
Unless it has changed recently (it is sometimes since I updated my Java
education), the Java solution is not bullet-proof: you can still access
variables before initialization from constructors. Note that if the Java
people were confident in their rule, there would be no need to require
that every variable be initialized to zero!

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



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

* Re: Operation can be dispatching in only one type
  2009-12-02 14:29                                                                   ` Jean-Pierre Rosen
@ 2009-12-02 15:35                                                                     ` Georg Bauhaus
  0 siblings, 0 replies; 132+ messages in thread
From: Georg Bauhaus @ 2009-12-02 15:35 UTC (permalink / raw)


Jean-Pierre Rosen schrieb:
> Note that if the Java
> people were confident in their rule, there would be no need to require
> that every variable be initialized to zero!


A local variable, unlike the others, is not initialized
to zero.  But the "assigned before use" rule applies to
local variables.



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

* Re: Operation can be dispatching in only one type
  2009-12-02 12:35                                                                 ` John B. Matthews
  2009-12-02 13:35                                                                   ` Dmitry A. Kazakov
@ 2009-12-03  5:23                                                                   ` Randy Brukardt
  2009-12-03 20:21                                                                     ` John B. Matthews
  1 sibling, 1 reply; 132+ messages in thread
From: Randy Brukardt @ 2009-12-03  5:23 UTC (permalink / raw)


"John B. Matthews" <nospam@nospam.invalid> wrote in message 
news:nospam-9C9974.07353802122009@news.aioe.org...
...
> I'm not especially advocating applying the Java rules to Ada, but I like
> the warning.

Warnings have no semantic impact in Ada. There are a few places in the 
standard that suggest that warnings be generated, but there is no ideas 
whatsoever what that might mean. It is purely a quality-of-implementation 
issue -- and that is between you and your Ada vendor.

                             Randy.





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

* Re: Operation can be dispatching in only one type
  2009-12-02  9:07                                                               ` Dmitry A. Kazakov
  2009-12-02 12:35                                                                 ` John B. Matthews
@ 2009-12-03  5:29                                                                 ` Randy Brukardt
  2009-12-03 11:24                                                                   ` Georg Bauhaus
  1 sibling, 1 reply; 132+ messages in thread
From: Randy Brukardt @ 2009-12-03  5:29 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:1jcbtmi5rztyp$.norvlhez9i9$.dlg@40tude.net...
...
> No the problem is whether to treat a call to the body as legal. The 
> problem
> is that you could not rely on its contract (out Car), in order to be able
> to decide whether this call would "initialize" the object.
>
> BTW, you consider ":=" as an initialization, but why? Where is a guaranty
> that it initializes the object by a "valid" value? I feel that very 
> concept
> is somewhat inconsistent with ADT.

To expand on this point, there are a number of places in Ada where objects 
can become "deinitialized". (Compilation strategies can prevent some of 
these, but at a cost of more checks with the associated loss of performance. 
For instance, Janus/Ada prevents Unchecked_Conversion from deinitializing 
scalar objects -- but to do so requires that range/validity checks be done 
on the results of some conversions -- hardly "unchecked").

Other places (such as the result of Stream'Read and the results of 
Sequential_IO.Read for composite types, and especially abort) can't be 
eliminated in any reasonable way.

If you really care about this topic, I suggest you read and reread 13.9.1 
until you understand it. (Then join the ARG and explain it to the rest of 
us. ;-)! This is not at all a simple topic, and the sort of simple rule used 
by Java does little other than give a false sense of security (and a lot of 
annoying errors in code that has no problems).

                               Randy.





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

* Re: Operation can be dispatching in only one type
  2009-12-03  5:29                                                                 ` Randy Brukardt
@ 2009-12-03 11:24                                                                   ` Georg Bauhaus
  2009-12-03 23:08                                                                     ` Randy Brukardt
  0 siblings, 1 reply; 132+ messages in thread
From: Georg Bauhaus @ 2009-12-03 11:24 UTC (permalink / raw)


Randy Brukardt schrieb:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
> news:1jcbtmi5rztyp$.norvlhez9i9$.dlg@40tude.net...
> ...
>> No the problem is whether to treat a call to the body as legal. The 
>> problem
>> is that you could not rely on its contract (out Car), in order to be able
>> to decide whether this call would "initialize" the object.
> [...]
> This is not at all a simple topic, and the sort of simple rule used 
> by Java does little other than give a false sense of security (and a lot of 
> annoying errors in code that has no problems).

After reading your recent hints to compatibility and single
pass compilation preventing flow analysis for legality decisions,
I noticed the possibility of a restrictions pragma, too.

Is it really annoying when programmers are forced to state,
explicitly, what they seem to be knowing?  That is, for example,
"I know that no ELSE is missing in the following code,
therefore I have omitted a no-op else branch"

    X : Some_Type;
begin
    if I_Know_What_This_Does (P) then
       X := Assign_It;
    end if;

    Use_It := Involve (X);

When I try to change a program, I find it annoying to
*not* see an ELSE branch that does then become a missing ELSE
branch.  The desired change turns a one-way flow into a blind alley...

The code typically looks like this:

    X : Some_Type;
begin
    if Has_Worked_For_Me (P) then
        X := Assign_it;
    end if;

    I_Can_Use_It := Involve (X);
        -- (formally fine in Ada, though not in Java or SPARK)

The incompleteness of information here can be avoided,
to some extent I think, and that's the reason I find
the Java rule to be helpful, or the Ada warning, or the
pragma which you have suggested.
Not really annoying.  I can no longer like seeing only half
of the cases of Boolean covered in an IF, explicitly.

To me, SPARK is not an annoyance when it refuses to accept
the above code, since flow analysis reveals the possibility
of missing initilization.  The Ada programmer may well have decided
the halting question for I_Know_What_This_Does or Has_Worked_For_Me.
However, I'd sure like to be hinted to his reasons and not just take
inspiration from a missing ELSE branch.

Could a compiler make some good use of code like the following
as a minimal way to express the programmer's valuable knowledge?
Or some less intrusive (annoying?) pragma or syntax or ...?

    X : Some_Type;
begin
    if Whatever (P) then
        X := Assign_it;
    else
        -- Stupid Ada configuration requires this.
        -- Yeah, X is valid because ...
        -- ... Whatever (P) is always true, you know.
        pragma Assert (Some_Type'Valid (X));
        null;
    end if;



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

* Re: Operation can be dispatching in only one type
  2009-12-03  5:23                                                                   ` Randy Brukardt
@ 2009-12-03 20:21                                                                     ` John B. Matthews
  0 siblings, 0 replies; 132+ messages in thread
From: John B. Matthews @ 2009-12-03 20:21 UTC (permalink / raw)


In article <hf7i10$enn$1@munin.nbi.dk>,
 "Randy Brukardt" <randy@rrsoftware.com> wrote:

> "John B. Matthews" <nospam@nospam.invalid> wrote in message 
> news:nospam-9C9974.07353802122009@news.aioe.org...
> ...
> > I'm not especially advocating applying the Java rules to Ada, but I 
> > like the warning.
> 
> Warnings have no semantic impact in Ada. There are a few places in 
> the standard that suggest that warnings be generated, but there is no 
> ideas whatsoever what that might mean. It is purely a quality-of- 
> implementation issue -- and that is between you and your Ada vendor.

Few indeed: ARM 1.1.1, 1.1.5, 13.5.2, 2.8, M.3! This is a virtue in Ada. 
When reviewing code, my own or others', I'll often use -gnatwa or -Xlint 
or -Wall or similar. Even if the warning does not represent a genuine 
oversight, it may suggest the need for a clarifying comment.

-- 
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>



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

* Re: Operation can be dispatching in only one type
  2009-12-03 11:24                                                                   ` Georg Bauhaus
@ 2009-12-03 23:08                                                                     ` Randy Brukardt
  2009-12-04  8:52                                                                       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 132+ messages in thread
From: Randy Brukardt @ 2009-12-03 23:08 UTC (permalink / raw)


"Georg Bauhaus" <rm.dash-bauhaus@futureapps.de> wrote in message 
news:4b179ffb$0$6591$9b4e6d93@newsspool3.arcor-online.net...
> Randy Brukardt schrieb:
>> [...]
>> This is not at all a simple topic, and the sort of simple rule used
>> by Java does little other than give a false sense of security (and a lot 
>> of
>> annoying errors in code that has no problems).
>
> After reading your recent hints to compatibility and single
> pass compilation preventing flow analysis for legality decisions,
> I noticed the possibility of a restrictions pragma, too.
>
> Is it really annoying when programmers are forced to state,
> explicitly, what they seem to be knowing?  That is, for example,
> "I know that no ELSE is missing in the following code,
> therefore I have omitted a no-op else branch"
>
>    X : Some_Type;
> begin
>    if I_Know_What_This_Does (P) then
>       X := Assign_It;
>    end if;
>
>    Use_It := Involve (X);
>
> When I try to change a program, I find it annoying to
> *not* see an ELSE branch that does then become a missing ELSE
> branch.  The desired change turns a one-way flow into a blind alley...

Compatibility again would cause problems for a general rule; a restriction 
could be stronger.

It should be noted that our local coding standard would consider the above 
incorrect; there always must be an else branch or at least a comment 
explaining why there is no else branch:

    if I_Know_What_This_Does (P) then
       X := Assign_It;
    -- else can't happen as P must be valid - previously checked.
    end if;

Although I generally prefer:

    if I_Know_What_This_Does (P) then
       X := Assign_It;
    else
       raise Program_Error; -- Can't happen as P must be valid - previously 
checked.
    end if;

Or in our compiler:

    if I_Know_What_This_Does (P) then
       X := Assign_It;
    else
       J2Trace.Internal_Error ("P must be valid"); -- Often including P in 
the message.
    end if;

...
> The incompleteness of information here can be avoided,
> to some extent I think, and that's the reason I find
> the Java rule to be helpful, or the Ada warning, or the
> pragma which you have suggested.
> Not really annoying.  I can no longer like seeing only half
> of the cases of Boolean covered in an IF, explicitly.

Ada has generally left this to coding standards. I'm sure Jean-Pierre will 
be happy to tell us that Ada-Control has options for enforcing the existence 
of ELSE branches.

One could imagine providing such possibilities within the language, but it 
is fairly rare that we've done that. That's partially because Restrictions 
(almost always) apply to the entire partition, including the runtime 
libraries. But independently developed subsystems (like the runtime system 
or Claw or GTKAda or AWS) are likely to have used different coding 
standards. And rewriting them to *your* coding standard is busy work at 
best, and a great way to introduce bugs at worst.

                                               Randy.





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

* Re: Operation can be dispatching in only one type
  2009-12-03 23:08                                                                     ` Randy Brukardt
@ 2009-12-04  8:52                                                                       ` Dmitry A. Kazakov
  2009-12-05  2:45                                                                         ` Randy Brukardt
  0 siblings, 1 reply; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-12-04  8:52 UTC (permalink / raw)


On Thu, 3 Dec 2009 17:08:01 -0600, Randy Brukardt wrote:

> It should be noted that our local coding standard would consider the above 
> incorrect; there always must be an else branch or at least a comment 
> explaining why there is no else branch:

What about:

   if Read_Error (File) then
      raise Data_Error;
   end if;

or

   if Estimated_Error <= Threshold then
      return Estimated_Result;
   end if;

or "exit when", which is a hidden if without else.

All these cases represent some lengthy action, maybe iterated or recursive.
The action is left upon some condition.

If not senseless "else null;", then semantically, under "else" there must
be the rest of the action (recursive, infinite).

Maybe "if" with two alternatives should better be "case". Though it would
look strange most of us:

   case Condition is
      when True =>
         X := This;
      when False =>
         X := That;
   end case;

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



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

* Re: Operation can be dispatching in only one type
  2009-12-04  8:52                                                                       ` Dmitry A. Kazakov
@ 2009-12-05  2:45                                                                         ` Randy Brukardt
  2009-12-05 10:32                                                                           ` Dmitry A. Kazakov
  0 siblings, 1 reply; 132+ messages in thread
From: Randy Brukardt @ 2009-12-05  2:45 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:qchmzfxola9n$.1owojhwd91cbc.dlg@40tude.net...
> On Thu, 3 Dec 2009 17:08:01 -0600, Randy Brukardt wrote:
>
>> It should be noted that our local coding standard would consider the 
>> above
>> incorrect; there always must be an else branch or at least a comment
>> explaining why there is no else branch:
>
> What about:
>
>   if Read_Error (File) then
>      raise Data_Error;
>   end if;

I hardly ever write this. I looked at 15 units picked at random and found 
only a handful of raises, most of them in case statements. And some of the 
"if" statements have elses or elsifs anyway. But the couple of examples I 
did find, I did indeed violate the coding standard, because there is no need 
to describe the else case. The beginning of our coding standard says that it 
is guidelines, not something to be followed blindly, and adding noise 
comments surely would qualify.

The one place where this is fairly common (the heading of Claw functions) 
would have been much better written as preconditions (which Ada 95 didn't 
have, of course):

      if not Is_Valid (Window) then
           raise Not_Valid_Error;
      end if;

doesn't need any explanation, but it would be better to have it clearly in 
the spec rather than just in comments. Writing in Ada 2012 as proposed today 
(and that might change before it gets standardized):

     procedure Do_Something (Window : Claw.Basic_Window_Type; ...)
             with Pre => Is_Valid (Window);

is surely better because it puts the check in the spec where the caller can 
see it, rather than in comments that can be ignored. (And it also opens up 
the possibility of tools/compilers warning when it is *not* true at the 
point of a call, both potentially eliminating generated code and making 
error detection earlier.)

> or
>
>   if Estimated_Error <= Threshold then
>      return Estimated_Result;
>   end if;

This should always have an else comment, IMHO. In the example you have:

    if if Estimated_Error <= Threshold then
        return Estimated_Result;
   -- else continue iteration
   end if;

because the fact that iteration is intentionally being continued is 
important. I always try to comment why and how loops are exited, because I 
find I can't figure it out easily when returning to the code in a year or 
five.

> or "exit when", which is a hidden if without else.

I also find that it is very rare that I can use "exit when". If I can, I 
would prefer to do so, as it doesn't need much commenting (continuation is 
obvious). But almost always I find that something needs to be done (usually 
to save the result of the iteration) before exiting for good, so I usually 
end up with an if statement:

     for I in Data'Range loop
         exit when Item = Buffer (I);
    end loop;
    -- Oops, we don't know where the item was found or *if* it was found, 
which was the point of the iteration.

So instead:

    Found := Data'Last + 1;
    for I in Data'Range loop
        if Item = Buffer (I) then
            Found := I;
            exit;
        -- else keep looking
        end if;
    end loop;
    -- Found now tells us where the item was, or if it was absent.

which is a pattern that seems to happen a lot in my programs.

> Maybe "if" with two alternatives should better be "case". Though it would
> look strange most of us:
>
>   case Condition is
>      when True =>
>         X := This;
>      when False =>
>         X := That;
>   end case;

That's not *that* weird; it's not unusual to find out that there are more 
than two possibilities and a case statement is often the best way to handle 
that.

Anyway, this is my (and by extension, RR's) coding standard. YMMV.

                           Randy.





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

* Re: Operation can be dispatching in only one type
  2009-12-05  2:45                                                                         ` Randy Brukardt
@ 2009-12-05 10:32                                                                           ` Dmitry A. Kazakov
  2009-12-08  0:19                                                                             ` Randy Brukardt
  0 siblings, 1 reply; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-12-05 10:32 UTC (permalink / raw)


On Fri, 4 Dec 2009 20:45:19 -0600, Randy Brukardt wrote:

> Writing in Ada 2012 as proposed today 
> (and that might change before it gets standardized):
> 
>      procedure Do_Something (Window : Claw.Basic_Window_Type; ...)
>              with Pre => Is_Valid (Window);

Why not to allow such constraints for subtypes? E.g.

   subtype Valid_Window_Type is Window_Type when Is_Valid;

then simply:

   procedure Do_Something (Window : Valid_Window_Type; ...)

> is surely better because it puts the check in the spec where the caller can 
> see it, rather than in comments that can be ignored. (And it also opens up 
> the possibility of tools/compilers warning when it is *not* true at the 
> point of a call, both potentially eliminating generated code and making 
> error detection earlier.)

Yes, but I do prefer the subtypes as the vehicle, rather than arbitrary
preconditions put here and there on the subprograms. The latter is kind of
weak typing to me.

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



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

* Re: Operation can be dispatching in only one type
  2009-12-05 10:32                                                                           ` Dmitry A. Kazakov
@ 2009-12-08  0:19                                                                             ` Randy Brukardt
  2009-12-08  4:30                                                                               ` stefan-lucks
  2009-12-08  9:22                                                                               ` Dmitry A. Kazakov
  0 siblings, 2 replies; 132+ messages in thread
From: Randy Brukardt @ 2009-12-08  0:19 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:1gcigitaii0u0.1psu2vj52e66g$.dlg@40tude.net...
> On Fri, 4 Dec 2009 20:45:19 -0600, Randy Brukardt wrote:
>
>> Writing in Ada 2012 as proposed today
>> (and that might change before it gets standardized):
>>
>>      procedure Do_Something (Window : Claw.Basic_Window_Type; ...)
>>              with Pre => Is_Valid (Window);
>
> Why not to allow such constraints for subtypes? E.g.
>
>   subtype Valid_Window_Type is Window_Type when Is_Valid;
>
> then simply:
>
>   procedure Do_Something (Window : Valid_Window_Type; ...)

That's also under consideration, but there are some problems with it. One 
problem is that such types are very confusing in array indexes/slices (do 
the values all participate or just the ones that pass the predicate?) There 
are a couple of others as well.

Another issue is that not all preconditions/postconditions can be written 
this way. For one thing, a precondition can depend on multiple parameters at 
once. Another issues is that the entry condition and exit conditions may be 
different for a parameter. For instance, from Claw:

     procedure Create (Window : Basic_Window_Type; ...)
         with Pre   => not Is_Valid (Window),
                 Post => Is_Valid (Window);

So subtypes cannot completely replace pre and post conditions, but they can 
be a complement to them.

                                Randy.





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

* Re: Operation can be dispatching in only one type
  2009-12-08  0:19                                                                             ` Randy Brukardt
@ 2009-12-08  4:30                                                                               ` stefan-lucks
  2009-12-08  9:12                                                                                 ` Dmitry A. Kazakov
  2009-12-11  0:10                                                                                 ` Robert A Duff
  2009-12-08  9:22                                                                               ` Dmitry A. Kazakov
  1 sibling, 2 replies; 132+ messages in thread
From: stefan-lucks @ 2009-12-08  4:30 UTC (permalink / raw)


On Mon, 7 Dec 2009, Randy Brukardt wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 

> > Why not to allow such constraints for subtypes? E.g.
> >
> >   subtype Valid_Window_Type is Window_Type when Is_Valid;
> >
> > then simply:
> >
> >   procedure Do_Something (Window : Valid_Window_Type; ...)
> 
> That's also under consideration, 

Great! 

Isn't that essentially the same as the invariants in Eiffel?

> but there are some problems with it. One 
> problem is that such types are very confusing in array indexes/slices (do 
> the values all participate or just the ones that pass the predicate?) 

One way to solve^H^H^H^H^H^H circumvent this problem would be to prohibit 
that kind of subtyping for discrete types. In Dmity's example above, 
Window_Type is likely to be a record (probably a tagged one). If it is not 
a discrete type, you can't use it as an array index. :-)

In any case, you definitively would not want to allow that kind of type 
for array indexes, if only the values which the predicate being true is 
allowed. How would you efficiently implement something like

   subtype Primes is Positive when Is_Prime;
   A: array (Primes (10_000 .. 20_000)) of T; -- 10_001 primality tests
   B: array (Primes (Start  ..   Stop)) of T; -- Start-Stop+1 such tests
                                              -- possibly at runtime

> Another issue is that not all preconditions/postconditions can be written 
> this way. For one thing, a precondition can depend on multiple parameters at 
> once. Another issues is that the entry condition and exit conditions may be 
> different for a parameter. 

Right. That is precisely why Eiffel distinguishes preconditions, 
postconditions and invariants -- and supports all the three.


-- 
------ Stefan Lucks   --  Bauhaus-University Weimar  --   Germany  ------
               Stefan dot Lucks at uni minus weimar dot de
------  I  love  the  taste  of  Cryptanalysis  in  the  morning!  ------




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

* Re: Operation can be dispatching in only one type
  2009-12-08  4:30                                                                               ` stefan-lucks
@ 2009-12-08  9:12                                                                                 ` Dmitry A. Kazakov
  2009-12-10  4:09                                                                                   ` Randy Brukardt
  2009-12-11  0:10                                                                                 ` Robert A Duff
  1 sibling, 1 reply; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-12-08  9:12 UTC (permalink / raw)


On Tue, 8 Dec 2009 05:30:30 +0100, stefan-lucks@see-the.signature wrote:

> On Mon, 7 Dec 2009, Randy Brukardt wrote:
> 
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
> 
>>> Why not to allow such constraints for subtypes? E.g.
>>>
>>>   subtype Valid_Window_Type is Window_Type when Is_Valid;
>>>
>>> then simply:
>>>
>>>   procedure Do_Something (Window : Valid_Window_Type; ...)
>> 
>> That's also under consideration, 
> 
> Great! 
> 
> Isn't that essentially the same as the invariants in Eiffel?

I see differences. Both Window_Type and Valid_Window_Type are visible.
Eiffel invariant deals with one type. Further the invariant is an
implementation detail normally invisible for the clients. Subtype is a
publicly declared constraint (contract).

>> but there are some problems with it. One 
>> problem is that such types are very confusing in array indexes/slices (do 
>> the values all participate or just the ones that pass the predicate?) 
> 
> One way to solve^H^H^H^H^H^H circumvent this problem would be to prohibit 
> that kind of subtyping for discrete types. In Dmity's example above, 
> Window_Type is likely to be a record (probably a tagged one). If it is not 
> a discrete type, you can't use it as an array index. :-)

Well, it would be nice not to limit this to only tagged types.

> In any case, you definitively would not want to allow that kind of type 
> for array indexes, if only the values which the predicate being true is 
> allowed. How would you efficiently implement something like
> 
>    subtype Primes is Positive when Is_Prime;
>    A: array (Primes (10_000 .. 20_000)) of T; -- 10_001 primality tests

I assume the above should be:

A: array (Primes'Val (10_000) .. Primes'Val (20_000)) of T;

>    B: array (Primes (Start  ..   Stop)) of T; -- Start-Stop+1 such tests
>                                               -- possibly at runtime

And this:

 B: array (Primes (Start) .. Primes (Stop)) of T;

However the rules determining the subtype of the range are not clear. The
main problem is that there is no range types and their subtype to clarify
the issue:

   Positive'(1)..Positive'(2)  is this positive range or Integer range?

Same with above, if ranges fall back to the base type ranges, there will be
no problem, but also the semantics of the declarations would change to:

A: array (Integer (Primes'Val (10_000)) .. Integer (Primes'Val (20_000)))
    of T;

This is the actual problem to me, not the performance issues. The
programmer packing a DVD playback into the subtype constraint should know
what he is doing.

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



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

* Re: Operation can be dispatching in only one type
  2009-12-08  0:19                                                                             ` Randy Brukardt
  2009-12-08  4:30                                                                               ` stefan-lucks
@ 2009-12-08  9:22                                                                               ` Dmitry A. Kazakov
  2009-12-08 10:06                                                                                 ` Georg Bauhaus
  1 sibling, 1 reply; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-12-08  9:22 UTC (permalink / raw)


On Mon, 7 Dec 2009 18:19:11 -0600, Randy Brukardt wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
> news:1gcigitaii0u0.1psu2vj52e66g$.dlg@40tude.net...
>> On Fri, 4 Dec 2009 20:45:19 -0600, Randy Brukardt wrote:
>>
>>> Writing in Ada 2012 as proposed today
>>> (and that might change before it gets standardized):
>>>
>>>      procedure Do_Something (Window : Claw.Basic_Window_Type; ...)
>>>              with Pre => Is_Valid (Window);
>>
>> Why not to allow such constraints for subtypes? E.g.
>>
>>   subtype Valid_Window_Type is Window_Type when Is_Valid;
>>
>> then simply:
>>
>>   procedure Do_Something (Window : Valid_Window_Type; ...)
> 
> That's also under consideration, but there are some problems with it. One 
> problem is that such types are very confusing in array indexes/slices (do 
> the values all participate or just the ones that pass the predicate?)

Only ones of the subtype, obviously. But the problem is same as with the
index sliding: when two subsets of the index are equivalent, either
nominally (when elements are same) or structurally (when the number of
elements is same + maybe other conditions). Structural equivalence might
appear convenient, but it is always a source of confusion.

> are a couple of others as well.
> 
> Another issue is that not all preconditions/postconditions can be written 
> this way. For one thing, a precondition can depend on multiple parameters at 
> once. Another issues is that the entry condition and exit conditions may be 
> different for a parameter. For instance, from Claw:
> 
>      procedure Create (Window : Basic_Window_Type; ...)
>          with Pre   => not Is_Valid (Window),
>                  Post => Is_Valid (Window);

Mutating [sub]type? That looks like a case for a constructor to me (an old
discussion).

> So subtypes cannot completely replace pre and post conditions, but they can 
> be a complement to them.

Absolutely.

However I consider it differently. In my view pre-/postconditions and
invariants should be static, used strictly for program correctness proofs.
Subtypes should complement them for dynamic run-time checks (recoverable
faults).

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



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

* Re: Operation can be dispatching in only one type
  2009-12-08  9:22                                                                               ` Dmitry A. Kazakov
@ 2009-12-08 10:06                                                                                 ` Georg Bauhaus
  2009-12-08 10:23                                                                                   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 132+ messages in thread
From: Georg Bauhaus @ 2009-12-08 10:06 UTC (permalink / raw)


Dmitry A. Kazakov schrieb:
> In my view pre-/postconditions and
> invariants should be static, used strictly for program correctness proofs.
> Subtypes should complement them for dynamic run-time checks (recoverable
> faults).
> 

Hm. What would be your subtype based expression for

  generic
     type E is private;
  package Stacks  is


    type Stack is private;

    procedure push (Modified_Stack : in out Stack;
                    Another : Element)
         with pre => not Full (Modified_Stack),
              post => Size (Modified_Stack'Exit) = Size (Modified_Stack);

    procedure pop (Modified_Stack : in out Stack)
         with pre => not Empty (Modified_Stack),
              post => Empty (Modified_Stack);





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

* Re: Operation can be dispatching in only one type
  2009-12-08 10:06                                                                                 ` Georg Bauhaus
@ 2009-12-08 10:23                                                                                   ` Dmitry A. Kazakov
  2009-12-08 10:33                                                                                     ` Georg Bauhaus
  0 siblings, 1 reply; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-12-08 10:23 UTC (permalink / raw)


On Tue, 08 Dec 2009 11:06:54 +0100, Georg Bauhaus wrote:

> Dmitry A. Kazakov schrieb:
>> In my view pre-/postconditions and
>> invariants should be static, used strictly for program correctness proofs.
>> Subtypes should complement them for dynamic run-time checks (recoverable
>> faults).
> 
> Hm. What would be your subtype based expression for
> 
>   generic
>      type E is private;
>   package Stacks  is
> 
>     type Stack is private;
> 
>     procedure push (Modified_Stack : in out Stack;
>                     Another : Element)
>          with pre => not Full (Modified_Stack),
>               post => Size (Modified_Stack'Exit) = Size (Modified_Stack);
> 
>     procedure pop (Modified_Stack : in out Stack)
>          with pre => not Empty (Modified_Stack),
>               post => Empty (Modified_Stack);

None. The above is wrong. You cannot implement this contract (if we deduced
one from the given pre- and postconditions). Proof:

   loop
      Push (Stack, X);
   end loop;

q.e.d.

Therefore the contract of a stack must always contain ideals, e.g.

1. exceptions, like Full_Error, Empty_Error;

2. blocked states, like holding the caller until the stack state is changed
from another task.

Pre- and psotconditions are to be used to prove a contract to hold. They
themselves are no contract.

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



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

* Re: Operation can be dispatching in only one type
  2009-12-08 10:23                                                                                   ` Dmitry A. Kazakov
@ 2009-12-08 10:33                                                                                     ` Georg Bauhaus
  2009-12-08 10:49                                                                                       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 132+ messages in thread
From: Georg Bauhaus @ 2009-12-08 10:33 UTC (permalink / raw)


Dmitry A. Kazakov schrieb:
> On Tue, 08 Dec 2009 11:06:54 +0100, Georg Bauhaus wrote:
> 
>> Dmitry A. Kazakov schrieb:
>>> In my view pre-/postconditions and
>>> invariants should be static, used strictly for program correctness proofs.
>>> Subtypes should complement them for dynamic run-time checks (recoverable
>>> faults).
>> Hm. What would be your subtype based expression for
>>
>>   generic
>>      type E is private;
>>   package Stacks  is
>>
>>     type Stack is private;
>>
>>     procedure push (Modified_Stack : in out Stack;
>>                     Another : Element)
>>          with pre => not Full (Modified_Stack),
>>               post => Size (Modified_Stack'Exit) = Size (Modified_Stack);
>>
>>     procedure pop (Modified_Stack : in out Stack)
>>          with pre => not Empty (Modified_Stack),
>>               post => Empty (Modified_Stack);
> 
> None. The above is wrong. You cannot implement this contract (if we deduced
> one from the given pre- and postconditions). Proof:
> 
>    loop
>       Push (Stack, X);
>    end loop;
> 
> q.e.d.
> 
> Therefore the contract of a stack must always contain ideals, e.g.
> 
> 1. exceptions, like Full_Error, Empty_Error;

I understand that exceptions are implied by Eiffel style
conditions.

The Eiffel camp might answer, for example,

    Lock (Stack);

    while not Full (Stack) loop
        Push (Stack, X);
    end loop;

    Unlock (Stack);

q.e.d.

> 2. blocked states, like holding the caller until the stack state is changed
> from another task.

Would you want this to be possible with Ada, or with SPARK? ;-)

> 
> Pre- and psotconditions are to be used to prove a contract to hold. They
> themselves are no contract.

In Eiffel, pre post and inv are used to write a contract.
The proof obligation rests on the programmer.



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

* Re: Operation can be dispatching in only one type
  2009-12-08 10:33                                                                                     ` Georg Bauhaus
@ 2009-12-08 10:49                                                                                       ` Dmitry A. Kazakov
  0 siblings, 0 replies; 132+ messages in thread
From: Dmitry A. Kazakov @ 2009-12-08 10:49 UTC (permalink / raw)


On Tue, 08 Dec 2009 11:33:25 +0100, Georg Bauhaus wrote:

> Dmitry A. Kazakov schrieb:
>> On Tue, 08 Dec 2009 11:06:54 +0100, Georg Bauhaus wrote:
>> 
>>> Dmitry A. Kazakov schrieb:
>>>> In my view pre-/postconditions and
>>>> invariants should be static, used strictly for program correctness proofs.
>>>> Subtypes should complement them for dynamic run-time checks (recoverable
>>>> faults).
>>> Hm. What would be your subtype based expression for
>>>
>>>   generic
>>>      type E is private;
>>>   package Stacks  is
>>>
>>>     type Stack is private;
>>>
>>>     procedure push (Modified_Stack : in out Stack;
>>>                     Another : Element)
>>>          with pre => not Full (Modified_Stack),
>>>               post => Size (Modified_Stack'Exit) = Size (Modified_Stack);
>>>
>>>     procedure pop (Modified_Stack : in out Stack)
>>>          with pre => not Empty (Modified_Stack),
>>>               post => Empty (Modified_Stack);
>> 
>> None. The above is wrong. You cannot implement this contract (if we deduced
>> one from the given pre- and postconditions). Proof:
>> 
>>    loop
>>       Push (Stack, X);
>>    end loop;
>> 
>> q.e.d.
>> 
>> Therefore the contract of a stack must always contain ideals, e.g.
>> 
>> 1. exceptions, like Full_Error, Empty_Error;
> 
> I understand that exceptions are implied by Eiffel style
> conditions.

No, in that case the conditions should be:

pre  => true
post => Size (Modified_Stack'Exit) = Size (Modified_Stack); or Full_Error

Actually, the second part is more elaborated, it should also state that the
stack was not modified, but you've got the idea. Ideals are postcondition
things. 

>> 2. blocked states, like holding the caller until the stack state is changed
>> from another task.
> 
> Would you want this to be possible with Ada, or with SPARK? ;-)

In what sense? Of course it is possible to implement in Ada using a
protected object or a monitor task.

>> Pre- and psotconditions are to be used to prove a contract to hold. They
>> themselves are no contract.
> 
> In Eiffel, pre post and inv are used to write a contract.
> The proof obligation rests on the programmer.

Yes, this is the core of the disagreement. If that rests on the programmer,
then *-conditions are THE program.

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



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

* Re: Operation can be dispatching in only one type
  2009-12-08  9:12                                                                                 ` Dmitry A. Kazakov
@ 2009-12-10  4:09                                                                                   ` Randy Brukardt
  0 siblings, 0 replies; 132+ messages in thread
From: Randy Brukardt @ 2009-12-10  4:09 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:c7bquicl77wg$.1lpuev0db0z46$.dlg@40tude.net...
> On Tue, 8 Dec 2009 05:30:30 +0100, stefan-lucks@see-the.signature wrote:
...
>> Isn't that essentially the same as the invariants in Eiffel?
>
> I see differences. Both Window_Type and Valid_Window_Type are visible.
> Eiffel invariant deals with one type. Further the invariant is an
> implementation detail normally invisible for the clients. Subtype is a
> publicly declared constraint (contract).

Right. We're actually considering both. We're almost certainly going to have 
invariants, on private types only, which are required to be checked only at 
the boundary of the defining package. (Such invariants can be abused, but 
they still more predicable than those on visible types.) Such invariants 
apply to all values of a type.

Subtype predicates (for the lack of a better name, they're definitely *not* 
constraints, read AI05-0153-1 to see why) apply only to a view of a type, 
and would mainly be checked when a conversion to the subtype is done. 
(Almost everything interesting in Ada is technically a conversion to a 
subtype, so that covers the vast majority of interesting cases.) The current 
thinking is that using a subtype with a predicate in an array index, slice, 
entry family, and possibly some cases I forgot about would be illegal (or 
raise Program_Error in a generic body). We don't want to prevent the 
construction of subtypes like:

     subtype Odd_Integer is Integer with Predicate => Odd_Integer mod 2 = 1;

but we sure don't want them in arrays.

I'm not throughly convinced that this is the right approach, but more work 
needs to be done on the proposal in any case.

                             Randy.







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

* Re: Operation can be dispatching in only one type
  2009-12-08  4:30                                                                               ` stefan-lucks
  2009-12-08  9:12                                                                                 ` Dmitry A. Kazakov
@ 2009-12-11  0:10                                                                                 ` Robert A Duff
  1 sibling, 0 replies; 132+ messages in thread
From: Robert A Duff @ 2009-12-11  0:10 UTC (permalink / raw)


stefan-lucks@see-the.signature writes:

> On Mon, 7 Dec 2009, Randy Brukardt wrote:
>
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
>
>> > Why not to allow such constraints for subtypes? E.g.
>> >
>> >   subtype Valid_Window_Type is Window_Type when Is_Valid;
>> >
>> > then simply:
>> >
>> >   procedure Do_Something (Window : Valid_Window_Type; ...)
>> 
>> That's also under consideration, 
>
> Great! 

Yes, it is great.  I am a strong advocate of this feature.
But there are a lot of details to work out, and the feature
might not make it into the language by 2012.  We'll see.

> Isn't that essentially the same as the invariants in Eiffel?

Yes, it's quite similar.  But there are some important differences,
such as the fact that in Eiffel, a class is both a type and a module,
whereas in Ada, we have types, subtypes, and packages as separate
concepts.

>> but there are some problems with it. One 
>> problem is that such types are very confusing in array indexes/slices (do 
>> the values all participate or just the ones that pass the predicate?) 

I consider such problems to be side issues.  They are solvable,
I think.

> One way to solve^H^H^H^H^H^H circumvent this problem would be to prohibit 
> that kind of subtyping for discrete types. In Dmity's example above, 
> Window_Type is likely to be a record (probably a tagged one). If it is not 
> a discrete type, you can't use it as an array index. :-)

I don't like that "solution" (or "circumvention", if you prefer).  ;-)
I think one important goal is to be able to have arbitrary
subtypes of an enumeration type, in addition to just subranges.
I don't much care about arrays indexed by such subtypes.

    subtype Vowel is Character
        with Predicate => To_Lower(Vowel) in ('a', 'e', 'i', 'o', 'u');

or something like that.  Here, Vowel refers to the current instance
of subtype Vowel.  I don't particularly want an array indexed by
Vowel, but I might want to say:

    case C is
        when Vowel => ...;
        when Consonant => ...;
        when Punctuation => ...;
        ...

or:

    procedure P(X : Vowel);

or:

    if X in Vowel ...

- Bob



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

* Re: Operation can be dispatching in only one type
  2009-12-01  8:01                                                       ` stefan-lucks
  2009-12-01 13:37                                                         ` Dmitry A. Kazakov
@ 2009-12-15 23:54                                                         ` Robert A Duff
  1 sibling, 0 replies; 132+ messages in thread
From: Robert A Duff @ 2009-12-15 23:54 UTC (permalink / raw)


stefan-lucks@see-the.signature writes:

> On Tue, 1 Dec 2009, Dmitry A. Kazakov wrote:
>
>> On Tue, 1 Dec 2009 06:45:16 +0100, stefan-lucks@see-the.signature wrote:
>> 
>> > On Tue, 1 Dec 2009, Dmitry A. Kazakov wrote:
>> > 
>> >> On Mon, 30 Nov 2009 15:43:21 -0500, Robert A Duff wrote:
>> > 
>> >>> Right.  I think they should be equivalent.  My solution is to use
>> >>> two different symbols for (initial) assignment and (subsequent)
>> >>> reassignment.
>> >> 
>> >> But they cannot be, otherwise the semantics of ":=" would depend on the
>> >> things done before:
>> >> 
>> >>     X : T;
>> >> begin
>> >>     X := F (Y); -- Initialization
>> > 
>> > No, at this point of time, X has been initialised to *some* value, even if 
>> > the value itself is undefined. So this is just a proper assignment. 
>> 
>> You should say that to Bob, because this is exactly my point.

Bob, here.

Sorry I didn't reply to many messages in this thread -- I don't follow
this newsgroup every day.  Too much real work to be done.  ;-)
More like every few months...

I'm getting mixed up about arguments regarding semantics,
versus arguments regarding terminology.  Both are important.

> No!
>
> You just moved to a different topic:
>
> [...]
>> Initialization /= construction does not fit into this picture.
>
> The issue was 
>
>   initialisation /= assignment (*)

Right.  Ada distinguishes the two.  But it uses the same syntax for
both, which I think is confusing.

Except we use "zee".  Or "zed" if you prefer.  ;-)

Actually the Ada terminology is that "assignment" includes both:
"initialization" and "assignment_statement".  That's confusing.

> and the fact that in Ada both look syntactically the same. You seem to be 
> the first to mention "construction" at all.
>
> BTW, I don't think initialisation and construction are actually identical, 
> even though they have to be performed in close temporal proximity. If 
> construction fails, this is a Storage_Error. A failed Initialisation is 
> much more powerful -- it can raise any of your favourite exceptions. ;-)

More terminology confusion:  Some folks think "construct" and "allocate
storage" are synonymous.  Other folks think "construct" and "initialize"
are synonymous.  Maybe in 100 years computer science will have terms
everybody can agree on.  In the mean time, we have "procedure",
"function", "subprogram", "subroutine", "routine", "program",
"method", etc. all of which mean more-or-less the same thing.  Sigh.

> ---------
> Footnote:
> (*) I prefer to avoid the word "reassignment", which Bob would use. 

Sigh.  Several people have voted against my (clever?  too clever?)
"assign" vs. "reassign" terminology.  I'm still not sure...

- Bob



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

* operation can be dispatching in only one type
@ 2015-11-23 10:23 Serge Robyns
  2015-11-23 11:29 ` Dmitry A. Kazakov
  2015-11-23 17:40 ` Jeffrey R. Carter
  0 siblings, 2 replies; 132+ messages in thread
From: Serge Robyns @ 2015-11-23 10:23 UTC (permalink / raw)


Guys,

I'm facing an issue with Ada when it comes to use an operation on two tagged types.  It isn't a road blocker and I've found my way around and are not using tagged types for these anymore.  I've now a function that computes the total balance every time.  Another option is to pass the id and then search the map.

However in C++ it does work as I expected.

Let's say I've the following tagged types.

   type T_Balance is tagged record
      Id       : T_Balance_Id;
      Name     : T_Balance_Name;
      Balance  : T_Amount;
   end record;

   package Balance_Map is new
     Ada.Containers.Ordered_Maps (Key_Type   => T_Balance_Id,
                                  Element_Type => T_Balance);

   type T_Account is tagged record
      Name             : T_Account_Name;
      Total_Balance    : T_Money;
      Balances         : Balance_Map.Map;
   end record;

And I want to have an operation increasing a balance and the total in the account.
The following declaration is refused:

   procedure Update_Balance
     (Self   : in out T_Account;
      AB     : in out T_Balance;
      Amount : in     T_Money);

My hope was that it gets dispatched to the right operation on Self which in turns will call the right operation on AB.  But the compiler seems not to agree.

in C++:
class account {
public:
	account_id id;
	account_name name;
        money total_balance;
	balance_list balances;

	account();
	virtual ~account();

	void update_balance (account_balance& ab, money amount);
};

void account::update_balance (account_balance& ab, money amount)
{
	ab.update_balance(amount);
	total_balance.amount += amount;
}

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

* Re: operation can be dispatching in only one type
  2015-11-23 10:23 operation can be dispatching in only one type Serge Robyns
@ 2015-11-23 11:29 ` Dmitry A. Kazakov
  2015-11-23 13:05   ` Serge Robyns
  2015-11-23 17:40 ` Jeffrey R. Carter
  1 sibling, 1 reply; 132+ messages in thread
From: Dmitry A. Kazakov @ 2015-11-23 11:29 UTC (permalink / raw)


On Mon, 23 Nov 2015 02:23:57 -0800 (PST), Serge Robyns wrote:

> I'm facing an issue with Ada when it comes to use an operation on two
> tagged types.

You can use tagged types, they cannot be dispatching arguments though. That
is a big difference.

> However in C++ it does work as I expected.

C++ has no multiple dispatch either.
 
> Let's say I've the following tagged types.
> 
>    type T_Balance is tagged record
>       Id       : T_Balance_Id;
>       Name     : T_Balance_Name;
>       Balance  : T_Amount;
>    end record;
> 
>    package Balance_Map is new
>      Ada.Containers.Ordered_Maps (Key_Type   => T_Balance_Id,
>                                   Element_Type => T_Balance);
> 
>    type T_Account is tagged record
>       Name             : T_Account_Name;
>       Total_Balance    : T_Money;
>       Balances         : Balance_Map.Map;
>    end record;
> 
> And I want to have an operation increasing a balance and the total in the account.
> The following declaration is refused:
> 
>    procedure Update_Balance
>      (Self   : in out T_Account;
>       AB     : in out T_Balance;
>       Amount : in     T_Money);
> 
> My hope was that it gets dispatched to the right operation on Self which
> in turns will call the right operation on AB.  But the compiler seems not
> to agree.

It is too late to declare a dispatching operation on T_Balance when you
already used T_Balance as a type somewhere else, e.g. to instantiate a
package.

I don't use Ada containers, but the pattern is:

1. Instantiate the package with T_Balance'Class

2. Declare the container-specific callback, e.g. Update_Balance with
T_Balance'Class

3. Dispatch from Update_Balance, to an [abstract] primitive operation of
T_Balance you declare in advance. E.g. On_Update.

[ This is what happens in C++, because in C++ T and T'Class are
[in]consistently confused. ]

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

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

* Re: operation can be dispatching in only one type
  2015-11-23 11:29 ` Dmitry A. Kazakov
@ 2015-11-23 13:05   ` Serge Robyns
  2015-11-23 13:48     ` Dmitry A. Kazakov
  0 siblings, 1 reply; 132+ messages in thread
From: Serge Robyns @ 2015-11-23 13:05 UTC (permalink / raw)


On Monday, 23 November 2015 12:29:55 UTC+1, Dmitry A. Kazakov  wrote:
> On Mon, 23 Nov 2015 02:23:57 -0800 (PST), Serge Robyns wrote:
> 
> > I'm facing an issue with Ada when it comes to use an operation on two
> > tagged types.
> 
> You can use tagged types, they cannot be dispatching arguments though. That
> is a big difference.
> 
> > However in C++ it does work as I expected.
> 
> C++ has no multiple dispatch either.

I'm not using multiple dispatching, I'm using "serial" dispatching.  What I'm trying to achieve is very close to the concept of a mix-in. The code in C++ is doing what I want to achieve.  Update the specific balance and the "parent" sum in a cheap and direct way.  Obviously there is a potential "bug" as I can pass any balance to the operation, including ones from another account.

> It is too late to declare a dispatching operation on T_Balance when you
> already used T_Balance as a type somewhere else, e.g. to instantiate a
> package.
> 

As I said that operation is not dispatching on T_Balance, the T_Account operation will be dispatching.

As with regards to callback constructs, this sounds like "ugly" workarounds IMHO.

This weekend I've been re-writing the complete core "class" hierarchy in C++11 and 1 XML SAX parser into Xerces as a test.  I still need to rewrite the existing business logic and decide on how to implement DAO for which I did a niece implementation in Ada (IMHO), as I can have mixture of data stores for different components.  The abstract interface is using multiple limited interfaces.  However I stumbled on something that looks very interesting: ODB (C++) https://en.wikipedia.org/wiki/ODB_%28C%2B%2B%29.  For Ada I did use GNATCOLL but was also looking at Gnoga as an alternative.

During that exercise I missed 2 major benefits of Ada.  Very strong typing, although C++11's "enum class" gives me the same when it comes to the primitive data types, i.e. scalars.  And last but not least it's readability.  I love the Pascal family syntax.  In my former C career I've suffered a lot of imbalanced '{}'. And I've been looking at C replacements since the early 1990's only to see that that syntax style is getting more and more spread. :-(

Having said that, I still didn't decide on which one to pursue, Ada 2012 or C++ 11 or 14.  One of the benefits of C++ is the very large collection of 3rd party libraries.  I do recognize the work of David Botton and yourself in that area.

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

* Re: operation can be dispatching in only one type
  2015-11-23 13:05   ` Serge Robyns
@ 2015-11-23 13:48     ` Dmitry A. Kazakov
  2015-11-23 14:16       ` Serge Robyns
  0 siblings, 1 reply; 132+ messages in thread
From: Dmitry A. Kazakov @ 2015-11-23 13:48 UTC (permalink / raw)


On Mon, 23 Nov 2015 05:05:02 -0800 (PST), Serge Robyns wrote:

> On Monday, 23 November 2015 12:29:55 UTC+1, Dmitry A. Kazakov  wrote:
>> On Mon, 23 Nov 2015 02:23:57 -0800 (PST), Serge Robyns wrote:
>> 
>>> I'm facing an issue with Ada when it comes to use an operation on two
>>> tagged types.
>> 
>> You can use tagged types, they cannot be dispatching arguments though. That
>> is a big difference.
>> 
>>> However in C++ it does work as I expected.
>> 
>> C++ has no multiple dispatch either.
> 
> I'm not using multiple dispatching, I'm using "serial" dispatching.  What
> I'm trying to achieve is very close to the concept of a mix-in.

Hmm, mix-in uses a class-wide that gets mixed in. Which is why you could
dispatch on it. No class-wide, no dispatch.

> The code in C++ is doing what I want to achieve.

C++ code is broken, always broken, because C++ confuses T and T'Class and
hence re-dispatches each time and every place (except for ctors). Ada's
exact equivalent to

void account::update_balance (account_balance& ab, money amount)

is

procedure Update_Balance (X : in out Account;
    AB : in out Account_Balance'Class, ...)

Neither is dispatching in AB. Where is a problem?

> Obviously there is a
> potential "bug" as I can pass any balance to the operation, including ones
> from another account.

Re-dispatch is a potential bug because it ignores declared types.
 
>> It is too late to declare a dispatching operation on T_Balance when you
>> already used T_Balance as a type somewhere else, e.g. to instantiate a
>> package.
> 
> As I said that operation is not dispatching on T_Balance, the T_Account
> operation will be dispatching.

Which is good as T_Account is the type being declared. I don't see what is
the problem. If Update_Balance should be a primitive operation of
T_Balance, it must be declared so. At the declaration point of T_Balance
there is no T_Account yet thus you could not use it there. Again, good, it
is bad design to mix containers and elements of. You just are trying an
unpattern, IMO.

You can still inject an account interface there if you wanted:

   type Abstract_Account is limited interface ...;

   type T_Balance is ...
   procedure Update_Balance -- Primitive operation
   (  Account : in out Abstract_Account'Class;
      Balance : in out T_Balance; ...
   );

   type T_Account is new Abstract_Account with ...
 
> As with regards to callback constructs, this sounds like "ugly" workarounds IMHO.

Possibly, but IMO because of an anti-OO design. What are operations of
T_Balance. What are operations of T_Account? Types are useless without
operations.

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

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

* Re: operation can be dispatching in only one type
  2015-11-23 13:48     ` Dmitry A. Kazakov
@ 2015-11-23 14:16       ` Serge Robyns
  2015-11-23 14:59         ` G.B.
  2015-11-23 15:52         ` Dmitry A. Kazakov
  0 siblings, 2 replies; 132+ messages in thread
From: Serge Robyns @ 2015-11-23 14:16 UTC (permalink / raw)


On Monday, 23 November 2015 14:48:45 UTC+1, Dmitry A. Kazakov  wrote:
> On Mon, 23 Nov 2015 05:05:02 -0800 (PST), Serge Robyns wrote:
> 
> > On Monday, 23 November 2015 12:29:55 UTC+1, Dmitry A. Kazakov  wrote:
> >> On Mon, 23 Nov 2015 02:23:57 -0800 (PST), Serge Robyns wrote:
> >> 
> >>> I'm facing an issue with Ada when it comes to use an operation on two
> >>> tagged types.
> >> 
> >> You can use tagged types, they cannot be dispatching arguments though. That
> >> is a big difference.
> >> 

> C++ code is broken, always broken, because C++ confuses T and T'Class and
> hence re-dispatches each time and every place (except for ctors). Ada's
> exact equivalent to
> 
> void account::update_balance (account_balance& ab, money amount)
> 
> is
> 
> procedure Update_Balance (X : in out Account;
>     AB : in out Account_Balance'Class, ...)
> 

This one did the trick.  I do feel very frustrated with regards to the Ada idiosyncrasies, if I may say so. Recalls me the "'" notation I had to use when declaring a part of a constant that was from a parent class.  I got this trick in this newsgroup too.  Trying to google on Ada "'" is a challenge :-P.

I'm wondering the best way to "learn" these without falling asleep while reading for the 10th time basic programming stuff and then missing that one important comment in the text.


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

* Re: operation can be dispatching in only one type
  2015-11-23 14:16       ` Serge Robyns
@ 2015-11-23 14:59         ` G.B.
  2015-11-23 15:52         ` Dmitry A. Kazakov
  1 sibling, 0 replies; 132+ messages in thread
From: G.B. @ 2015-11-23 14:59 UTC (permalink / raw)


On 23.11.15 15:16, Serge Robyns wrote:
> I do feel very frustrated with regards to the Ada idiosyncrasies

To me, 'Class means openly stating the intent:  C++ does many things
"automatically" when possible. Which is why you can show excellence
when you can tell how. (In case of interpreting compiler diagnostics,
say.)

An example is when different types inheriting from t_balance
are placed in a container

   map<..., t_balance>

If class t_balance_A : public t_balance, then the compiler may
let you place an object declared of type t_balance_A in the map
- you'd think. But it turns out to silently have become a t_balance.
Trying a fix

   map<..., t_balance&>

or similar, chances are that after this, a long list of errors
will appear, about operators, value initialization, type differences
etc.

If Ada does fewer things "automatically", thus requesting that you
specify type T'Class when you mean things class-wide, this reduced
malleability of the meaning of names may become an advantage.
A consequence is less effort at understanding what a name is
referring to, and an increase of  errors-related productivity,
as no automatic choice needs to be unfolded in the diagnostic messages.

    T'Class   means   for all types with T a progenitor
    T         means   T, only.

The 'Class thing marks the place where there could be a variation
in run-time dispatching at all.

Of course, any competent C++ programmer will always do the right
thing, which is not using T where a T* or T& is in order.


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

* Re: operation can be dispatching in only one type
  2015-11-23 14:16       ` Serge Robyns
  2015-11-23 14:59         ` G.B.
@ 2015-11-23 15:52         ` Dmitry A. Kazakov
  1 sibling, 0 replies; 132+ messages in thread
From: Dmitry A. Kazakov @ 2015-11-23 15:52 UTC (permalink / raw)


On Mon, 23 Nov 2015 06:16:38 -0800 (PST), Serge Robyns wrote:

> On Monday, 23 November 2015 14:48:45 UTC+1, Dmitry A. Kazakov  wrote:
>> On Mon, 23 Nov 2015 05:05:02 -0800 (PST), Serge Robyns wrote:
>> 
>>> On Monday, 23 November 2015 12:29:55 UTC+1, Dmitry A. Kazakov  wrote:
>>>> On Mon, 23 Nov 2015 02:23:57 -0800 (PST), Serge Robyns wrote:
>>>> 
>>>>> I'm facing an issue with Ada when it comes to use an operation on two
>>>>> tagged types.
>>>> 
>>>> You can use tagged types, they cannot be dispatching arguments though. That
>>>> is a big difference.
>>>> 
> 
>> C++ code is broken, always broken, because C++ confuses T and T'Class and
>> hence re-dispatches each time and every place (except for ctors). Ada's
>> exact equivalent to
>> 
>> void account::update_balance (account_balance& ab, money amount)
>> 
>> is
>> 
>> procedure Update_Balance (X : in out Account;
>>     AB : in out Account_Balance'Class, ...)
> 
> This one did the trick.  I do feel very frustrated with regards to the Ada
> idiosyncrasies, if I may say so. Recalls me the "'" notation I had to use
> when declaring a part of a constant that was from a parent class.

It depends on what you believe is "right." If you programmed C++ in Ada you
would indeed face difficulties, and conversely. But again C++ is
inconsistent in its treatment of specific and class-wide types. Ada merely
requires you to specify the exact type of the operation's argument, that
is.

> I'm wondering the best way to "learn" these without falling asleep while
> reading for the 10th time basic programming stuff and then missing that
> one important comment in the text.

Regarding OO features, the best way is start thinking of it in terms of
types rather than of [untyped] data structures and procedures. You will
better understand both Ada and C++:

class = set of types (closed upon inheritance)
class-wide type = the closure of the class
specific type = member of the class

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


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

* Re: operation can be dispatching in only one type
  2015-11-23 10:23 operation can be dispatching in only one type Serge Robyns
  2015-11-23 11:29 ` Dmitry A. Kazakov
@ 2015-11-23 17:40 ` Jeffrey R. Carter
  2015-11-24  9:08   ` Serge Robyns
  1 sibling, 1 reply; 132+ messages in thread
From: Jeffrey R. Carter @ 2015-11-23 17:40 UTC (permalink / raw)


On 11/23/2015 03:23 AM, Serge Robyns wrote:
> 
> I'm facing an issue with Ada when it comes to use an operation on two tagged types.  It isn't a road blocker and I've found my way around and are not using tagged types for these anymore.  I've now a function that computes the total balance every time.  Another option is to pass the id and then search the map.
>
>    type T_Balance is tagged record
>       Id       : T_Balance_Id;
>       Name     : T_Balance_Name;
>       Balance  : T_Amount;
>    end record;
> 
>    package Balance_Map is new
>      Ada.Containers.Ordered_Maps (Key_Type   => T_Balance_Id,
>                                   Element_Type => T_Balance);
> 
>    type T_Account is tagged record
>       Name             : T_Account_Name;
>       Total_Balance    : T_Money;
>       Balances         : Balance_Map.Map;
>    end record;
> 
> And I want to have an operation increasing a balance and the total in the account.
> The following declaration is refused:
> 
>    procedure Update_Balance
>      (Self   : in out T_Account;
>       AB     : in out T_Balance;
>       Amount : in     T_Money);
> 
> My hope was that it gets dispatched to the right operation on Self which in turns will call the right operation on AB.  But the compiler seems not to agree.

Ada has only single dispatch, so an operation can only be a primitive operation
of a single tagged type (the "controlling" type).

In Ada, neither the parameter name (Self) nor the position of the parameter in
the parameter list determine the type for which an operation of a tagged type
dispatches. Instead, it dispatches on the parameter of a tagged type for which
it is a primitive operation. [A primitive operation is declared in the same
declarative part as the type (usually a pkg spec).]

Since here you have 2 tagged types in the same declarative part, this operation
is primitive for both, which violates the Ada rule. Note that in the standard
containers, type Cursor is not tagged for precisely this reason: They need
operations that take both a container and a cursor as parameters.

The standard approach to this is to put each tagged type in a separate pkg:

package Balances is
   type Balance_Info is ...

   procedure Op (Balance : in out Balance_Info);
end Balances;

with Balances;
package Accounts is
   type Account_Info is ...

   procedure Op
      (Account : in out Account_Info; Balance : in out Balances.Balance_Info);
end Accounts;

Another approach is to make one parameter classwide; then it is primitive for
only one tagged type:

procedure Op
   (Account : in out Account_Info; Balance : in out Balance_Info'Class);

A third possibility is to make the operation non-primitive by putting it in a
different declarative part:

package Non_Primitive is
   procedure Op
      (Account : in out Account_Info; Balance : in out Balance_Info);
end Non_Primitive;

A fourth approach is to make one of the types non-tagged, as with Cursor in the
containers.

A fifth approach is to make all types non-tagged. This approach causes the
fewest problems.

> class account {
> public:
> 	account_id id;
> 	account_name name;
>         money total_balance;
> 	balance_list balances;
> 
> 	account();
> 	virtual ~account();
> 
> 	void update_balance (account_balance& ab, money amount);

This is a primitive operation of type account (to use the Ada terminology)
because it occurs in account's class structure. Ada has a somewhat idiosyncratic
syntax for programming by extension.

> };

-- 
Jeff Carter
"Now look, Col. Batguano, if that really is your name."
Dr. Strangelove
31


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

* Re: operation can be dispatching in only one type
  2015-11-23 17:40 ` Jeffrey R. Carter
@ 2015-11-24  9:08   ` Serge Robyns
  2015-11-24 16:44     ` AdaMagica
  2015-11-24 17:09     ` Jeffrey R. Carter
  0 siblings, 2 replies; 132+ messages in thread
From: Serge Robyns @ 2015-11-24  9:08 UTC (permalink / raw)


On Monday, 23 November 2015 18:40:57 UTC+1, Jeffrey R. Carter  wrote:
> On 11/23/2015 03:23 AM, Serge Robyns wrote:
> > 
> Ada has only single dispatch, so an operation can only be a primitive operation
> of a single tagged type (the "controlling" type).

That's fine as you must have noticed.

> 
> In Ada, neither the parameter name (Self) nor the position of the parameter in
> the parameter list determine the type for which an operation of a tagged type
> dispatches. Instead, it dispatches on the parameter of a tagged type for which
> it is a primitive operation. [A primitive operation is declared in the same
> declarative part as the type (usually a pkg spec).]

I didn't know about the position, I honestly believed it had to be the 1st. I don't know where I read that.  Anyway I'm reading now the A-LRM 2012.  I'm using "Self" as a naming convention.

> Since here you have 2 tagged types in the same declarative part, this operation
> is primitive for both, which violates the Ada rule. Note that in the standard
> containers, type Cursor is not tagged for precisely this reason: They need
> operations that take both a container and a cursor as parameters.
> 
> The standard approach to this is to put each tagged type in a separate pkg:

I though that packaging and typing were quite independent and hence this is why I merged these two types in one package as they form a coherent assembly.  I also recall some "advertisement" about that "fact".  But it seems not to be that fully true.

> Another approach is to make one parameter classwide; then it is primitive for
> only one tagged type:

Yep, learned about that in a previous post.

> A fourth approach is to make one of the types non-tagged, as with Cursor in the
> containers.
> 
> A fifth approach is to make all types non-tagged. This approach causes the
> fewest problems.
> 
> This is a primitive operation of type account (to use the Ada terminology)
> because it occurs in account's class structure. Ada has a somewhat idiosyncratic
> syntax for programming by extension.
> 

This is what I did in the end.  The only OO feature I'm now using is DAO in the business logic part of the application.  It really works very well and it is clean to read.  However it would have been nice not to have do abandon tagged types in general because of the issues above.  This is my biggest "disappointment".  I'm not in the camp of everything has to be an object but here I would love to have my main "business" objects be implemented as tagged types.  Like for example creating new specialized versions of the T_Account and per the rules you can only write "type New_T is new Old_T" for tagged types.  I'm fully convinced about Ada's code quality and reliability but I'm wondering if these types of issues are not what keeps Ada "locked" into its current niche and failing to gain attraction.

This is where it "transpires" that tagged types came in Ada95 and that backwards compatibility with Ada85 is giving hard time.  I recall reading about the issues of controlled tagged types.

Now, other languages have their own issues.  When I'm reading about C++ templates it can become really hard.  Yesterday I've been trying to figuring out about C++ type traits and how they are constructed.  Everything except readable if you ask my opinion.

Serge


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

* Re: operation can be dispatching in only one type
  2015-11-24  9:08   ` Serge Robyns
@ 2015-11-24 16:44     ` AdaMagica
  2015-11-24 17:09     ` Jeffrey R. Carter
  1 sibling, 0 replies; 132+ messages in thread
From: AdaMagica @ 2015-11-24 16:44 UTC (permalink / raw)


Am Dienstag, 24. November 2015 10:08:07 UTC+1 schrieb Serge Robyns:

> > In Ada, neither the parameter name (Self) nor the position of the parameter in
> > the parameter list determine the type for which an operation of a tagged type
> > dispatches. Instead, it dispatches on the parameter of a tagged type for which
> > it is a primitive operation. [A primitive operation is declared in the same
> > declarative part as the type (usually a pkg spec).]
> 
> I didn't know about the position, I honestly believed it had to be the 1st. I don't know where I read that.  Anyway I'm reading now the A-LRM 2012.  I'm using "Self" as a naming convention.

If you want to use prefix notation Obj.Op, then Obj has to be the first parameter.

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

* Re: operation can be dispatching in only one type
  2015-11-24  9:08   ` Serge Robyns
  2015-11-24 16:44     ` AdaMagica
@ 2015-11-24 17:09     ` Jeffrey R. Carter
  2015-11-24 18:37       ` Serge Robyns
  2015-11-24 20:25       ` Niklas Holsti
  1 sibling, 2 replies; 132+ messages in thread
From: Jeffrey R. Carter @ 2015-11-24 17:09 UTC (permalink / raw)


On 11/24/2015 02:08 AM, Serge Robyns wrote:
> 
> I didn't know about the position, I honestly believed it had to be the 1st. I don't know where I read that.  Anyway I'm reading now the A-LRM 2012.  I'm using "Self" as a naming convention.

Dispatching is described in ARM 3.9.2(2/3). Note that a function call can
dispatch on its result type.

> I though that packaging and typing were quite independent and hence this is why I merged these two types in one package as they form a coherent assembly.  I also recall some "advertisement" about that "fact".  But it seems not to be that fully true.

What is called a "class" in most languages (other than Ada) involves a type
declaration (a set of values and a set of operations on those values),
encapsulation of the value and its operations, and information hiding of the
implementation of the values. In Ada, the pkg provides encapsulation and
information hiding, independent of the mechanisms for declaring types. To get
the equivalent of a "class" in Ada one must put the type and operation
declarations into a pkg. Pkgs, unlike "classes", are intended to be used for
other things as well.

Note that the Ada construct that most closely matches a "class" is a protected type.

> Like for example creating new specialized versions of the T_Account and per the rules you can only write "type New_T is new Old_T" for tagged types.

I'm not sure what you're saying here, but one can derive a new type from any
type, not just tagged types. This existed in Ada 83:

type George is new Integer [range Low .. High];

The Ada-95 designers built on that to provide type extension:

type George is new Martha with record ...

The only thing you *need* tagged types for in Ada is finalization. They also
provide Object.Operation notation, which is nice, and many types are declared
tagged solely to provide that (the containers are examples of this). Type
extension, combined with a container, also provides a kind of syntactic noise
that allows self-referential types without access types/values.

Other than those uses, with adequate thought before beginning coding, one can
implement anything more clearly without tagged types than with.

-- 
Jeff Carter
"Whatever it is, I'm against it."
Horse Feathers
46


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

* Re: operation can be dispatching in only one type
  2015-11-24 17:09     ` Jeffrey R. Carter
@ 2015-11-24 18:37       ` Serge Robyns
  2015-11-24 20:18         ` Jeffrey R. Carter
  2015-11-24 20:25       ` Niklas Holsti
  1 sibling, 1 reply; 132+ messages in thread
From: Serge Robyns @ 2015-11-24 18:37 UTC (permalink / raw)


On Tuesday, 24 November 2015 18:09:14 UTC+1, Jeffrey R. Carter  wrote:

> > Like for example creating new specialized versions of the T_Account and per the rules you can only write "type New_T is new Old_T" for tagged types.
> 
> The Ada-95 designers built on that to provide type extension:
> 
> type George is new Martha with record ...

This is what I get with gnat2015:
type derived from untagged type cannot have extension

for:
   type T_Control is record
      Name : T_Control_Name;
   end record;

   type T_Counter_Control is new T_Control with record
            Counter : Natural;
   end record;

PS: T_Control_Name is a type derived straight from T_Strings_20.Bounded_String (instance of the generic package) in case this should matter but I believe not.

> The only thing you *need* tagged types for in Ada is finalization. They also
> provide Object.Operation notation, which is nice, and many types are declared
> tagged solely to provide that (the containers are examples of this). Type
> extension, combined with a container, also provides a kind of syntactic noise
> that allows self-referential types without access types/values.
> 
> Other than those uses, with adequate thought before beginning coding, one can
> implement anything more clearly without tagged types than with.

I agree and so far the need is limited.  However I do love the obj.method notation which was my initial reason for using tagged types everywhere.  And I do expect needs on the business objects, like indeed finalization and a few specializations.  True back in the 80's we did those 'tricks' without any OO language.  Hence facing such issues now will avoid me to re-design the whole thing later on because of an oversight due to lack of Ada experience.  This is my biggest fear for me; to pursue my project in Ada rather than to go more for my older friends.  I'm more the guy that should read Ada for the C programmer with some experience in old C++ and Java.  And besides this group, I know no one using Ada.

Serge


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

* Re: operation can be dispatching in only one type
  2015-11-24 18:37       ` Serge Robyns
@ 2015-11-24 20:18         ` Jeffrey R. Carter
  2015-11-24 20:40           ` Serge Robyns
  0 siblings, 1 reply; 132+ messages in thread
From: Jeffrey R. Carter @ 2015-11-24 20:18 UTC (permalink / raw)


On 11/24/2015 11:37 AM, Serge Robyns wrote:
> 
> This is what I get with gnat2015:
> type derived from untagged type cannot have extension
> 
> for:
>    type T_Control is record
>       Name : T_Control_Name;
>    end record;
> 
>    type T_Counter_Control is new T_Control with record
>             Counter : Natural;
>    end record;

Yes, only a tagged type can be extended (and any derivation from a tagged type
requires an extension), but a new type can be derived from any type:

type Control_Info is record
   Active : Boolean;
end record;

type External_Control is new Control_Info;
for External_Control use record
   Active at 1 range 3 .. 3;
end record;

> 
> I agree and so far the need is limited.  However I do love the obj.method notation which was my initial reason for using tagged types everywhere.  And I do expect needs on the business objects, like indeed finalization and a few specializations.  True back in the 80's we did those 'tricks' without any OO language.  Hence facing such issues now will avoid me to re-design the whole thing later on because of an oversight due to lack of Ada experience.  This is my biggest fear for me; to pursue my project in Ada rather than to go more for my older friends.  I'm more the guy that should read Ada for the C programmer with some experience in old C++ and Java.  And besides this group, I know no one using Ada.

Have you looked at /Ada Distilled/? It is Ada for the experienced programmer.

-- 
Jeff Carter
"Whatever it is, I'm against it."
Horse Feathers
46

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

* Re: operation can be dispatching in only one type
  2015-11-24 17:09     ` Jeffrey R. Carter
  2015-11-24 18:37       ` Serge Robyns
@ 2015-11-24 20:25       ` Niklas Holsti
  2015-11-24 21:48         ` Jeffrey R. Carter
  1 sibling, 1 reply; 132+ messages in thread
From: Niklas Holsti @ 2015-11-24 20:25 UTC (permalink / raw)


On 15-11-24 19:09 , Jeffrey R. Carter wrote:

> Note that the Ada construct that most closely matches a "class" is a protected type.

Huh? What have mutual exclusion and interrupt-handling to do with "class"?

Ok, some languages have "synchronized" classes, mixing the two concepts.

Perhaps you mean that there is a syntactic resemblance, in that the 
operations and data of a protected type are indeed enclosed in dedicated 
"is" .. "end" brackets?

> The only thing you *need* tagged types for in Ada is finalization.

Tagged types and finalization are never "needed" in the Turing sense :-)

I find that tagged types are a huge help in decoupling dependencies 
between packages. The root type (and 'Class type) can often have many 
fewer dependencies than the child types, greatly helping to localize 
cross-package dependencies. YMMV of course.

-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
       .      @       .


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

* Re: operation can be dispatching in only one type
  2015-11-24 20:18         ` Jeffrey R. Carter
@ 2015-11-24 20:40           ` Serge Robyns
  0 siblings, 0 replies; 132+ messages in thread
From: Serge Robyns @ 2015-11-24 20:40 UTC (permalink / raw)


On Tuesday, 24 November 2015 21:18:10 UTC+1, Jeffrey R. Carter  wrote:

> 
> Have you looked at /Ada Distilled/? It is Ada for the experienced programmer.
> 

Yes I did and liked it, I read the version of May this year.  But as I said earlier, I still do "miss" some "particularities".  For 2012 specifics I did read the excellent 2012 rationale PDF's.  Programming in Ada 2012 seems to be an interesting book but it isn't a cheap one.


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

* Re: operation can be dispatching in only one type
  2015-11-24 20:25       ` Niklas Holsti
@ 2015-11-24 21:48         ` Jeffrey R. Carter
  2015-11-25  8:24           ` Dmitry A. Kazakov
  0 siblings, 1 reply; 132+ messages in thread
From: Jeffrey R. Carter @ 2015-11-24 21:48 UTC (permalink / raw)


On 11/24/2015 01:25 PM, Niklas Holsti wrote:
> On 15-11-24 19:09 , Jeffrey R. Carter wrote:
> 
>> Note that the Ada construct that most closely matches a "class" is a protected
>> type.
> 
> Huh? What have mutual exclusion and interrupt-handling to do with "class"?

Nothing.

> Ok, some languages have "synchronized" classes, mixing the two concepts.
> 
> Perhaps you mean that there is a syntactic resemblance, in that the operations
> and data of a protected type are indeed enclosed in dedicated "is" .. "end"
> brackets?

I mean that a protected type defines a set of values and operations on those
values, encapsulates the values and operations, and hides the implementation of
the values.

-- 
Jeff Carter
"Whatever it is, I'm against it."
Horse Feathers
46

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

* Re: operation can be dispatching in only one type
  2015-11-24 21:48         ` Jeffrey R. Carter
@ 2015-11-25  8:24           ` Dmitry A. Kazakov
  2015-11-25 11:22             ` Serge Robyns
  2015-11-25 12:27             ` G.B.
  0 siblings, 2 replies; 132+ messages in thread
From: Dmitry A. Kazakov @ 2015-11-25  8:24 UTC (permalink / raw)


On Tue, 24 Nov 2015 14:48:24 -0700, Jeffrey R. Carter wrote:

> I mean that a protected type defines a set of values and operations on those
> values,

This is a type, not yet a class. BTW, it is not even a proper class-type (a
root type in Ada terms) because you could not derive anything from it.

> encapsulates the values and operations, and hides the implementation of
> the values.

In fact it does not hide the implementation of values. That is one of its
design flaws. The implementation of protected components is mixed with the
interface. It should have had public components with read access acting as
a protected function and write access doing as a protected procedure. The
private components should have been declared in the package's private
section or the package body.

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

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

* Re: operation can be dispatching in only one type
  2015-11-25  8:24           ` Dmitry A. Kazakov
@ 2015-11-25 11:22             ` Serge Robyns
  2015-11-25 17:38               ` Dmitry A. Kazakov
  2015-11-25 12:27             ` G.B.
  1 sibling, 1 reply; 132+ messages in thread
From: Serge Robyns @ 2015-11-25 11:22 UTC (permalink / raw)


On Wednesday, 25 November 2015 09:25:07 UTC+1, Dmitry A. Kazakov  wrote:
> On Tue, 24 Nov 2015 14:48:24 -0700, Jeffrey R. Carter wrote:
> 
> In fact it does not hide the implementation of values. That is one of its
> design flaws. The implementation of protected components is mixed with the
> interface. It should have had public components with read access acting as
> a protected function and write access doing as a protected procedure. The
> private components should have been declared in the package's private
> section or the package body.

I fully agree with you.  This is what I really wanted to have.  However, not all types need to be fully ADT's.  Like in my example an account has a set of properties which may be revealed in the public part.  Why hide them?  Following your logic, we could have "business" objects with well know properties, then inherit from it to create implementation variants for persistent access with getters/setters.  This is how I could use the "Bridge" Design Pattern or "Adapter".  Now, I've used the following construct instead (which is very close to the Bridge pattern.

package Accounts: type T_Account => defines the basic properties and operations.
package Accounts.DAO: type Factory is limited interface => Defines an interface to read/write clients from a "data store" as a child package of accounts.
package Data_Store : type T_Abstract_Date_Store is limited interface Accounts.DAO and Client.DAO and ....; => Assembles all the interfaces in a single interface type.
package Data_Store.In_Memory: type T_Data_Store is limited new T_Abstract_Data_Store with private; => implements an in memory data_store
package Data_Store.SQL: type T_Data_Store is limited new T_Abstract_Data_Store with private; => implements a GNATCOLL.SQL data_store.  I could create a Gnoga version too.  Which I'm seriously considering. This is the beauty of OO.

Now all business functions have to use the DOA functions (getters/setters) to retrieve and update objects.  Initially I was hoping to hide the DAO behind the business object.  Now I've to do the two actions in the business logic: first update T_Account object and then call T_Account.DAO operations to "retrieve" or "store".  After giving it some thought I've accept this as this enable me to have "control" on the moment for the updates, commits and roll-bacls to the "store".

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

* Re: operation can be dispatching in only one type
  2015-11-25  8:24           ` Dmitry A. Kazakov
  2015-11-25 11:22             ` Serge Robyns
@ 2015-11-25 12:27             ` G.B.
  2015-11-25 17:25               ` Dmitry A. Kazakov
  1 sibling, 1 reply; 132+ messages in thread
From: G.B. @ 2015-11-25 12:27 UTC (permalink / raw)


On 25.11.15 09:24, Dmitry A. Kazakov wrote:
> On Tue, 24 Nov 2015 14:48:24 -0700, Jeffrey R. Carter wrote:
>
>> I mean that a protected type defines a set of values and operations on those
>> values,
>
> This is a type, not yet a class. BTW, it is not even a proper class-type (a
> root type in Ada terms) because you could not derive anything from it.
>
>> encapsulates the values and operations, and hides the implementation of
>> the values.
>
> In fact it does not hide the implementation of values.

I understand that for abstraction, you'd use abstraction features
of the language.

    interface_type_definition ::=
      [limited | task | protected | synchronized] interface
         [and interface_list]

That is,

     type Abstraction is protected interface;

     ... operations ...

And then derive a concrete protected type that implements
the interface:

     protected type Concrete is new Abstraction with ...

> That is one of its
> design flaws. The implementation of protected components is mixed with the
> interface.

Every Ada package tends to have "implementation of components"
after "private",  such as a full type definition? That's a long
standing flaw then, justified by separate compilation needing
full types.

> It should have had public components with read access acting as
> a protected function and write access doing as a protected procedure. The
> private components should have been declared in the package's private
> section or the package body.

That seems approximately possible, I think, even when it is not
formally possible:


package Approx is

    type Opaque is private;
    Initial_Value : constant Opaque;

    protected type P is
       entry E1;
       function F1 return Boolean;
    private
       Data : Opaque := Initial_Value;
    end P;

private
    type Index is range 1 .. 10;
    type Opaque is array (Index) of Boolean;
    Initial_Value : constant Opaque := (others => False);
end Approx;

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

* Re: operation can be dispatching in only one type
  2015-11-25 12:27             ` G.B.
@ 2015-11-25 17:25               ` Dmitry A. Kazakov
  0 siblings, 0 replies; 132+ messages in thread
From: Dmitry A. Kazakov @ 2015-11-25 17:25 UTC (permalink / raw)


On Wed, 25 Nov 2015 13:27:08 +0100, G.B. wrote:

> Every Ada package tends to have "implementation of components"
> after "private",  such as a full type definition? That's a long
> standing flaw then, justified by separate compilation needing
> full types.

It is a flaw only when using nested packages:

package P is
   package Q is
       ...
   private -- This should not appear here
       ...
   end Q;
private
   ...
end P;

Should have been sort of

package P is
   package Q is
       ...
   end Q;
private
   private package Q is
       ...
   end Q;
   ...
end P;

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


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

* Re: operation can be dispatching in only one type
  2015-11-25 11:22             ` Serge Robyns
@ 2015-11-25 17:38               ` Dmitry A. Kazakov
  2015-11-26 11:30                 ` Serge Robyns
  0 siblings, 1 reply; 132+ messages in thread
From: Dmitry A. Kazakov @ 2015-11-25 17:38 UTC (permalink / raw)


On Wed, 25 Nov 2015 03:22:57 -0800 (PST), Serge Robyns wrote:

> However, not all types need to be fully ADT's.

They are. If you don't define operations, the compiler does anyway.

> Like in my example an
> account has a set of properties which may be revealed in the public part. 
> Why hide them?

Nobody asked that. What you call "property" is certainly an operation of
the ADT generated by the compiler. If you had

   type T is record
       X : ...
   end record;

That would implicitly declare among others the operations to access the
member X, i.e. a getter T.X and a setter T.X.

> Following your logic, we could have "business" objects
> with well know properties, then inherit from it to create implementation
> variants for persistent access with getters/setters.

Alas, you cannot override operations of built-in interfaces. It is an Ada
83 heritage.

> Now all business functions have to use the DOA functions (getters/setters)
> to retrieve and update objects.  Initially I was hoping to hide the DAO
> behind the business object.  Now I've to do the two actions in the
> business logic: first update T_Account object and then call T_Account.DAO
> operations to "retrieve" or "store".  After giving it some thought I've
> accept this as this enable me to have "control" on the moment for the
> updates, commits and roll-bacls to the "store".

The object is a proxy to a persistent object. It is OK to update the proxy
without committing changes to the persistent counterpart. But note that you
still want to extend compiler-generated setters. E.g. for marking the proxy
object out-of-sync. Thus when a transaction is getting committed the
connection handler would store all updated objects.

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


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

* Re: operation can be dispatching in only one type
  2015-11-25 17:38               ` Dmitry A. Kazakov
@ 2015-11-26 11:30                 ` Serge Robyns
  2015-11-26 13:14                   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 132+ messages in thread
From: Serge Robyns @ 2015-11-26 11:30 UTC (permalink / raw)


Dmitry,

On Wednesday, 25 November 2015 18:38:53 UTC+1, Dmitry A. Kazakov  wrote:
> The object is a proxy to a persistent object. It is OK to update the proxy
> without committing changes to the persistent counterpart. But note that you
> still want to extend compiler-generated setters. E.g. for marking the proxy
> object out-of-sync. Thus when a transaction is getting committed the
> connection handler would store all updated objects.

Can you please elaborate what you mean by a "compiler-generated" setter?  Because from what I do understand from your explanation about marking the proxy is something I'm looking for and maybe to far while it's right under my nose.

Serge


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

* Re: operation can be dispatching in only one type
  2015-11-26 11:30                 ` Serge Robyns
@ 2015-11-26 13:14                   ` Dmitry A. Kazakov
  2015-11-26 14:27                     ` Serge Robyns
  2015-11-29 17:59                     ` Jacob Sparre Andersen
  0 siblings, 2 replies; 132+ messages in thread
From: Dmitry A. Kazakov @ 2015-11-26 13:14 UTC (permalink / raw)


On Thu, 26 Nov 2015 03:30:09 -0800 (PST), Serge Robyns wrote:

> On Wednesday, 25 November 2015 18:38:53 UTC+1, Dmitry A. Kazakov  wrote:
>> The object is a proxy to a persistent object. It is OK to update the proxy
>> without committing changes to the persistent counterpart. But note that you
>> still want to extend compiler-generated setters. E.g. for marking the proxy
>> object out-of-sync. Thus when a transaction is getting committed the
>> connection handler would store all updated objects.
> 
> Can you please elaborate what you mean by a "compiler-generated" setter? 
> Because from what I do understand from your explanation about marking the
> proxy is something I'm looking for and maybe to far while it's right under
> my nose.

type T is record
   X : Integer;
end record;

The compiler generated setter is something like inventing Ada-like
notation:

   procedure ".X" (Left : in out T; Right : Integer);

Called as follows:

   Y : T;
begin
   Y.X := 10;

If Ada were a better language you could override getters/setters and
provide your own implementation:

   type T is private record -- This is not Ada!
      X : Integer;
   end record;
private
   type T is new DB.Handle with null record; -- No Integer members!
   procedure ".X" (Left : in out T; Right : Integer);
   function ".X" (Left : T) return Integer);
 
P.S. Surely, at some point there would a kludge invented with aspects as it
was done for array indexing...

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

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

* Re: operation can be dispatching in only one type
  2015-11-26 13:14                   ` Dmitry A. Kazakov
@ 2015-11-26 14:27                     ` Serge Robyns
  2015-11-26 15:16                       ` J-P. Rosen
  2015-11-29 17:59                     ` Jacob Sparre Andersen
  1 sibling, 1 reply; 132+ messages in thread
From: Serge Robyns @ 2015-11-26 14:27 UTC (permalink / raw)


On Thursday, 26 November 2015 14:15:01 UTC+1, Dmitry A. Kazakov  wrote:
> If Ada were a better language you could override getters/setters and
> provide your own implementation:
> 
>    type T is private record -- This is not Ada!
>       X : Integer;
>    end record;
> private
>    type T is new DB.Handle with null record; -- No Integer members!
>    procedure ".X" (Left : in out T; Right : Integer);
>    function ".X" (Left : T) return Integer);
>  
> P.S. Surely, at some point there would a kludge invented with aspects as it
> was done for array indexing...

Got you.  Yes that would be nice but my need is current :-(
I agree that this would be a marvelous enhancement.  We could write code as below with the ability to "override" T.X function and procedure and also inherit it from parent types like when implementing interfaces.  type T_Stored is new T and T_DOA;
A : T;
...
A.X := 10;
...
if A.X /= 10 then
   null;
end if;


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

* Re: operation can be dispatching in only one type
  2015-11-26 14:27                     ` Serge Robyns
@ 2015-11-26 15:16                       ` J-P. Rosen
  2015-11-26 18:27                         ` Serge Robyns
  0 siblings, 1 reply; 132+ messages in thread
From: J-P. Rosen @ 2015-11-26 15:16 UTC (permalink / raw)


Le 26/11/2015 15:27, Serge Robyns a écrit :
> n Thursday, 26 November 2015 14:15:01 UTC+1, Dmitry A. Kazakov  wrote:
>> > If Ada were a better language you could override getters/setters and
>> > provide your own implementation:
>> > 
>> >    type T is private record -- This is not Ada!
>> >       X : Integer;
>> >    end record;
>> > private
>> >    type T is new DB.Handle with null record; -- No Integer members!
>> >    procedure ".X" (Left : in out T; Right : Integer);
>> >    function ".X" (Left : T) return Integer);
>> >  
>> > P.S. Surely, at some point there would a kludge invented with aspects as it
>> > was done for array indexing...
> Got you.  Yes that would be nice but my need is current :-(
> I agree that this would be a marvelous enhancement.

Nothing marvelous, just saving keystrokes. You can always make a private
type and explicit subprograms to access "virtual" components.


-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr

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

* Re: operation can be dispatching in only one type
  2015-11-26 15:16                       ` J-P. Rosen
@ 2015-11-26 18:27                         ` Serge Robyns
  2015-11-26 21:20                           ` J-P. Rosen
  0 siblings, 1 reply; 132+ messages in thread
From: Serge Robyns @ 2015-11-26 18:27 UTC (permalink / raw)


On Thursday, 26 November 2015 16:16:34 UTC+1, J-P. Rosen  wrote:
unction ".X" (Left : T) return Integer);
> >> >  
> >> > P.S. Surely, at some point there would a kludge invented with aspects as it
> >> > was done for array indexing...
> > Got you.  Yes that would be nice but my need is current :-(
> > I agree that this would be a marvelous enhancement.
> 
> Nothing marvelous, just saving keystrokes. You can always make a private
> type and explicit subprograms to access "virtual" components.
> 

Isn't the purpose of higher programming languages not to save keystrokes, simplifying abstractions, enabling more powerful algorithms to be expressed directly?  My first language was assembly language.  I've been programming 100K's of code and could literally do whatever I wanted, even change the OS behavior through hooking into or jumping at very specific places inside the OS ROM.  I felt very mighty, my code was actually very readable and I was a very fast programmer on top of that.  But it took always more effort to build or call a callable subroutine than just using high level programming language, I had to take care of building a stack, fill the right values into the right registers, recover return values, etc. where as otherwise I could just write I := Integer'Value(S);

True, assembly isn't portable but if this is the only purpose then we would have stick to "simple" languages such BCPL for example.  C would never have appeared, Ada would not have been invented nor Smalltalk and the list is almost endless.


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

* Re: operation can be dispatching in only one type
  2015-11-26 18:27                         ` Serge Robyns
@ 2015-11-26 21:20                           ` J-P. Rosen
  2015-11-27  8:37                             ` Dmitry A. Kazakov
  0 siblings, 1 reply; 132+ messages in thread
From: J-P. Rosen @ 2015-11-26 21:20 UTC (permalink / raw)


Le 26/11/2015 19:27, Serge Robyns a écrit :
> Isn't the purpose of higher programming languages not to save
> keystrokes, simplifying abstractions, enabling more powerful
> algorithms to be expressed directly?
Sure, but here the proposal is to offer the same functionality, with a
different syntax. It may be more pleasant, but it's not higher level.
That's what is called syntactic sugar. (Sugar is pleasant, isn't it? But
not in my coffee, no thanks ;-) )

-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr

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

* Re: operation can be dispatching in only one type
  2015-11-26 21:20                           ` J-P. Rosen
@ 2015-11-27  8:37                             ` Dmitry A. Kazakov
  2015-11-27 12:58                               ` J-P. Rosen
  0 siblings, 1 reply; 132+ messages in thread
From: Dmitry A. Kazakov @ 2015-11-27  8:37 UTC (permalink / raw)


On Thu, 26 Nov 2015 22:20:41 +0100, J-P. Rosen wrote:

> Le 26/11/2015 19:27, Serge Robyns a écrit :
>> Isn't the purpose of higher programming languages not to save
>> keystrokes, simplifying abstractions, enabling more powerful
>> algorithms to be expressed directly?
> Sure, but here the proposal is to offer the same functionality, with a
> different syntax. It may be more pleasant, but it's not higher level.

It is higher level because it introduces an abstract record interface. It
also supports separation of interface and implementation which built-in
record types fail to provide. And it would make the language type system
more regular. Usual claims of separation OO language parts from non-OO
parts is nonsense. There is no such thing, but reasonably designed types
and compiler-magic assisted kludges.

> That's what is called syntactic sugar. (Sugar is pleasant, isn't it? But
> not in my coffee, no thanks ;-) )

Why do you use record types at all? It surely is just sugar dust put on a
memory chunk. You certainly could declare Get and Set operations to extract
and set members at the specified memory offsets. No?

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


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

* Re: operation can be dispatching in only one type
  2015-11-27  8:37                             ` Dmitry A. Kazakov
@ 2015-11-27 12:58                               ` J-P. Rosen
  2015-11-27 13:39                                 ` Dmitry A. Kazakov
  0 siblings, 1 reply; 132+ messages in thread
From: J-P. Rosen @ 2015-11-27 12:58 UTC (permalink / raw)


Le 27/11/2015 09:37, Dmitry A. Kazakov a écrit :
>> That's what is called syntactic sugar. (Sugar is pleasant, isn't it? But
>> > not in my coffee, no thanks ;-) )
> Why do you use record types at all? It surely is just sugar dust put on a
> memory chunk. You certainly could declare Get and Set operations to extract
> and set members at the specified memory offsets. No?
1) For types not exported by packages
2) For types exported by packages where you want the structure to be
public, like information returned by queries. You don't always need to
hide information.

And when a construct provides higher abstraction level, it is NOT
syntactic sugar. A record provides typing and controls over raw memory.

-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr


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

* Re: operation can be dispatching in only one type
  2015-11-27 12:58                               ` J-P. Rosen
@ 2015-11-27 13:39                                 ` Dmitry A. Kazakov
  2015-11-30 22:22                                   ` Randy Brukardt
  0 siblings, 1 reply; 132+ messages in thread
From: Dmitry A. Kazakov @ 2015-11-27 13:39 UTC (permalink / raw)


On Fri, 27 Nov 2015 13:58:32 +0100, J-P. Rosen wrote:

> Le 27/11/2015 09:37, Dmitry A. Kazakov a écrit :
>>> That's what is called syntactic sugar. (Sugar is pleasant, isn't it? But
>>> > not in my coffee, no thanks ;-) )
>> Why do you use record types at all? It surely is just sugar dust put on a
>> memory chunk. You certainly could declare Get and Set operations to extract
>> and set members at the specified memory offsets. No?
> 1) For types not exported by packages
> 2) For types exported by packages where you want the structure to be
> public, like information returned by queries. You don't always need to
> hide information.

But when I need I must be able to do it.

> And when a construct provides higher abstraction level, it is NOT
> syntactic sugar. A record provides typing and controls over raw memory.

q.e.d.

1. Raw memory is an implementation detail. A record could provide all that
for a lot of things beyond raw memory.

2. What makes you think that the compiler always knows better how to
control raw memory?

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

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

* Re: operation can be dispatching in only one type
  2015-11-26 13:14                   ` Dmitry A. Kazakov
  2015-11-26 14:27                     ` Serge Robyns
@ 2015-11-29 17:59                     ` Jacob Sparre Andersen
  2015-11-30 22:29                       ` Randy Brukardt
  1 sibling, 1 reply; 132+ messages in thread
From: Jacob Sparre Andersen @ 2015-11-29 17:59 UTC (permalink / raw)


Dmitry A. Kazakov wrote:

> type T is record
>    X : Integer;
> end record;
>
> The compiler generated setter is something like inventing Ada-like
> notation:
>
>    procedure ".X" (Left : in out T; Right : Integer);
>
> Called as follows:
>
>    Y : T;
> begin
>    Y.X := 10;

Wouldn't it be much easier to add the simple bit of syntactic sugar
saying that given:

   procedure Setter (Object : in out T;
                     Field  : in     U);

For a variable object, V, of (a tagged) type T, and an expression, E, of
type U, the statement:

   V.Setter := E;

is equivalent to the statement:

   V.Setter (E);

(Not because it is shorter - it isn't - but because it nicely mirrors
 matching "getter" functions, and because it makes it clear that the
 procedure call copies a value into an object and modifies it.)

Greetings,

Jacob
-- 
Those who can't laugh at themselves leave the job to others.

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

* Re: operation can be dispatching in only one type
  2015-11-27 13:39                                 ` Dmitry A. Kazakov
@ 2015-11-30 22:22                                   ` Randy Brukardt
  2015-12-01  8:46                                     ` Dmitry A. Kazakov
  0 siblings, 1 reply; 132+ messages in thread
From: Randy Brukardt @ 2015-11-30 22:22 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:11das66l3vhic$.1stkau3dqp6ld.dlg@40tude.net...
...
> 2. What makes you think that the compiler always knows better how to
> control raw memory?

Because it's true?? :-)

In an ideal world (with an ideal programming language), the compiler always 
knows far more than the programmer about the target, the access patterns, 
and so on. To the extent that there is information that the compiler doesn't 
have, the focus should be on giving it that information, not on telling it 
what to do. (For instance, it is better to tell a compiler which subprograms 
are "hot" than to tell it that it must inline certain subprograms --  
inlining is just one possibly way of improving the performance and the 
compiler is in a better position to juggle the trade-offs than any 
programmer could be. That's one of the reasons that just-in-time compilation 
produces better performance than one would imagine just based on 
traditionally compiling individual subprograms.)

In the real world, of course, there are limitations on compilation time, 
execution information, and so on, but it still is the case that it is rare 
that a programmer can really do better at these things (especially at the 
"raw memory" level) than a decent compiler. That's why it's unfortunate that 
most programming languages (and Ada is no exception) focus too much on 
features that can be implemented easily and less on improving abstraction. 
(But of course, get too fancy and the features can't be implemented 
efficiently at all, which defeats the purpose.)

                                    Randy.



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

* Re: operation can be dispatching in only one type
  2015-11-29 17:59                     ` Jacob Sparre Andersen
@ 2015-11-30 22:29                       ` Randy Brukardt
  0 siblings, 0 replies; 132+ messages in thread
From: Randy Brukardt @ 2015-11-30 22:29 UTC (permalink / raw)


"Jacob Sparre Andersen" <sparre@nbi.dk> wrote in message 
news:87two4d6uk.fsf@adaheads.sparre-andersen.dk...
> Dmitry A. Kazakov wrote:
>
>> type T is record
>>    X : Integer;
>> end record;
>>
>> The compiler generated setter is something like inventing Ada-like
>> notation:
>>
>>    procedure ".X" (Left : in out T; Right : Integer);
>>
>> Called as follows:
>>
>>    Y : T;
>> begin
>>    Y.X := 10;
>
> Wouldn't it be much easier to add the simple bit of syntactic sugar
> saying that given:
>
>   procedure Setter (Object : in out T;
>                     Field  : in     U);
>
> For a variable object, V, of (a tagged) type T, and an expression, E, of
> type U, the statement:
>
>   V.Setter := E;
>
> is equivalent to the statement:
>
>   V.Setter (E);
>
> (Not because it is shorter - it isn't - but because it nicely mirrors
> matching "getter" functions, and because it makes it clear that the
> procedure call copies a value into an object and modifies it.)

Certainly. That's what Dmitry meant when he said "... a kludge invented with 
aspects ...". We can argue just how kludgy it really is (a user-defined 
anything ultimately maps into a subprogram call, after all, and the syntax 
of a call isn't engraved in stone), but I think Dmitry has an ideal vision 
where all of these sorts of operations are given the same first-class level. 
That won't ever happen for Ada, but it might make sense for a new language 
design.

                                 Randy.



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

* Re: operation can be dispatching in only one type
  2015-11-30 22:22                                   ` Randy Brukardt
@ 2015-12-01  8:46                                     ` Dmitry A. Kazakov
  2015-12-01 11:19                                       ` G.B.
  2015-12-02 19:27                                       ` Randy Brukardt
  0 siblings, 2 replies; 132+ messages in thread
From: Dmitry A. Kazakov @ 2015-12-01  8:46 UTC (permalink / raw)


On Mon, 30 Nov 2015 16:22:12 -0600, Randy Brukardt wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
> news:11das66l3vhic$.1stkau3dqp6ld.dlg@40tude.net...
> ...
>> 2. What makes you think that the compiler always knows better how to
>> control raw memory?
> 
> Because it's true?? :-)
> 
> In an ideal world (with an ideal programming language), the compiler always 
> knows far more than the programmer about the target,

In most cases yes. But note you focused on the hardware here. Even with
hardware, the compiler knows nothing about the layout of a packet from some
I/O protocol. Countless requests here in c.l.a. concerning instructing the
compiler to do it right is a proof.

But when it becomes the problem space the compiler knows absolutely nothing
about handling proxy objects located in the memory. A row of a DB record
result set is a record for which the compiler has no slightest idea how to
map it (onto the DB environment, connection, cursor).

> To the extent that there is information that the compiler doesn't 
> have, the focus should be on giving it that information, not on telling it 
> what to do. (For instance, it is better to tell a compiler which subprograms 
> are "hot" than to tell it that it must inline certain subprograms --  
> inlining is just one possibly way of improving the performance and the 
> compiler is in a better position to juggle the trade-offs than any 
> programmer could be. That's one of the reasons that just-in-time compilation 
> produces better performance than one would imagine just based on 
> traditionally compiling individual subprograms.)

Not exactly. It is true when we talk about non-functional requirements and
wrong for the functional ones. The example with inlining works because it
is non-functional.

> In the real world, of course, there are limitations on compilation time, 
> execution information, and so on, but it still is the case that it is rare 
> that a programmer can really do better at these things (especially at the 
> "raw memory" level) than a decent compiler. That's why it's unfortunate that 
> most programming languages (and Ada is no exception) focus too much on 
> features that can be implemented easily and less on improving abstraction. 

There is no contradiction in providing simple building blocks for higher
level abstractions. There is no reason why indexing or record member access
should be less efficient when a user-defined implementation allowed, but
not actually used.

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

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

* Re: operation can be dispatching in only one type
  2015-12-01  8:46                                     ` Dmitry A. Kazakov
@ 2015-12-01 11:19                                       ` G.B.
  2015-12-01 13:56                                         ` Dmitry A. Kazakov
  2015-12-02 19:27                                       ` Randy Brukardt
  1 sibling, 1 reply; 132+ messages in thread
From: G.B. @ 2015-12-01 11:19 UTC (permalink / raw)


On 01.12.15 09:46, Dmitry A. Kazakov wrote:
> On Mon, 30 Nov 2015 16:22:12 -0600, Randy Brukardt wrote:
>
> some
> I/O protocol. Countless requests here in c.l.a. concerning instructing the
> compiler to do it right is a proof.
>
> But when it becomes the problem space the compiler knows absolutely nothing
> about handling proxy objects located in the memory. A row of a DB record
> result set is a record for which the compiler has no slightest idea how to
> map it (onto the DB environment, connection, cursor).

Compiler vendors convincing the bosses of the database vending
families to agree on giving up control over I/O and representation,
now that will be quite something! ;-)

> There is no reason why indexing or record member access
> should be less efficient when a user-defined implementation allowed, but
> not actually used.

Sounds a bit like user defined aspects of compilation? What
guarantees would the compiler be able to generate that user
defined mechanics will work at the same level of assurance
as that of "regular" records?

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

* Re: operation can be dispatching in only one type
  2015-12-01 11:19                                       ` G.B.
@ 2015-12-01 13:56                                         ` Dmitry A. Kazakov
  2015-12-01 16:05                                           ` G.B.
  2015-12-02 19:33                                           ` Randy Brukardt
  0 siblings, 2 replies; 132+ messages in thread
From: Dmitry A. Kazakov @ 2015-12-01 13:56 UTC (permalink / raw)


On Tue, 1 Dec 2015 12:19:02 +0100, G.B. wrote:

> On 01.12.15 09:46, Dmitry A. Kazakov wrote:

>> There is no reason why indexing or record member access
>> should be less efficient when a user-defined implementation allowed, but
>> not actually used.
> 
> Sounds a bit like user defined aspects of compilation?

It is not an aspect. Aspect is a view, characteristic, feature:

http://www.thefreedictionary.com/aspect

It means that aspect may not change the semantics.

User-defined operation is exactly the opposite. It does not change the
view. The object is still viewed as an array or a record. It is the
semantics that gets changed.

This is also what is wrong with the aspect approach in general. From the
software design point of view it implies that you add a view to something
already existing, already designed in its own way, a cherry on the top.
That is either a wrong way to design software or else a superfluous thing.
I suspect that creators of aspects considered the latter, as something
unserious. The end users do it as the former, which results in poor design.

> What
> guarantees would the compiler be able to generate that user
> defined mechanics will work at the same level of assurance
> as that of "regular" records?

Generated guaranties? You lost me here.

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

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

* Re: operation can be dispatching in only one type
  2015-12-01 13:56                                         ` Dmitry A. Kazakov
@ 2015-12-01 16:05                                           ` G.B.
  2015-12-01 17:58                                             ` Dmitry A. Kazakov
  2015-12-02 19:33                                           ` Randy Brukardt
  1 sibling, 1 reply; 132+ messages in thread
From: G.B. @ 2015-12-01 16:05 UTC (permalink / raw)


On 01.12.15 14:56, Dmitry A. Kazakov wrote:
> On Tue, 1 Dec 2015 12:19:02 +0100, G.B. wrote:
>
>> On 01.12.15 09:46, Dmitry A. Kazakov wrote:
>
>>> There is no reason why indexing or record member access
>>> should be less efficient when a user-defined implementation allowed, but
>>> not actually used.
>>
>> Sounds a bit like user defined aspects of compilation?
>
> It is not an aspect. Aspect is a view, characteristic, feature:
>
> http://www.thefreedictionary.com/aspect
>
> It means that aspect may not change the semantics.
>
> User-defined operation is exactly the opposite. It does not change the
> view. The object is still viewed as an array or a record. It is the
> semantics that gets changed.

I take it that by "semantics" you mean the simplest meaning
of this word, viz. the operations that happen to become generated
for a ".X" function, say, as a consequence of compilation?

If, however, a user may define what "rec.x" will do, then
this changes an aspect (sic) of compilation: what was previously
defined by the LRM (or would appear to be defined by the
language) does now seem to flow from the job of the programmer,
and becomes a property of the program, as it redefines certain
occurrences of ".".

The compiler now needs to ensure something different when
translating "rec.x".


>> What
>> guarantees would the compiler be able to generate that user
>> defined mechanics will work at the same level of assurance
>> as that of "regular" records?
>
> Generated guaranties? You lost me here.

The current Ada language makes the compiler emit code for "Rec.X"
that is going to have a somewhat predictable effect. It does so
driven by what it the LRM says. That much is a guaranteed outcome.

If users are allowed to change the semantics of "rec.x", then
what level of assurance do we get? We'd take away a basic building
block from the set of unequivocally predictable building blocks.

Is it hubris or are there hidden powers in overloading what now
are non-operators?


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

* Re: operation can be dispatching in only one type
  2015-12-01 16:05                                           ` G.B.
@ 2015-12-01 17:58                                             ` Dmitry A. Kazakov
  2015-12-02 13:06                                               ` G.B.
  0 siblings, 1 reply; 132+ messages in thread
From: Dmitry A. Kazakov @ 2015-12-01 17:58 UTC (permalink / raw)


On Tue, 1 Dec 2015 17:05:28 +0100, in comp.lang.ada you wrote:

> On 01.12.15 14:56, Dmitry A. Kazakov wrote:
>> On Tue, 1 Dec 2015 12:19:02 +0100, G.B. wrote:
>>
>>> On 01.12.15 09:46, Dmitry A. Kazakov wrote:
>>
>>>> There is no reason why indexing or record member access
>>>> should be less efficient when a user-defined implementation allowed, but
>>>> not actually used.
>>>
>>> Sounds a bit like user defined aspects of compilation?
>>
>> It is not an aspect. Aspect is a view, characteristic, feature:
>>
>> http://www.thefreedictionary.com/aspect
>>
>> It means that aspect may not change the semantics.
>>
>> User-defined operation is exactly the opposite. It does not change the
>> view. The object is still viewed as an array or a record. It is the
>> semantics that gets changed.
> 
> I take it that by "semantics" you mean the simplest meaning
> of this word, viz. the operations that happen to become generated
> for a ".X" function, say, as a consequence of compilation?
> 
> If, however, a user may define what "rec.x" will do, then
> this changes an aspect (sic) of compilation: what was previously
> defined by the LRM (or would appear to be defined by the
> language) does now seem to flow from the job of the programmer,
> and becomes a property of the program, as it redefines certain
> occurrences of ".".

Who cares? Less defined by the RM then better. Any predefined semantics is
a necessary evil. If not necessary, then just evil.

> The compiler now needs to ensure something different when
> translating "rec.x".

The compiler needs to ensure what the programmer means (assuming correct
language use)

>>> What
>>> guarantees would the compiler be able to generate that user
>>> defined mechanics will work at the same level of assurance
>>> as that of "regular" records?
>>
>> Generated guaranties? You lost me here.
> 
> The current Ada language makes the compiler emit code for "Rec.X"
> that is going to have a somewhat predictable effect.

It does not make sense. For *any* legal construct the compiler should emit
code with a predictable effect. Otherwise the language is ill-defined.

The correct sentence is probably related to the program readability. That
is up to the programmer and how he expresses the problem space in the
language terms. I don't see how Employee.Salary is less readable,
predictable, etc than Get_Salary(Employee).

> If users are allowed to change the semantics of "rec.x", then
> what level of assurance do we get?

Same level as when the users are allowed to change the semantics of Foo(x),
x+y etc.

> We'd take away a basic building
> block from the set of unequivocally predictable building blocks.

Member extraction/setting operations is not a basic building block.

Oh, I forgot, that you are in the anti-typed camp. So let me explain. There
is *no* free operations. There are only types. The member operation .X is
one of the built-in operations of the built-in record type. You don't loose
it in no way if you allow *other* types have operations named this way or
implementing same abstract interface. If you don't believe me, look at
fully qualified names, they have "." inside. What a horror!

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


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

* Re: operation can be dispatching in only one type
  2015-12-01 17:58                                             ` Dmitry A. Kazakov
@ 2015-12-02 13:06                                               ` G.B.
  2015-12-02 13:31                                                 ` Dmitry A. Kazakov
  0 siblings, 1 reply; 132+ messages in thread
From: G.B. @ 2015-12-02 13:06 UTC (permalink / raw)


On 01.12.15 18:58, Dmitry A. Kazakov wrote:

> Less defined by the RM then better.

(OK, yet, taking this to absurd extremes, the ideal language
would be undefined...)

 > Any predefined semantics is
> a necessary evil. If not necessary, then just evil.

How much predefined semantics is (un)necessary? In what circumstances?

How much less will be more productive? And conducive to correct
use of the language? How? (request for example below)
For example, Apple is making "object properties" (dot notation)
a convenience for connecting them to key-value coding.

>> The compiler now needs to ensure something different when
>> translating "rec.x".
>
> The compiler needs to ensure what the programmer means (assuming correct
> language use)

Right. Also, the programmer might want ways of expressing volatility
of virtual components, of addressing representation issues, etc.
In this regard, could there be a novel approach to protecting
access when defining ".X" instead of defining a plain old prim_op?

> For *any* legal construct the compiler should emit
> code with a predictable effect. Otherwise the language is ill-defined.

Of course, what matters is the kind of predictability that a reviewer
needs in order to check, efficiently, that the compiled code is of
a kind that he could have predicted.  This kind of efficient
predictability suffers the more, I think, the more the programmer
takes hold of defining things.  Unless---which is why I'm asking---
the compiler can still manage to restore predictability in terms that
are language terms of a kind that provide for said efficiency.
So that no need for further study of the program's own definitions
arises.

> I don't see how Employee.Salary is less readable,
> predictable, etc than Get_Salary(Employee).

I'll be fine with ".X" if it offers any real benefit at virtually
no cost. So, how will a record abstraction be usefully different
from a private type?  Can you give an example, say, built around

    procedure Op (X : ...; V : record'Class);  -- (sic)


I'm not opposed to new notations ("Who cares?" applies here ;):
For example, I have often longed for a notation that expresses
message sending. Related to that, in Ada terms, sequential calls
look like concurrent calls. I don't always like that, because in
one sense they are fundamentally different and I may want to state
that they are. Granted, when calls are near "select", context does
suggest "non-sequential".


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

* Re: operation can be dispatching in only one type
  2015-12-02 13:06                                               ` G.B.
@ 2015-12-02 13:31                                                 ` Dmitry A. Kazakov
  0 siblings, 0 replies; 132+ messages in thread
From: Dmitry A. Kazakov @ 2015-12-02 13:31 UTC (permalink / raw)


On Wed, 2 Dec 2015 14:06:04 +0100, G.B. wrote:

> On 01.12.15 18:58, Dmitry A. Kazakov wrote:
> 
>> Less defined by the RM then better.
> 
> (OK, yet, taking this to absurd extremes, the ideal language
> would be undefined...)

It is similar to the minimum set of axioms in a formal system, or a minimal
instruction set, minimal alphabet, minimal numeral set etc. Of course it
does not mean that the ideal language must be minimal. But blown languages
are not ideal either.

>> Any predefined semantics is
>> a necessary evil. If not necessary, then just evil.
> 
> How much predefined semantics is (un)necessary?

The lower boundary is Turing completeness, obviously.

> In what circumstances?
> 
> How much less will be more productive? And conducive to correct
> use of the language? How? (request for example below)
> For example, Apple is making "object properties" (dot notation)
> a convenience for connecting them to key-value coding.

There is some optimum. But anything you could move at the library level and
beyond should be.

>>> The compiler now needs to ensure something different when
>>> translating "rec.x".
>>
>> The compiler needs to ensure what the programmer means (assuming correct
>> language use)
> 
> Right. Also, the programmer might want ways of expressing volatility
> of virtual components, of addressing representation issues, etc.

Syntactically? Probably not. At least not in Ada's way where same syntax is
used for.

> In this regard, could there be a novel approach to protecting
> access when defining ".X" instead of defining a plain old prim_op?

There is nothing specifically "protecting" in dot-syntax. It is used for
all sorts of calls in Ada.

>> For *any* legal construct the compiler should emit
>> code with a predictable effect. Otherwise the language is ill-defined.
> 
> Of course, what matters is the kind of predictability that a reviewer
> needs in order to check, efficiently, that the compiled code is of
> a kind that he could have predicted.

It is not achievable in a higher level language, only in Assembler. Neither
it is required. The reader should understand the semantics and programmer's
intent rather than machine instructions generated.

>> I don't see how Employee.Salary is less readable,
>> predictable, etc than Get_Salary(Employee).
> 
> I'll be fine with ".X" if it offers any real benefit at virtually
> no cost. So, how will a record abstraction be usefully different
> from a private type?

Because in this case Employee is seen as a record in the problem space.

> Can you give an example, say, built around
> 
>     procedure Op (X : ...; V : record'Class);  -- (sic)

Example of what? Of tuples? They are everywhere in almost all problem
spaces. Simply observe that an implementation of tuple need not to be a
record. E.g. Color with RGB , HLS, L*a*b record views.

> For example, I have often longed for a notation that expresses
> message sending.

You should look no further than task interfaces. Granted, they should be
fixed.

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

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

* Re: operation can be dispatching in only one type
  2015-12-01  8:46                                     ` Dmitry A. Kazakov
  2015-12-01 11:19                                       ` G.B.
@ 2015-12-02 19:27                                       ` Randy Brukardt
  1 sibling, 0 replies; 132+ messages in thread
From: Randy Brukardt @ 2015-12-02 19:27 UTC (permalink / raw)



"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:6y03ogx0fsk8$.n0ldd6cud931$.dlg@40tude.net...
> On Mon, 30 Nov 2015 16:22:12 -0600, Randy Brukardt wrote:
...
>> To the extent that there is information that the compiler doesn't
>> have, the focus should be on giving it that information, not on telling 
>> it
>> what to do. (For instance, it is better to tell a compiler which 
>> subprograms
>> are "hot" than to tell it that it must inline certain subprograms --
>> inlining is just one possibly way of improving the performance and the
>> compiler is in a better position to juggle the trade-offs than any
>> programmer could be. That's one of the reasons that just-in-time 
>> compilation
>> produces better performance than one would imagine just based on
>> traditionally compiling individual subprograms.)
>
> Not exactly. It is true when we talk about non-functional requirements and
> wrong for the functional ones. The example with inlining works because it
> is non-functional.

"Functional" requirements are the entire point of the program and of course 
have to be described to the compiler. It's not the compiler's job to guess 
functional requirements! It would be writing your program for you in that 
case, and that only works in very limited circumstances (not for a general 
programming language like Ada). That includes all interfacing to things 
outside of the compiler's universe (that includes all of your other 
examples, such as streaming, DB access, etc.)

After all, it's not "raw memory" if it is involved in functional 
requirements.

                               Randy.


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

* Re: operation can be dispatching in only one type
  2015-12-01 13:56                                         ` Dmitry A. Kazakov
  2015-12-01 16:05                                           ` G.B.
@ 2015-12-02 19:33                                           ` Randy Brukardt
  1 sibling, 0 replies; 132+ messages in thread
From: Randy Brukardt @ 2015-12-02 19:33 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:51sbiz7sr8o7$.9wqd8z5xjlf8$.dlg@40tude.net...
> On Tue, 1 Dec 2015 12:19:02 +0100, G.B. wrote:
...
>> Sounds a bit like user defined aspects of compilation?
>
> It is not an aspect. Aspect is a view, characteristic, feature:
>
> http://www.thefreedictionary.com/aspect
>
> It means that aspect may not change the semantics.

Ada 83 tried that fiction (both for representation clauses and pragmas), but 
the results were laughable. Almost anything you can do modifies the sematics 
in some subtle way. (The only pragma that really doesn't modify the 
semantics is List(On)). A better way to view them is as modifiers or 
specifiers that reign in implementation freedom and/or add additional 
capabilities. Perhaps a better term could have been used, but as they were 
already called aspects in Ada 95 (and probably Ada 83, I'm not going to look 
right now), we left the terminology the same.

                                Randy.



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

end of thread, other threads:[~2015-12-02 19:33 UTC | newest]

Thread overview: 132+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-23 10:23 operation can be dispatching in only one type Serge Robyns
2015-11-23 11:29 ` Dmitry A. Kazakov
2015-11-23 13:05   ` Serge Robyns
2015-11-23 13:48     ` Dmitry A. Kazakov
2015-11-23 14:16       ` Serge Robyns
2015-11-23 14:59         ` G.B.
2015-11-23 15:52         ` Dmitry A. Kazakov
2015-11-23 17:40 ` Jeffrey R. Carter
2015-11-24  9:08   ` Serge Robyns
2015-11-24 16:44     ` AdaMagica
2015-11-24 17:09     ` Jeffrey R. Carter
2015-11-24 18:37       ` Serge Robyns
2015-11-24 20:18         ` Jeffrey R. Carter
2015-11-24 20:40           ` Serge Robyns
2015-11-24 20:25       ` Niklas Holsti
2015-11-24 21:48         ` Jeffrey R. Carter
2015-11-25  8:24           ` Dmitry A. Kazakov
2015-11-25 11:22             ` Serge Robyns
2015-11-25 17:38               ` Dmitry A. Kazakov
2015-11-26 11:30                 ` Serge Robyns
2015-11-26 13:14                   ` Dmitry A. Kazakov
2015-11-26 14:27                     ` Serge Robyns
2015-11-26 15:16                       ` J-P. Rosen
2015-11-26 18:27                         ` Serge Robyns
2015-11-26 21:20                           ` J-P. Rosen
2015-11-27  8:37                             ` Dmitry A. Kazakov
2015-11-27 12:58                               ` J-P. Rosen
2015-11-27 13:39                                 ` Dmitry A. Kazakov
2015-11-30 22:22                                   ` Randy Brukardt
2015-12-01  8:46                                     ` Dmitry A. Kazakov
2015-12-01 11:19                                       ` G.B.
2015-12-01 13:56                                         ` Dmitry A. Kazakov
2015-12-01 16:05                                           ` G.B.
2015-12-01 17:58                                             ` Dmitry A. Kazakov
2015-12-02 13:06                                               ` G.B.
2015-12-02 13:31                                                 ` Dmitry A. Kazakov
2015-12-02 19:33                                           ` Randy Brukardt
2015-12-02 19:27                                       ` Randy Brukardt
2015-11-29 17:59                     ` Jacob Sparre Andersen
2015-11-30 22:29                       ` Randy Brukardt
2015-11-25 12:27             ` G.B.
2015-11-25 17:25               ` Dmitry A. Kazakov
  -- strict thread matches above, loose matches on Subject: below --
2009-11-13 20:12 Operation " xorque
2009-11-13 20:34 ` Dmitry A. Kazakov
2009-11-13 20:43   ` xorque
2009-11-13 21:14     ` Dmitry A. Kazakov
2009-11-13 20:44   ` xorque
2009-11-16 17:43 ` Adam Beneschan
2009-11-16 20:28   ` Dmitry A. Kazakov
2009-11-16 20:32     ` Dmitry A. Kazakov
2009-11-16 21:35     ` Adam Beneschan
2009-11-16 22:28       ` Dmitry A. Kazakov
2009-11-17 22:10         ` Adam Beneschan
2009-11-18  9:46           ` Dmitry A. Kazakov
2009-11-18 16:39             ` Adam Beneschan
2009-11-18 19:21               ` Dmitry A. Kazakov
2009-11-19  0:27                 ` Randy Brukardt
2009-11-19  2:11                   ` Robert A Duff
2009-11-19 15:57                     ` Adam Beneschan
2009-11-19 19:39                       ` Robert A Duff
2009-11-19 23:43                         ` Randy Brukardt
2009-11-19  8:50                   ` Dmitry A. Kazakov
2009-11-19 23:54                     ` Randy Brukardt
2009-11-20  8:34                       ` Dmitry A. Kazakov
2009-11-20 10:58                         ` Jean-Pierre Rosen
2009-11-21  6:02                         ` Randy Brukardt
2009-11-21 13:07                           ` Dmitry A. Kazakov
2009-11-22  5:45                         ` xorque
2009-11-22 11:25                           ` Georg Bauhaus
2009-11-22 11:30                             ` xorque
2009-11-22 16:25                             ` Dmitry A. Kazakov
2009-11-22 16:27                               ` xorque
2009-11-22 16:42                                 ` Dmitry A. Kazakov
2009-11-22 16:52                                   ` xorque
2009-11-22 17:41                                     ` Dmitry A. Kazakov
2009-11-22 18:03                                       ` xorque
2009-11-22 18:08                                         ` xorque
2009-11-22 18:28                                         ` Dmitry A. Kazakov
2009-11-22 18:41                                           ` xorque
2009-11-22 21:47                                           ` Robert A Duff
2009-11-23  3:42                                             ` stefan-lucks
2009-11-30 20:36                                               ` Robert A Duff
2009-11-30 23:54                                                 ` (see below)
2009-12-01 12:13                                                 ` Georg Bauhaus
2009-12-01 12:23                                                   ` Georg Bauhaus
2009-12-01 12:44                                                     ` Georg Bauhaus
2009-12-01 13:48                                                   ` Dmitry A. Kazakov
2009-12-01 15:02                                                     ` Georg Bauhaus
2009-12-01 16:18                                                       ` Dmitry A. Kazakov
2009-12-01 17:52                                                         ` Georg Bauhaus
2009-12-01 18:47                                                           ` Dmitry A. Kazakov
2009-12-01 21:53                                                             ` John B. Matthews
2009-12-02  0:32                                                               ` Georg Bauhaus
2009-12-02 11:18                                                                 ` John B. Matthews
2009-12-02 14:29                                                                   ` Jean-Pierre Rosen
2009-12-02 15:35                                                                     ` Georg Bauhaus
2009-12-02  1:13                                                             ` Georg Bauhaus
2009-12-02  9:07                                                               ` Dmitry A. Kazakov
2009-12-02 12:35                                                                 ` John B. Matthews
2009-12-02 13:35                                                                   ` Dmitry A. Kazakov
2009-12-03  5:23                                                                   ` Randy Brukardt
2009-12-03 20:21                                                                     ` John B. Matthews
2009-12-03  5:29                                                                 ` Randy Brukardt
2009-12-03 11:24                                                                   ` Georg Bauhaus
2009-12-03 23:08                                                                     ` Randy Brukardt
2009-12-04  8:52                                                                       ` Dmitry A. Kazakov
2009-12-05  2:45                                                                         ` Randy Brukardt
2009-12-05 10:32                                                                           ` Dmitry A. Kazakov
2009-12-08  0:19                                                                             ` Randy Brukardt
2009-12-08  4:30                                                                               ` stefan-lucks
2009-12-08  9:12                                                                                 ` Dmitry A. Kazakov
2009-12-10  4:09                                                                                   ` Randy Brukardt
2009-12-11  0:10                                                                                 ` Robert A Duff
2009-12-08  9:22                                                                               ` Dmitry A. Kazakov
2009-12-08 10:06                                                                                 ` Georg Bauhaus
2009-12-08 10:23                                                                                   ` Dmitry A. Kazakov
2009-12-08 10:33                                                                                     ` Georg Bauhaus
2009-12-08 10:49                                                                                       ` Dmitry A. Kazakov
2009-12-01 23:51                                                   ` Randy Brukardt
2009-11-23  8:52                                             ` Dmitry A. Kazakov
2009-11-30 20:43                                               ` Robert A Duff
2009-12-01  9:00                                                 ` Dmitry A. Kazakov
2009-12-01  5:45                                                   ` stefan-lucks
2009-12-01 11:12                                                     ` Dmitry A. Kazakov
2009-12-01  8:01                                                       ` stefan-lucks
2009-12-01 13:37                                                         ` Dmitry A. Kazakov
2009-12-15 23:54                                                         ` Robert A Duff
2009-11-23  7:48                                         ` Georg Bauhaus
2009-11-23  7:58                                           ` Georg Bauhaus
2009-11-19 16:04                 ` Adam Beneschan
2009-11-19  2:23           ` tmoran
2009-11-19  8:32             ` 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