comp.lang.ada
 help / color / mirror / Atom feed
* A bad counterintuitive behaviour of Ada about OO
@ 2014-08-05 20:09 Victor Porton
  2014-08-05 20:58 ` Simon Wright
                   ` (2 more replies)
  0 siblings, 3 replies; 73+ messages in thread
From: Victor Porton @ 2014-08-05 20:09 UTC (permalink / raw)


http://freesoft.portonvictor.org/binaries/ada-obj-test.tar.gz

contains a tiny Ada program which prints 0 despite intuition suggests that 
it should print 123, because it just copies (using Adjust) an object holding 
123.

In this program Handle_Type models some handle provided by an external API, 
where 0 is an undefined handle. Base_Object is a tagged record which holds a 
handle inside itself and can copy or destroy the handle automatically (as 
Base_Object is a controlled object).

Example_Record is a derived type of Base_Object which imitates a behavior of 
a simple library which operates over some handles. For example, in this 
example copying a handle preserves it unchanged.

This tiny program was created by me as a model of my real Ada bindings for 
Raptor C library, which produces a wrong behavior.

Why Ada behaves in this counter-intuitive way?

What should I do in similar situations when developing real Ada software?

-- 
Victor Porton - http://portonvictor.org

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-05 20:09 A bad counterintuitive behaviour of Ada about OO Victor Porton
@ 2014-08-05 20:58 ` Simon Wright
  2014-08-05 21:06   ` Victor Porton
  2014-08-05 22:35   ` Victor Porton
  2014-08-05 20:59 ` Dmitry A. Kazakov
  2014-08-06  4:50 ` Per Sandberg
  2 siblings, 2 replies; 73+ messages in thread
From: Simon Wright @ 2014-08-05 20:58 UTC (permalink / raw)


Victor Porton <porton@narod.ru> writes:

> http://freesoft.portonvictor.org/binaries/ada-obj-test.tar.gz
>
> contains a tiny Ada program which prints 0 despite intuition suggests that 
> it should print 123, because it just copies (using Adjust) an object holding 
> 123.
>
> In this program Handle_Type models some handle provided by an external API, 
> where 0 is an undefined handle. Base_Object is a tagged record which holds a 
> handle inside itself and can copy or destroy the handle automatically (as 
> Base_Object is a controlled object).
>
> Example_Record is a derived type of Base_Object which imitates a behavior of 
> a simple library which operates over some handles. For example, in this 
> example copying a handle preserves it unchanged.
>
> This tiny program was created by me as a model of my real Ada bindings for 
> Raptor C library, which produces a wrong behavior.
>
> Why Ada behaves in this counter-intuitive way?
>
> What should I do in similar situations when developing real Ada software?

I think what is happening is that in

   function From_Handle(Handle: Handle_Type) return Base_Object is
   begin
      return (Ada.Finalization.Controlled with Handle=>Handle);
   end;

the aggregate is created and copied to the function's result as a
Base_Object, so that when

   procedure Adjust(Object: in out Base_Object) is
   begin
      if Object.Handle /= 0 then
         Object.Handle := Copy_Handle(Base_Object'Class(Object), Object.Handle);
      end if;
   end;

is called during the copy,

   function Copy_Handle(Object: Base_Object; Handle: Handle_Type) return Handle_Type is
   begin
      return 0;
   end;

returns 0, as you've seen.


(1) If all you wanted to do was copy the Handle over, you don't need to
do anything, because that's the default behaviour (i.e., copies the
bits).

(2) Normally, From_Handle wouldn't be inherited, so you'd have had to
write your own; because Example_Object has a null extension, it can be
inherited.

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-05 20:09 A bad counterintuitive behaviour of Ada about OO Victor Porton
  2014-08-05 20:58 ` Simon Wright
@ 2014-08-05 20:59 ` Dmitry A. Kazakov
  2014-08-05 21:07   ` Victor Porton
  2014-08-05 21:11   ` Victor Porton
  2014-08-06  4:50 ` Per Sandberg
  2 siblings, 2 replies; 73+ messages in thread
From: Dmitry A. Kazakov @ 2014-08-05 20:59 UTC (permalink / raw)


On Tue, 05 Aug 2014 23:09:40 +0300, Victor Porton wrote:

> Why Ada behaves in this counter-intuitive way?

Because it is C++ code written in Ada.

> What should I do in similar situations when developing real Ada software?

Never re-dispatch, never cast types, unless you exactly know what are you
doing.

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

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-05 20:58 ` Simon Wright
@ 2014-08-05 21:06   ` Victor Porton
  2014-08-05 21:51     ` Niklas Holsti
  2014-08-05 22:35   ` Victor Porton
  1 sibling, 1 reply; 73+ messages in thread
From: Victor Porton @ 2014-08-05 21:06 UTC (permalink / raw)


Simon Wright wrote:

> Victor Porton <porton@narod.ru> writes:
> 
>> http://freesoft.portonvictor.org/binaries/ada-obj-test.tar.gz
>>
>> contains a tiny Ada program which prints 0 despite intuition suggests
>> that it should print 123, because it just copies (using Adjust) an object
>> holding 123.
>>
>> In this program Handle_Type models some handle provided by an external
>> API, where 0 is an undefined handle. Base_Object is a tagged record which
>> holds a handle inside itself and can copy or destroy the handle
>> automatically (as Base_Object is a controlled object).
>>
>> Example_Record is a derived type of Base_Object which imitates a behavior
>> of a simple library which operates over some handles. For example, in
>> this example copying a handle preserves it unchanged.
>>
>> This tiny program was created by me as a model of my real Ada bindings
>> for Raptor C library, which produces a wrong behavior.
>>
>> Why Ada behaves in this counter-intuitive way?
>>
>> What should I do in similar situations when developing real Ada software?
> 
> I think what is happening is that in
> 
>    function From_Handle(Handle: Handle_Type) return Base_Object is
>    begin
>       return (Ada.Finalization.Controlled with Handle=>Handle);
>    end;
> 
> the aggregate is created and copied to the function's result as a
> Base_Object, so that when
> 
>    procedure Adjust(Object: in out Base_Object) is
>    begin
>       if Object.Handle /= 0 then
>          Object.Handle := Copy_Handle(Base_Object'Class(Object),
>          Object.Handle);
>       end if;
>    end;
> 
> is called during the copy,
> 
>    function Copy_Handle(Object: Base_Object; Handle: Handle_Type) return
>    Handle_Type is begin
>       return 0;
>    end;
> 
> returns 0, as you've seen.
> 
> 
> (1) If all you wanted to do was copy the Handle over, you don't need to
> do anything, because that's the default behaviour (i.e., copies the
> bits).
> 
> (2) Normally, From_Handle wouldn't be inherited, so you'd have had to
> write your own; because Example_Object has a null extension, it can be
> inherited.

I've added in example_record.ads:

   function From_Handle(Handle: Handle_Type) return Example_Object;

and in example_record.adb:

   function From_Handle(Handle: Handle_Type) return Example_Object is
   begin
      return (Base_Object'(From_Handle(Handle)) with null record);
   end;

It prints "0" not as it was before.

So this does not help.

What to do? I write a real software project and need to make a decision what 
to do in this situation.

Please help.

-- 
Victor Porton - http://portonvictor.org

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-05 20:59 ` Dmitry A. Kazakov
@ 2014-08-05 21:07   ` Victor Porton
  2014-08-05 22:39     ` Shark8
  2014-08-05 21:11   ` Victor Porton
  1 sibling, 1 reply; 73+ messages in thread
From: Victor Porton @ 2014-08-05 21:07 UTC (permalink / raw)


Dmitry A. Kazakov wrote:

> On Tue, 05 Aug 2014 23:09:40 +0300, Victor Porton wrote:
> 
>> Why Ada behaves in this counter-intuitive way?
> 
> Because it is C++ code written in Ada.
> 
>> What should I do in similar situations when developing real Ada software?
> 
> Never re-dispatch, never cast types, unless you exactly know what are you
> doing.

Pleas explain what exactly you mean saying "re-dispatch".

-- 
Victor Porton - http://portonvictor.org


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-05 20:59 ` Dmitry A. Kazakov
  2014-08-05 21:07   ` Victor Porton
@ 2014-08-05 21:11   ` Victor Porton
  2014-08-06  7:26     ` Dmitry A. Kazakov
  1 sibling, 1 reply; 73+ messages in thread
From: Victor Porton @ 2014-08-05 21:11 UTC (permalink / raw)


Dmitry A. Kazakov wrote:

> On Tue, 05 Aug 2014 23:09:40 +0300, Victor Porton wrote:
> 
>> Why Ada behaves in this counter-intuitive way?
> 
> Because it is C++ code written in Ada.
> 
>> What should I do in similar situations when developing real Ada software?
> 
> Never re-dispatch, never cast types, unless you exactly know what are you
> doing.

Your answer is "negative". You say what not to do.

But I am seeking a positive answer: what should I do in this situation, when 
writing real software?

-- 
Victor Porton - http://portonvictor.org


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-05 21:06   ` Victor Porton
@ 2014-08-05 21:51     ` Niklas Holsti
  2014-08-05 22:13       ` Victor Porton
  0 siblings, 1 reply; 73+ messages in thread
From: Niklas Holsti @ 2014-08-05 21:51 UTC (permalink / raw)


On 14-08-06 00:06 , Victor Porton wrote:
> Simon Wright wrote:
> 
>> Victor Porton <porton@narod.ru> writes:
>>
>>> http://freesoft.portonvictor.org/binaries/ada-obj-test.tar.gz
>>>
>>> contains a tiny Ada program which prints 0 despite intuition suggests
>>> that it should print 123, because it just copies (using Adjust) an object
>>> holding 123.
>>>
>>> In this program Handle_Type models some handle provided by an external
>>> API, where 0 is an undefined handle. Base_Object is a tagged record which
>>> holds a handle inside itself and can copy or destroy the handle
>>> automatically (as Base_Object is a controlled object).
>>>
>>> Example_Record is a derived type of Base_Object which imitates a behavior
>>> of a simple library which operates over some handles. For example, in
>>> this example copying a handle preserves it unchanged.
>>>
>>> This tiny program was created by me as a model of my real Ada bindings
>>> for Raptor C library, which produces a wrong behavior.
>>>
>>> Why Ada behaves in this counter-intuitive way?
>>>
>>> What should I do in similar situations when developing real Ada software?
>>
>> I think what is happening is that in
>>
>>    function From_Handle(Handle: Handle_Type) return Base_Object is
>>    begin
>>       return (Ada.Finalization.Controlled with Handle=>Handle);
>>    end;
>>
>> the aggregate is created and copied to the function's result as a
>> Base_Object, so that when
>>
>>    procedure Adjust(Object: in out Base_Object) is
>>    begin
>>       if Object.Handle /= 0 then
>>          Object.Handle := Copy_Handle(Base_Object'Class(Object),
>>          Object.Handle);
>>       end if;
>>    end;
>>
>> is called during the copy,
>>
>>    function Copy_Handle(Object: Base_Object; Handle: Handle_Type) return
>>    Handle_Type is begin
>>       return 0;
>>    end;
>>
>> returns 0, as you've seen.
>>
>>
>> (1) If all you wanted to do was copy the Handle over, you don't need to
>> do anything, because that's the default behaviour (i.e., copies the
>> bits).
>>
>> (2) Normally, From_Handle wouldn't be inherited, so you'd have had to
>> write your own; because Example_Object has a null extension, it can be
>> inherited.
> 
> I've added in example_record.ads:
> 
>    function From_Handle(Handle: Handle_Type) return Example_Object;
> 
> and in example_record.adb:
> 
>    function From_Handle(Handle: Handle_Type) return Example_Object is
>    begin
>       return (Base_Object'(From_Handle(Handle)) with null record);
>    end;
> 
> It prints "0" not as it was before.

(I assume the "not" above is a mistake, and you mean that it prints "0"
just as before.)

That happens because in your new From_Handle for Example_Object, the
part Base_Object'(From_Handle(Handle)) returns an object of type
Base_Object, which is then assigned into the parent part of the
extension aggregate, and this assignment operation invokes the Adjust
operation for Base_Object, which invokes Copy_Handle for Base_Object,
which returns a zero handle.

> What to do? I write a real software project and need to make a decision what 
> to do in this situation.

Alternatives:

1. Write a sensible Copy_Handle for Base_Object (preferred solution), or

2. make Example_Record a child package of Handled_Record, which makes
the internal structure of Base_Object visible, and lets you write

    function From_Handle(Handle: Handle_Type) return Example_Object is
    begin
       return (Ada.Finalization.Controlled with Handle => Handle);
    end;

and therefore lets you create Example_Objects without going through a
Base_Object and its handle-destroying Copy_Handle.

By the way, Dmitry's advice not to use re-dispatching is his personal
opinion, shared by some people on comp.lang.ada but not by me; you
should consider the pros and cons yourself.

Re-dispatching is what happens in your Adjust operation when you convert
the Object to Base_Type'Class and then invoke Copy_Handle. The
conversion forces the call to be a dispatching call. Without conversion,
the call is statically bound to the Copy_Handle of Base_Object.

Re-dispatching plays no role in your problem. The problem is that by
making Base_Object private, and Example_Record not a child of
Handled_Record, you have made it impossible to create an Example_Object
without first creating a Base_Object and therefore invoking the Adjust
and Copy_Handle for Base_Object.

-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
      .      @       .


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-05 21:51     ` Niklas Holsti
@ 2014-08-05 22:13       ` Victor Porton
  0 siblings, 0 replies; 73+ messages in thread
From: Victor Porton @ 2014-08-05 22:13 UTC (permalink / raw)


Niklas Holsti wrote:

> On 14-08-06 00:06 , Victor Porton wrote:
>> Simon Wright wrote:
>> 
>>> Victor Porton <porton@narod.ru> writes:
>>>
>>>> http://freesoft.portonvictor.org/binaries/ada-obj-test.tar.gz
>>>>
>>>> contains a tiny Ada program which prints 0 despite intuition suggests
>>>> that it should print 123, because it just copies (using Adjust) an
>>>> object holding 123.
>>>>
>>>> In this program Handle_Type models some handle provided by an external
>>>> API, where 0 is an undefined handle. Base_Object is a tagged record
>>>> which holds a handle inside itself and can copy or destroy the handle
>>>> automatically (as Base_Object is a controlled object).
>>>>
>>>> Example_Record is a derived type of Base_Object which imitates a
>>>> behavior of a simple library which operates over some handles. For
>>>> example, in this example copying a handle preserves it unchanged.
>>>>
>>>> This tiny program was created by me as a model of my real Ada bindings
>>>> for Raptor C library, which produces a wrong behavior.
>>>>
>>>> Why Ada behaves in this counter-intuitive way?
>>>>
>>>> What should I do in similar situations when developing real Ada
>>>> software?
>>>
>>> I think what is happening is that in
>>>
>>>    function From_Handle(Handle: Handle_Type) return Base_Object is
>>>    begin
>>>       return (Ada.Finalization.Controlled with Handle=>Handle);
>>>    end;
>>>
>>> the aggregate is created and copied to the function's result as a
>>> Base_Object, so that when
>>>
>>>    procedure Adjust(Object: in out Base_Object) is
>>>    begin
>>>       if Object.Handle /= 0 then
>>>          Object.Handle := Copy_Handle(Base_Object'Class(Object),
>>>          Object.Handle);
>>>       end if;
>>>    end;
>>>
>>> is called during the copy,
>>>
>>>    function Copy_Handle(Object: Base_Object; Handle: Handle_Type) return
>>>    Handle_Type is begin
>>>       return 0;
>>>    end;
>>>
>>> returns 0, as you've seen.
>>>
>>>
>>> (1) If all you wanted to do was copy the Handle over, you don't need to
>>> do anything, because that's the default behaviour (i.e., copies the
>>> bits).
>>>
>>> (2) Normally, From_Handle wouldn't be inherited, so you'd have had to
>>> write your own; because Example_Object has a null extension, it can be
>>> inherited.
>> 
>> I've added in example_record.ads:
>> 
>>    function From_Handle(Handle: Handle_Type) return Example_Object;
>> 
>> and in example_record.adb:
>> 
>>    function From_Handle(Handle: Handle_Type) return Example_Object is
>>    begin
>>       return (Base_Object'(From_Handle(Handle)) with null record);
>>    end;
>> 
>> It prints "0" not as it was before.
> 
> (I assume the "not" above is a mistake, and you mean that it prints "0"
> just as before.)

Yes, my typo.

> That happens because in your new From_Handle for Example_Object, the
> part Base_Object'(From_Handle(Handle)) returns an object of type
> Base_Object, which is then assigned into the parent part of the
> extension aggregate, and this assignment operation invokes the Adjust
> operation for Base_Object, which invokes Copy_Handle for Base_Object,
> which returns a zero handle.
> 
>> What to do? I write a real software project and need to make a decision
>> what to do in this situation.
> 
> Alternatives:
> 
> 1. Write a sensible Copy_Handle for Base_Object (preferred solution), or

It is hardly possible to make sensible Copy_Handle for Base_Object, because 
the copy handler is different for every kind of objects.

> 2. make Example_Record a child package of Handled_Record, which makes
> the internal structure of Base_Object visible, and lets you write
> 
>     function From_Handle(Handle: Handle_Type) return Example_Object is
>     begin
>        return (Ada.Finalization.Controlled with Handle => Handle);
>     end;
> 
> and therefore lets you create Example_Objects without going through a
> Base_Object and its handle-destroying Copy_Handle.

In fact I have RDF.Auxilary.Simple_Handled_Record and some related (generic) 
packages defined like this:

[[[
with RDF.Auxilary.Handled_Record;

package RDF.Auxilary.Simple_Handled_Record is
   new RDF.Auxilary.Handled_Record(Dummy_Record);
]]]

So the solution to use child packages is not a good fit for me. (Well, I can 
rearrange the structure of my packages, but would not like this idea.)

Making it child packages to expose internal structure of object also should 
be eliminated if possible.

So now I see no really good way to do this. Any ideas?

> By the way, Dmitry's advice not to use re-dispatching is his personal
> opinion, shared by some people on comp.lang.ada but not by me; you
> should consider the pros and cons yourself.
> 
> Re-dispatching is what happens in your Adjust operation when you convert
> the Object to Base_Type'Class and then invoke Copy_Handle. The
> conversion forces the call to be a dispatching call. Without conversion,
> the call is statically bound to the Copy_Handle of Base_Object.
> 
> Re-dispatching plays no role in your problem. The problem is that by
> making Base_Object private, and Example_Record not a child of
> Handled_Record, you have made it impossible to create an Example_Object
> without first creating a Base_Object and therefore invoking the Adjust
> and Copy_Handle for Base_Object.

-- 
Victor Porton - http://portonvictor.org

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-05 20:58 ` Simon Wright
  2014-08-05 21:06   ` Victor Porton
@ 2014-08-05 22:35   ` Victor Porton
  2014-08-05 23:25     ` Adam Beneschan
  1 sibling, 1 reply; 73+ messages in thread
From: Victor Porton @ 2014-08-05 22:35 UTC (permalink / raw)


Simon Wright wrote:

> Victor Porton <porton@narod.ru> writes:
> 
>> http://freesoft.portonvictor.org/binaries/ada-obj-test.tar.gz
>>
>> contains a tiny Ada program which prints 0 despite intuition suggests
>> that it should print 123, because it just copies (using Adjust) an object
>> holding 123.
>>
>> In this program Handle_Type models some handle provided by an external
>> API, where 0 is an undefined handle. Base_Object is a tagged record which
>> holds a handle inside itself and can copy or destroy the handle
>> automatically (as Base_Object is a controlled object).
>>
>> Example_Record is a derived type of Base_Object which imitates a behavior
>> of a simple library which operates over some handles. For example, in
>> this example copying a handle preserves it unchanged.
>>
>> This tiny program was created by me as a model of my real Ada bindings
>> for Raptor C library, which produces a wrong behavior.
>>
>> Why Ada behaves in this counter-intuitive way?
>>
>> What should I do in similar situations when developing real Ada software?
> 
> I think what is happening is that in
> 
>    function From_Handle(Handle: Handle_Type) return Base_Object is
>    begin
>       return (Ada.Finalization.Controlled with Handle=>Handle);
>    end;
> 
> the aggregate is created and copied to the function's result as a
> Base_Object, so that when
> 
>    procedure Adjust(Object: in out Base_Object) is
>    begin
>       if Object.Handle /= 0 then
>          Object.Handle := Copy_Handle(Base_Object'Class(Object),
>          Object.Handle);
>       end if;
>    end;
> 
> is called during the copy,
> 
>    function Copy_Handle(Object: Base_Object; Handle: Handle_Type) return
>    Handle_Type is begin
>       return 0;
>    end;
> 
> returns 0, as you've seen.
> 
> 
> (1) If all you wanted to do was copy the Handle over, you don't need to
> do anything, because that's the default behaviour (i.e., copies the
> bits).
> 
> (2) Normally, From_Handle wouldn't be inherited, so you'd have had to
> write your own; because Example_Object has a null extension, it can be
> inherited.

So now I understand what I should do. To eliminate side effects when copying 
subobjects of Base_Object type, I should remove overriding Adjust from 
Base_Object and define it manually for particular object types. Copy_Handle 
then becomes unnecessary and should be removed altogether.

To make possible to implement Adjust in derived types, I need to define:

-- Don't call this procedure unless you really need it.
procedure Set_Handle_Hack(Object: in out Base_Object; Handle: Handle_Type) 
is
begin
   Object.Handle := Handle;
end;

It is an acceptable solution.

-- 
Victor Porton - http://portonvictor.org


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-05 21:07   ` Victor Porton
@ 2014-08-05 22:39     ` Shark8
  0 siblings, 0 replies; 73+ messages in thread
From: Shark8 @ 2014-08-05 22:39 UTC (permalink / raw)


On 05-Aug-14 15:07, Victor Porton wrote:
> Pleas explain what exactly you mean saying "re-dispatch".

The wiki-book has a pretty good explanation:
http://en.wikibooks.org/wiki/Ada_Programming/Object_Orientation#Redispatching

The difference between Dispatching and non-Dispatching is, essentially, 
the same as that of static- and dynamic-linking -- Re-Dispatching is 
when the dispatching-call makes another dispatching call.

I'm probably not explaining it well but let's step-through -- given the 
following:

     Package Example is
         Type Base is tagged null record;
         Procedure Call_Op1  ( T1 : Base'Class ); -- A Dispatching Call
         Procedure Call_Op2  ( T1 : Base );   -- Not A Dispatching Call
         Procedure Operation ( T1 : Base );   -- Not A Dispatching Call

         Type Current is new Base with null record;
         Overriding Procedure Call_Op2 ( T1 : Current ); -- Not A 
Dispatching Call
         Overriding Procedure Operation( T1 : Current ); -- Not A 
Dispatching Call

         Type Child is new Current with null record;
         Overriding Procedure Call_Op2 ( T1 : Child );   -- Not A 
Dispatching Call
         Overriding Procedure Operation( T1 : Child );   -- Not A 
Dispatching Call
     End Example;

     Package Body Example is
         Procedure Call_Op1 ( T1 : Base'Class ) is
         begin
             T1.Operation; -- Re-Dispatching.
         end;

         Procedure Call_Op2 ( T1 : Base ) is
         begin
           Base'Class(T1).Operation; -- Dispatching
         end;

         Overriding Procedure Call_Op2 ( T1 : Current ) is
         begin
             Ada.Text_IO.Put_Line( "-- Current.Op2 --" );
             Ada.Text_IO.Put( ASCII.HT );
             Base'Class(T1).Operation;
         end;

         Overriding Procedure Call_Op2 ( T1 : Child ) is
         begin
             Ada.Text_IO.Put_Line( "-- Child.Op2 --" );
             Ada.Text_IO.Put( ASCII.HT );
             Base(T1).Call_Op2;
         end;


         Procedure Operation( T1 : Base       ) is
         begin
             Ada.Text_IO.Put_Line( "-- BASE --" );
         End Operation;

         Overriding Procedure Operation( T1 : Current ) is
         begin
             Ada.Text_IO.Put_Line( "-- CURRENT --" );
         End Operation;


         Overriding Procedure Operation( T1 : Child ) is
         begin
             Ada.Text_IO.Put_Line( "-- CHILD --" );
         End Operation;
     End Example;

The execution of
     declare
         X : Example.Child;
     begin
         X.Call_Op1;
         X.Call_Op2;
         Example.Current(X).Operation;
         Example.Current(X).Call_Op1;
         Example.Current(X).Call_Op2;
     end;
produces:
-- CHILD --
-- Child.Op2 --
	-- CHILD --
-- CURRENT --
-- CHILD --
-- Current.Op2 --
	-- CHILD --


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-05 22:35   ` Victor Porton
@ 2014-08-05 23:25     ` Adam Beneschan
  0 siblings, 0 replies; 73+ messages in thread
From: Adam Beneschan @ 2014-08-05 23:25 UTC (permalink / raw)


On Tuesday, August 5, 2014 3:35:49 PM UTC-7, Victor Porton wrote:

> So now I understand what I should do. To eliminate side effects when copying 
> subobjects of Base_Object type, I should remove overriding Adjust from 
> Base_Object and define it manually for particular object types. Copy_Handle 
> then becomes unnecessary and should be removed altogether.

This seems to be on the right track.  An "Adjust" procedure that destroys data (e.g. by clearing it to 0, as you've done) is asking for trouble.  The problem, as you've found out, is that records could be copied at times when you're not expecting.  The semantics in the LRM for function calls and aggregates talk about creating anonymous objects and then copying them to their final destination, which could involve extra Adjust/Finalize calls.  Then it spells out cases where an implementation is permitted to build stuff in place (instead of building in a temporary location and copying), and avoid an Adjust/Finalize pair, and it spells out other cases where the implementation is *required* to build stuff in place.

I tried your example with two different compilers, and in both cases, the process of calling Handled_Record.From_Handle led to an Adjust call that cleared the data to 0.  This was true even after you added an explicit From_Handle for the Example_Object; your expression still called the Handled_Record.From_Handle function and that led to the Adjust call.  As an experiment, I tried rewriting From_Handle from this:

   function From_Handle(Handle: Handle_Type) return Base_Object is 
   begin 
      return (Ada.Finalization.Controlled with Handle=>Handle); 
   end; 

to this:

   function From_Handle(Handle: Handle_Type) return Base_Object is 
   begin 
      return Result : Base_Object do
          Result.Handle := Handle;
      end return;
   end; 

This caused the program to avoid calling Handled_Record.Adjust with one compiler, thus outputting the expected result, but not with the other compiler.  And neither compiler is wrong.  They're taking advantage of implementation permissions differently.

So you have to be careful when defining Adjust/Finalize for a type.  You have to make sure that whenever you call a function that returns that type, or use an aggregate or extension aggregate of that type, you have to make sure the program will work if one *or* *more* Adjust/Finalize pairs are called when moving the data around from one location to another, and you have to make sure it will work if Adjust/Finalize are *not* called.  Your original Adjust fails that test.

                                 -- Adam

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-05 20:09 A bad counterintuitive behaviour of Ada about OO Victor Porton
  2014-08-05 20:58 ` Simon Wright
  2014-08-05 20:59 ` Dmitry A. Kazakov
@ 2014-08-06  4:50 ` Per Sandberg
  2 siblings, 0 replies; 73+ messages in thread
From: Per Sandberg @ 2014-08-06  4:50 UTC (permalink / raw)


The program is doing exat what is should.
May i sugest you to put the folowing line in all methods.
---------------------------------------------------------------------
pragma debug (GNAT.IO.Put_Line (GNAT.Source_Info.Enclosing_Entity & " " 
& Object.Handle'img));
--------------------------------------------------------------------
And compile with assertions enabled.
And reflect on the output.

/Per

On 05.08.2014 22:09, Victor Porton wrote:
> http://freesoft.portonvictor.org/binaries/ada-obj-test.tar.gz
>
> contains a tiny Ada program which prints 0 despite intuition suggests that
> it should print 123, because it just copies (using Adjust) an object holding
> 123.
>
> In this program Handle_Type models some handle provided by an external API,
> where 0 is an undefined handle. Base_Object is a tagged record which holds a
> handle inside itself and can copy or destroy the handle automatically (as
> Base_Object is a controlled object).
>
> Example_Record is a derived type of Base_Object which imitates a behavior of
> a simple library which operates over some handles. For example, in this
> example copying a handle preserves it unchanged.
>
> This tiny program was created by me as a model of my real Ada bindings for
> Raptor C library, which produces a wrong behavior.
>
> Why Ada behaves in this counter-intuitive way?
>
> What should I do in similar situations when developing real Ada software?
>

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-05 21:11   ` Victor Porton
@ 2014-08-06  7:26     ` Dmitry A. Kazakov
  2014-08-07  7:41       ` Maciej Sobczak
  0 siblings, 1 reply; 73+ messages in thread
From: Dmitry A. Kazakov @ 2014-08-06  7:26 UTC (permalink / raw)


On Wed, 06 Aug 2014 00:11:33 +0300, Victor Porton wrote:

> Dmitry A. Kazakov wrote:
> 
>> On Tue, 05 Aug 2014 23:09:40 +0300, Victor Porton wrote:
>> 
>>> Why Ada behaves in this counter-intuitive way?
>> 
>> Because it is C++ code written in Ada.
>> 
>>> What should I do in similar situations when developing real Ada software?
>> 
>> Never re-dispatch, never cast types, unless you exactly know what are you
>> doing.
> 
> Your answer is "negative". You say what not to do.
> 
> But I am seeking a positive answer: what should I do in this situation, when 
> writing real software?

It could be answered if you stated the problem. You wrote about
"counterintuitive" behavior. What "intuitive" behavior would be.

Remember that OO features in practically all OOPL are broken. Ada is the
only language I know which implements OO consistently in a properly typed
way.

P.S. Controlled wrappers around external references is a quite simple
thing, if not trivial.

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


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-06  7:26     ` Dmitry A. Kazakov
@ 2014-08-07  7:41       ` Maciej Sobczak
  2014-08-07  8:50         ` Dmitry A. Kazakov
  2014-08-07  8:58         ` J-P. Rosen
  0 siblings, 2 replies; 73+ messages in thread
From: Maciej Sobczak @ 2014-08-07  7:41 UTC (permalink / raw)



> Remember that OO features in practically all OOPL are broken. Ada is the
> only language I know which implements OO consistently in a properly typed
> way.

No way. :-D With type/interface schizophrenia, lack of MI, controlled as a base class, unsafe (!!!) handling of dispatch during initialization/finalization and no support for type covariance on return type Ada is way more broken than other languages I am aware of. I mean - in its handling of OO it's almost as broken as Java.

No trolling here - I really consider the above issues to be problems. OO in Ada definitely looks like a patchwork, not a consistent language feature.

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

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-07  7:41       ` Maciej Sobczak
@ 2014-08-07  8:50         ` Dmitry A. Kazakov
  2014-08-08  7:54           ` Maciej Sobczak
  2014-08-07  8:58         ` J-P. Rosen
  1 sibling, 1 reply; 73+ messages in thread
From: Dmitry A. Kazakov @ 2014-08-07  8:50 UTC (permalink / raw)


On Thu, 7 Aug 2014 00:41:08 -0700 (PDT), Maciej Sobczak wrote:

>> Remember that OO features in practically all OOPL are broken. Ada is the
>> only language I know which implements OO consistently in a properly typed
>> way.
> 
> No way. :-D With type/interface schizophrenia, lack of MI, controlled as a
> base class,

I didn't say "completely", I said "consistently". True, lack of MI and
having first- and second-class types is a serious incompleteness. You can
add lack of full MD to the list, missing delegation support, lack of
abstract interfaces for record, array, access, task, protected types.

> unsafe (!!!) handling of dispatch during
> initialization/finalization

Well, I don't consider Initialize/Finalize stuff as
initialization/finalization. To me it is hack made to avoid serious dealing
with the issue. Thus it is not an inconsistency but an incompleteness of
the Ada initialization/finalization model. It would be possible to add
necessary hooks and leave Initialize/Finalize as is.

More serious is the garbage limited return stuff. That borders
inconsistency and likely crosses the border. A lighter issue is the return
statement which allows multiple initialization-finalization rounds on the
"same" object. Yet another serious issue is renaming to a differently
constrained subtype. That is plain inconsistent.

> and no support for type covariance on return
> type Ada is way more broken than other languages I am aware of.

I don't understand this. The return type is covariant in Ada.

> No trolling here - I really consider the above issues to be problems. OO
> in Ada definitely looks like a patchwork, not a consistent language
> feature.

Yes, but again a patchwork may mean incompleteness or inconsistency (or
both (:-))

To me the most important thing is making classes of types typed. T /=
T'Class. Ada did it. The rest could be fixed, if there were a desire.
Unfortunately, there is none.

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

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-07  7:41       ` Maciej Sobczak
  2014-08-07  8:50         ` Dmitry A. Kazakov
@ 2014-08-07  8:58         ` J-P. Rosen
  2014-08-07  9:40           ` Dmitry A. Kazakov
                             ` (2 more replies)
  1 sibling, 3 replies; 73+ messages in thread
From: J-P. Rosen @ 2014-08-07  8:58 UTC (permalink / raw)


Le 07/08/2014 09:41, Maciej Sobczak a écrit :
> No way. :-D With type/interface schizophrenia, lack of MI, controlled
> as a base class, unsafe (!!!) handling of dispatch during
> initialization/finalization and no support for type covariance on
> return type Ada is way more broken than other languages I am aware
> of. I mean - in its handling of OO it's almost as broken as Java.
> 
> No trolling here - I really consider the above issues to be problems.
> OO in Ada definitely looks like a patchwork, not a consistent
> language feature.

Rather say that there are two kinds of OO programming languages: those
that consider OOP as one tool among others, to be used when (and only
when) appropriate, and the "pure" OO languages where OOP is the only way
to do everything. Ada clearly belongs to the first category.

Of course, there are similarly two kinds of programmers. You belong to
the second category (no bad feelings intended), but some of us belong to
the first one.

-- 
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] 73+ messages in thread

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-07  8:58         ` J-P. Rosen
@ 2014-08-07  9:40           ` Dmitry A. Kazakov
  2014-08-07 11:17             ` J-P. Rosen
  2014-08-07 15:03           ` Jeffrey Carter
  2014-08-08  7:48           ` Maciej Sobczak
  2 siblings, 1 reply; 73+ messages in thread
From: Dmitry A. Kazakov @ 2014-08-07  9:40 UTC (permalink / raw)


On Thu, 07 Aug 2014 10:58:20 +0200, J-P. Rosen wrote:

> Le 07/08/2014 09:41, Maciej Sobczak a écrit :
>> No way. :-D With type/interface schizophrenia, lack of MI, controlled
>> as a base class, unsafe (!!!) handling of dispatch during
>> initialization/finalization and no support for type covariance on
>> return type Ada is way more broken than other languages I am aware
>> of. I mean - in its handling of OO it's almost as broken as Java.
>> 
>> No trolling here - I really consider the above issues to be problems.
>> OO in Ada definitely looks like a patchwork, not a consistent
>> language feature.
> 
> Rather say that there are two kinds of OO programming languages: those
> that consider OOP as one tool among others, to be used when (and only
> when) appropriate, and the "pure" OO languages where OOP is the only way
> to do everything. Ada clearly belongs to the first category.

You are conflating OOA/D (SW design technique) with the features of the
language type system. You may not use OOA/D, I don't. But there is no
slightest doubt that the type system must have the features described
above.

> Of course, there are similarly two kinds of programmers. You belong to
> the second category (no bad feelings intended), but some of us belong to
> the first one.

Let's take another example, formal correctness proofs. Very few programmers
will ever use them at full. Yet, there is no doubt that Ada must support
proofs at all levels - type invariants, subprogram's pre-/post-conditions,
pre-/post-conditions and loop invariants within the control flow.

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

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-07  9:40           ` Dmitry A. Kazakov
@ 2014-08-07 11:17             ` J-P. Rosen
  2014-08-07 12:28               ` Dmitry A. Kazakov
  0 siblings, 1 reply; 73+ messages in thread
From: J-P. Rosen @ 2014-08-07 11:17 UTC (permalink / raw)


Le 07/08/2014 11:40, Dmitry A. Kazakov a écrit :
> You are conflating OOA/D (SW design technique) with the features of the
> language type system. You may not use OOA/D, I don't. But there is no
> slightest doubt that the type system must have the features described
> above.

No doubt? I'm very happy that elementary types are kept separate from
all the OO stuff, for example...

-- 
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] 73+ messages in thread

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-07 11:17             ` J-P. Rosen
@ 2014-08-07 12:28               ` Dmitry A. Kazakov
  2014-08-07 13:34                 ` J-P. Rosen
  0 siblings, 1 reply; 73+ messages in thread
From: Dmitry A. Kazakov @ 2014-08-07 12:28 UTC (permalink / raw)


On Thu, 07 Aug 2014 13:17:47 +0200, J-P. Rosen wrote:

> Le 07/08/2014 11:40, Dmitry A. Kazakov a écrit :
>> You are conflating OOA/D (SW design technique) with the features of the
>> language type system. You may not use OOA/D, I don't. But there is no
>> slightest doubt that the type system must have the features described
>> above.
> 
> No doubt? I'm very happy that elementary types are kept separate from
> all the OO stuff, for example...

Is it OO being able to write a class-wide numeric Sort, Put, Image,
container?

Anyway, it would help to indicate reasons for this happiness. I see no gain
in having types and not-quite types in the language. And there are lot of
problems with not-quite types in Ada concerning safety, reuse,
maintainability (Ada's key features, BTW).

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

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-07 12:28               ` Dmitry A. Kazakov
@ 2014-08-07 13:34                 ` J-P. Rosen
  2014-08-07 16:10                   ` Dmitry A. Kazakov
  2014-08-07 20:29                   ` Shark8
  0 siblings, 2 replies; 73+ messages in thread
From: J-P. Rosen @ 2014-08-07 13:34 UTC (permalink / raw)


Le 07/08/2014 14:28, Dmitry A. Kazakov a écrit :
>> No doubt? I'm very happy that elementary types are kept separate from
>> > all the OO stuff, for example...
> Is it OO being able to write a class-wide numeric Sort, Put, Image,
> container?
I prefer generics for that kind of stuff. It keeps my types independent,
and it doesn't need any dispatching.

> Anyway, it would help to indicate reasons for this happiness. I see no gain
> in having types and not-quite types in the language. And there are lot of
> problems with not-quite types in Ada concerning safety, reuse,
> maintainability (Ada's key features, BTW).

Because good ol' elementary types are much simpler to understand, and
more efficient to implement. Classification makes sense only if you have
heterogeneous data structures that manipulate various types belonging to
a same class. This is rarely the case for elementary types.

It happened to me several times that I consulted for a client, and
simplified design a lot by /removing/ unnecessary classification.

Now I come to think that some people have a mind turned to
classification and others not - maybe related to being left- or
right-brained? But please, because you have a certain (respectable) way
of thinking, don't assume that everybody must have the same. There's
more than one way to skin a cat!

-- 
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] 73+ messages in thread

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-07  8:58         ` J-P. Rosen
  2014-08-07  9:40           ` Dmitry A. Kazakov
@ 2014-08-07 15:03           ` Jeffrey Carter
  2014-08-08  7:48           ` Maciej Sobczak
  2 siblings, 0 replies; 73+ messages in thread
From: Jeffrey Carter @ 2014-08-07 15:03 UTC (permalink / raw)


On 08/07/2014 01:58 AM, J-P. Rosen wrote:
>
> Rather say that there are two kinds of OO programming languages: those
> that consider OOP as one tool among others, to be used when (and only
> when) appropriate, and the "pure" OO languages where OOP is the only way
> to do everything. Ada clearly belongs to the first category.

There are no "OO" languages. There are languages that support type extension and 
dispatching, and those that don't. Object orientation is a design 
characteristic. There is nothing object-oriented about programming by type 
extension; it is an implementation technique. It can be used to implement OO 
designs, but it can also be (and often is) used to implement non-OO designs. 
Programming by composition can also be used to implement both kinds of designs.

-- 
Jeff Carter
"He that hath no beard is less than a man."
Much Ado About Nothing
132


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-07 13:34                 ` J-P. Rosen
@ 2014-08-07 16:10                   ` Dmitry A. Kazakov
  2014-08-07 18:14                     ` Robert A Duff
  2014-08-08  7:45                     ` J-P. Rosen
  2014-08-07 20:29                   ` Shark8
  1 sibling, 2 replies; 73+ messages in thread
From: Dmitry A. Kazakov @ 2014-08-07 16:10 UTC (permalink / raw)


On Thu, 07 Aug 2014 15:34:26 +0200, J-P. Rosen wrote:

> Le 07/08/2014 14:28, Dmitry A. Kazakov a écrit :
>>> No doubt? I'm very happy that elementary types are kept separate from
>>> > all the OO stuff, for example...
>> Is it OO being able to write a class-wide numeric Sort, Put, Image,
>> container?
> I prefer generics for that kind of stuff. It keeps my types independent,
> and it doesn't need any dispatching.

Generics do not work for containers: you cannot have one of class-wide
elements. And generics enforce overloading which is a bad idea as
Ada.Text_IO has proven.

>> Anyway, it would help to indicate reasons for this happiness. I see no gain
>> in having types and not-quite types in the language. And there are lot of
>> problems with not-quite types in Ada concerning safety, reuse,
>> maintainability (Ada's key features, BTW).
> 
> Because good ol' elementary types are much simpler to understand, and
> more efficient to implement.

Having classes of elementary types does not change anything.

> Classification makes sense only if you have
> heterogeneous data structures that manipulate various types belonging to
> a same class. This is rarely the case for elementary types.

It is in any math book. Fields, groups, rings, spaces are such
classifications known for centuries.

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

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-07 16:10                   ` Dmitry A. Kazakov
@ 2014-08-07 18:14                     ` Robert A Duff
  2014-08-07 19:41                       ` Dmitry A. Kazakov
  2014-08-08  7:45                     ` J-P. Rosen
  1 sibling, 1 reply; 73+ messages in thread
From: Robert A Duff @ 2014-08-07 18:14 UTC (permalink / raw)


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

> Generics do not work for containers:

There are various annoying limitations, but...

>...you cannot have one of class-wide
> elements.

...but that's not one of them.  Ada.Containers.Indefinite_Vectors
supports class-wide element types, for example.

- Bob


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-07 18:14                     ` Robert A Duff
@ 2014-08-07 19:41                       ` Dmitry A. Kazakov
  2014-08-07 20:53                         ` Robert A Duff
  0 siblings, 1 reply; 73+ messages in thread
From: Dmitry A. Kazakov @ 2014-08-07 19:41 UTC (permalink / raw)


On Thu, 07 Aug 2014 14:14:52 -0400, Robert A Duff wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> 
>>...you cannot have one of class-wide
>> elements.
> 
> ...but that's not one of them.  Ada.Containers.Indefinite_Vectors
> supports class-wide element types, for example.

But you must have class-wide "elementary types" first. There is none, which
was the point.

-----------
Generics (parametric polymorphism) does not add anything to the language.
Anything you want to parametrize, must be in the language first, e.g. to
have a generic package the language must have plain packages.

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

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-07 13:34                 ` J-P. Rosen
  2014-08-07 16:10                   ` Dmitry A. Kazakov
@ 2014-08-07 20:29                   ` Shark8
  2014-08-08  7:49                     ` J-P. Rosen
  1 sibling, 1 reply; 73+ messages in thread
From: Shark8 @ 2014-08-07 20:29 UTC (permalink / raw)


On 07-Aug-14 07:34, J-P. Rosen wrote:
> Classification makes sense only if you have
> heterogeneous data structures that manipulate various types belonging to
> a same class.

I'd note that the heterogeneous data-structure needn't be strict; 
consider if you will an instruction set for a [virtual] CPU -- different 
instructions could have different numbers of parameters and therefore 
not be [strictly] heterogeneous. (Granted that all of these instructions 
would have another, if implicit, common parameter: the CPU.)

So, you could end up with abstract types:
   Instruction         -- Base/common interface.
   Arity_0_Instruction -- Common structure of 0 param instructions.
   Arity_1_Instruction -- Common structure of 1 param instructions.
   Arity_2_Instruction -- Common structure of 2 param instructions.
   Arity_3_Instruction -- Common structure of 3 param instructions.
and having all the instructions derive from the proper Arity.

Granted, you could also do the above [structurally] using a 
variant-record with multiple nestings.


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-07 19:41                       ` Dmitry A. Kazakov
@ 2014-08-07 20:53                         ` Robert A Duff
  2014-08-08  7:43                           ` Dmitry A. Kazakov
  0 siblings, 1 reply; 73+ messages in thread
From: Robert A Duff @ 2014-08-07 20:53 UTC (permalink / raw)


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

> On Thu, 07 Aug 2014 14:14:52 -0400, Robert A Duff wrote:
>
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
>> 
>>>...you cannot have one of class-wide
>>> elements.
>> 
>> ...but that's not one of them.  Ada.Containers.Indefinite_Vectors
>> supports class-wide element types, for example.
>
> But you must have class-wide "elementary types" first. There is none, which
> was the point.

Oh, now I see what you mean.  That's not a restriction on generics, it's
a restriction on non-tagged types.  We tried to add 'Class on non-tagged
types in Ada 9X, but the idea was rejected.

universal_integer is something like root_integer'Class, but since you
can't name those types, you can't do something like:

    function Image(X: universal_integer; Base: Integer range 2..16 := 10) return String;

> -----------
> Generics (parametric polymorphism) does not add anything to the language.
> Anything you want to parametrize, must be in the language first, e.g. to
> have a generic package the language must have plain packages.

I think types should be generic, instead.  See Eiffel.

- Bob


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-07 20:53                         ` Robert A Duff
@ 2014-08-08  7:43                           ` Dmitry A. Kazakov
  2014-08-08  8:18                             ` Shark8
  0 siblings, 1 reply; 73+ messages in thread
From: Dmitry A. Kazakov @ 2014-08-08  7:43 UTC (permalink / raw)


On Thu, 07 Aug 2014 16:53:50 -0400, Robert A Duff wrote:

> I think types should be generic, instead.  See Eiffel.

You need some clearl  defined scope where the format parameter would be
visible:

   generic
       with ... Something;
   type Generic_Mess is ...;
   ...
   -- many lines below

   procedure Bar (Y : Generic_Mess; X : Something);

   -- even more lines after. Is this OK?
   procedure Foo (X : Something) return String;

But, surely, discriminants do the job to me.

In my view any parameters must be a value and have a proper type. If you
wanted to parametrize using types make them first-class citizens. However,
there are better design methods than type parameters and blowing up the
language with generics.

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

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-07 16:10                   ` Dmitry A. Kazakov
  2014-08-07 18:14                     ` Robert A Duff
@ 2014-08-08  7:45                     ` J-P. Rosen
  2014-08-08  8:04                       ` Dmitry A. Kazakov
  1 sibling, 1 reply; 73+ messages in thread
From: J-P. Rosen @ 2014-08-08  7:45 UTC (permalink / raw)


Le 07/08/2014 18:10, Dmitry A. Kazakov a écrit :
>> Classification makes sense only if you have
>> > heterogeneous data structures that manipulate various types belonging to
>> > a same class. This is rarely the case for elementary types.
> It is in any math book. Fields, groups, rings, spaces are such
> classifications known for centuries.

Huh? I was talking about having containers holding values of different
types. You are answering with classification in mathematics. I fail to
see the connection.

-- 
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] 73+ messages in thread

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-07  8:58         ` J-P. Rosen
  2014-08-07  9:40           ` Dmitry A. Kazakov
  2014-08-07 15:03           ` Jeffrey Carter
@ 2014-08-08  7:48           ` Maciej Sobczak
  2014-08-08  8:51             ` J-P. Rosen
  2 siblings, 1 reply; 73+ messages in thread
From: Maciej Sobczak @ 2014-08-08  7:48 UTC (permalink / raw)


W dniu czwartek, 7 sierpnia 2014 10:58:20 UTC+2 użytkownik J-P. Rosen napisał:

> Rather say that there are two kinds of OO programming languages: those
> that consider OOP as one tool among others, to be used when (and only
> when) appropriate, and the "pure" OO languages where OOP is the only way
> to do everything.

Yes. But this division is completely orthogonal to whether the OOP support is consistent or broken. That is, taking into account these two aspects we have not two, but four kinds of programming languages and Ada belongs to the category of "broken support for OOP as one tool among others".
In practice, these divisions are not strict and different languages can be placed in a continuous space and compared relative to each other. For example, C++ also considers OOP as just one tool among others, but supports it in a more consistent way than Ada.

> Ada clearly belongs to the first category.

Yes. As many other languages.

> Of course, there are similarly two kinds of programmers.

Yes.

> You belong to
> the second category

I did not write anything that would allow you to make such claims. In fact, I find myself using OOP very rarely in my current projects - but when I do it I expect consistent support.

Just as an example - one of my current projects (in C++) has 15k lines of code, there are only 60 lines containing the "virtual" keyword (this indicates dispatching operation) and I use it consistently not only in base classes, but in derived too, so in total there are only a few dispatching operations in the whole project.
So, no, I am definitely not an OOP extremist.

> but some of us belong to
> the first one.

And you are OK with broken support for the tool that you are using occasionally? This is dangerous as it allows to justify broken support for every other language feature - after all, every one is just "one tool among others". Ada should do better than that.

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

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-07 20:29                   ` Shark8
@ 2014-08-08  7:49                     ` J-P. Rosen
  2014-08-08  8:12                       ` Shark8
  0 siblings, 1 reply; 73+ messages in thread
From: J-P. Rosen @ 2014-08-08  7:49 UTC (permalink / raw)


Le 07/08/2014 22:29, Shark8 a écrit :
> On 07-Aug-14 07:34, J-P. Rosen wrote:
>> Classification makes sense only if you have
>> heterogeneous data structures that manipulate various types belonging to
>> a same class.
> 
> I'd note that the heterogeneous data-structure needn't be strict;
> consider if you will an instruction set for a [virtual] CPU -- different
> instructions could have different numbers of parameters and therefore
> not be [strictly] heterogeneous. (Granted that all of these instructions
> would have another, if implicit, common parameter: the CPU.)
> 
> So, you could end up with abstract types:
>   Instruction         -- Base/common interface.
>   Arity_0_Instruction -- Common structure of 0 param instructions.
>   Arity_1_Instruction -- Common structure of 1 param instructions.
>   Arity_2_Instruction -- Common structure of 2 param instructions.
>   Arity_3_Instruction -- Common structure of 3 param instructions.
> and having all the instructions derive from the proper Arity.
> 
> Granted, you could also do the above [structurally] using a
> variant-record with multiple nestings.

Exactly. In Ada, you have multiple solutions to a problem (like using
plain types, variant types, tagged types, generics), with different
trade-offs, and it is the basis of engineering to investigate and choose
the most appropriate solution for the case at hand.

That's what I like with Ada, and that's why I regularly object to the
argument that "you can do everything with OOP, therefore you must do
everything with OOP".

-- 
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] 73+ messages in thread

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-07  8:50         ` Dmitry A. Kazakov
@ 2014-08-08  7:54           ` Maciej Sobczak
  2014-08-08  8:14             ` Dmitry A. Kazakov
  2014-08-08  8:34             ` Shark8
  0 siblings, 2 replies; 73+ messages in thread
From: Maciej Sobczak @ 2014-08-08  7:54 UTC (permalink / raw)


W dniu czwartek, 7 sierpnia 2014 10:50:52 UTC+2 użytkownik Dmitry A. Kazakov napisał:

> > and no support for type covariance on return
> > type Ada is way more broken than other languages I am aware of.
> 
> I don't understand this. The return type is covariant in Ada.

Can I have Better_Factory type with a primitive operation returning Better_Product?

No, because Better_Product is a different type than Product and such operation would not be considered overriding. This works properly in just about any other language with support for OO.

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


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08  7:45                     ` J-P. Rosen
@ 2014-08-08  8:04                       ` Dmitry A. Kazakov
  2014-08-08  8:55                         ` J-P. Rosen
  0 siblings, 1 reply; 73+ messages in thread
From: Dmitry A. Kazakov @ 2014-08-08  8:04 UTC (permalink / raw)


On Fri, 08 Aug 2014 09:45:41 +0200, J-P. Rosen wrote:

> Le 07/08/2014 18:10, Dmitry A. Kazakov a écrit :
>>> Classification makes sense only if you have
>>> > heterogeneous data structures that manipulate various types belonging to
>>> > a same class. This is rarely the case for elementary types.
>> It is in any math book. Fields, groups, rings, spaces are such
>> classifications known for centuries.
> 
> Huh? I was talking about having containers holding values of different
> types. You are answering with classification in mathematics. I fail to
> see the connection.

I thought you argued that classifications were non-existent. So it is
against generic programming? That would include generics.

As for class-wide containers, *any* GUI library is over the top of such
stuff.

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

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08  7:49                     ` J-P. Rosen
@ 2014-08-08  8:12                       ` Shark8
  2014-08-08  8:26                         ` Dmitry A. Kazakov
  0 siblings, 1 reply; 73+ messages in thread
From: Shark8 @ 2014-08-08  8:12 UTC (permalink / raw)


On 08-Aug-14 01:49, J-P. Rosen wrote:
> that's why I regularly object to the
> argument that "you can do everything with OOP, therefore you must do
> everything with OOP".

I certainly agree.
One of the biggest disservices the CS education establishment has done 
[IMO] is to push OOP (and especially extensibility) to the point that 
many CS graduates have the idea that "if you can't extend it, it's 
bad/worthless/flawed."

Restriction is so pervasive [we all used it in math, esp. for proofs], 
and useful that I find it amazing that Ada's Subtype facility *isn't* a 
common thing in programming languages -- and there are [lots of] 
programmers who seem not to grasp the utility thereof. :(

I mean you really can't use OOP to do:
    Subtype Natural_Float is Float range 0.0 .. Float'Last;
    Function Sqrt( X: Natural_Float ) return Natural_Float;
{At least not elegantly.}


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08  7:54           ` Maciej Sobczak
@ 2014-08-08  8:14             ` Dmitry A. Kazakov
  2014-08-08 13:06               ` Maciej Sobczak
  2014-08-08  8:34             ` Shark8
  1 sibling, 1 reply; 73+ messages in thread
From: Dmitry A. Kazakov @ 2014-08-08  8:14 UTC (permalink / raw)


On Fri, 8 Aug 2014 00:54:01 -0700 (PDT), Maciej Sobczak wrote:

> W dniu czwartek, 7 sierpnia 2014 10:50:52 UTC+2 użytkownik Dmitry A. Kazakov napisał:
> 
>>> and no support for type covariance on return
>>> type Ada is way more broken than other languages I am aware of.
>> 
>> I don't understand this. The return type is covariant in Ada.
> 
> Can I have Better_Factory type with a primitive operation returning Better_Product?

I still do not understand the example. Is the operation in question
primitive for both the factory and product hierarchy? That is MD.

> No, because Better_Product is a different type than Product and such
> operation would not be considered overriding.

Different how? Unrelated, derived from?

------------------
Covariance means that upon inheritance the argument or result of an
operation mutates to the derived type. All primitive operations in Ada are
covariant per definition. The only way to have an operation contravariant
is to declare it after the freezing point (in another package) or having
the argument/result class-wide => non-primitive.

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

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08  7:43                           ` Dmitry A. Kazakov
@ 2014-08-08  8:18                             ` Shark8
  0 siblings, 0 replies; 73+ messages in thread
From: Shark8 @ 2014-08-08  8:18 UTC (permalink / raw)


On 08-Aug-14 01:43, Dmitry A. Kazakov wrote:
> On Thu, 07 Aug 2014 16:53:50 -0400, Robert A Duff wrote:
>
>> I think types should be generic, instead.  See Eiffel.
>
> You need some clearl  defined scope where the format parameter would be
> visible:
>
>     generic
>         with ... Something;
>     type Generic_Mess is ...;
>     ...
>     -- many lines below
>
>     procedure Bar (Y : Generic_Mess; X : Something);
>
>     -- even more lines after. Is this OK?
>     procedure Foo (X : Something) return String;
>
> But, surely, discriminants do the job to me.

I think you misunderstand him -- what he's saying, to me, sounds a lot 
like your "type-classes" or my "abstract type" idea.

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08  8:12                       ` Shark8
@ 2014-08-08  8:26                         ` Dmitry A. Kazakov
  2014-08-08 11:10                           ` Shark8
  0 siblings, 1 reply; 73+ messages in thread
From: Dmitry A. Kazakov @ 2014-08-08  8:26 UTC (permalink / raw)


On Fri, 08 Aug 2014 02:12:00 -0600, Shark8 wrote:

> Restriction is so pervasive [we all used it in math, esp. for proofs], 
> and useful that I find it amazing that Ada's Subtype facility *isn't* a 
> common thing in programming languages -- and there are [lots of] 
> programmers who seem not to grasp the utility thereof. :(

It is a common thing still. E.g. const int is such a type, int constrained
by disallowing mutators.

OO favored extension because it keept substitutability for immutable
operations. Extension breaks mutators and out-arguments/results, which
aren't supported anyway in most OOPL.

The idea that subtyping can be directly reflect substitutability is the
root problem and the idea that the set of values could somehow define the
type so generalization or specialization might mean something. Ada's
subtypes suffer this as well. Both are wrong.

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


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08  7:54           ` Maciej Sobczak
  2014-08-08  8:14             ` Dmitry A. Kazakov
@ 2014-08-08  8:34             ` Shark8
  2014-08-08 12:59               ` Maciej Sobczak
  1 sibling, 1 reply; 73+ messages in thread
From: Shark8 @ 2014-08-08  8:34 UTC (permalink / raw)


On 08-Aug-14 01:54, Maciej Sobczak wrote:
> W dniu czwartek, 7 sierpnia 2014 10:50:52 UTC+2 użytkownik Dmitry A. Kazakov napisał:
>
>>> and no support for type covariance on return
>>> type Ada is way more broken than other languages I am aware of.
>>
>> I don't understand this. The return type is covariant in Ada.
>
> Can I have Better_Factory type with a primitive operation returning Better_Product?
>
> No, because Better_Product is a different type than Product and such operation
> would not be considered overriding. This works properly in just about any other
> language with support for OO.
>

Can't you use some class-wide functions, some primitive functions, and 
the Generic_Dispatching_Constructor function to do this?

IIRC something like:

   Type Base is abstract tagged null record;
   Function Product return Base is abstract; -- Primitive function.
   Function Get_Product return Base'Class;   -- Dispatches call to Product.
   -- Uses generic_dispatching constructor.
   Function Make(Stream : not null access
                          Ada.Streams.Root_Stream_Type'Class)
         return Base'Class;                  -- For Stream-creation.
   -- Perhaps some other creation functions.
   -- ...

   Type Child is tagged ...

Or am I misunderstanding you?

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08  7:48           ` Maciej Sobczak
@ 2014-08-08  8:51             ` J-P. Rosen
  2014-08-08 13:25               ` Maciej Sobczak
  0 siblings, 1 reply; 73+ messages in thread
From: J-P. Rosen @ 2014-08-08  8:51 UTC (permalink / raw)


Le 08/08/2014 09:48, Maciej Sobczak a écrit :
>> You belong to the second category

> I did not write anything that would allow you to make such claims. In
> fact, I find myself using OOP very rarely in my current projects -
> but when I do it I expect consistent support.
Sorry, "you" was addressed to Dmitry (I hope he will agree to be
designated as "OOP purist" ;-) ).

>> but some of us belong to the first one.
> 
> And you are OK with broken support for the tool that you are using
> occasionally? This is dangerous as it allows to justify broken
> support for every other language feature - after all, every one is
> just "one tool among others". Ada should do better than that.
> 
1) I never missed the features that you (and others) argue are missing
to Ada, therefore I don't feel that Ada is "broken" in that aspect

2) I am afraid that adding those features would have an adverse effect
on other parts of the language that I do use. My feeling (but I'm ready
to be corrected) is that you can't have the same features in a "pure" OO
language and in a "mixed paradigms" language, because of different
trade-offs.

<rant> (not specially addressing anybody in particular)
I'm a bit tired of those messages here claiming that Ada is "broken".
Ada is not perfect, it is "only" the best language for software engineering.
Ada has a big disadvantage: like any sophisticated technic, it needs to
be taught, and it needs to be learned. My general advice is: learn how
to use it; sometimes, you'll have to do things in less straightforward
ways than in other languages, but that's the price to pay for the added
safety. In the end, you'll win.
</rant>

-- 
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] 73+ messages in thread

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08  8:04                       ` Dmitry A. Kazakov
@ 2014-08-08  8:55                         ` J-P. Rosen
  2014-08-08  9:13                           ` Dmitry A. Kazakov
  0 siblings, 1 reply; 73+ messages in thread
From: J-P. Rosen @ 2014-08-08  8:55 UTC (permalink / raw)


Le 08/08/2014 10:04, Dmitry A. Kazakov a écrit :
> I thought you argued that classifications were non-existent. So it is
> against generic programming? That would include generics.

No, but I do argue that the fact that classifications exists in other
disciplines does not necessarily imply that it is appropriate for
software development, and especially that it is appropriate to all
software development.

And no, I do not consider generic programming as a classification. I
would argue that it is the opposite of classification: it allows you to
develop algorithms that can be applied to types that have some features,
without requiring that these types have a common "is-a" relationship.

-- 
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] 73+ messages in thread

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08  8:55                         ` J-P. Rosen
@ 2014-08-08  9:13                           ` Dmitry A. Kazakov
  2014-08-08 10:01                             ` J-P. Rosen
  0 siblings, 1 reply; 73+ messages in thread
From: Dmitry A. Kazakov @ 2014-08-08  9:13 UTC (permalink / raw)


On Fri, 08 Aug 2014 10:55:19 +0200, J-P. Rosen wrote:

> Le 08/08/2014 10:04, Dmitry A. Kazakov a écrit :
>> I thought you argued that classifications were non-existent. So it is
>> against generic programming? That would include generics.
> 
> No, but I do argue that the fact that classifications exists in other
> disciplines does not necessarily imply that it is appropriate for
> software development, and especially that it is appropriate to all
> software development.

How mathematics may not apply to the elementary types like Integer?

> And no, I do not consider generic programming as a classification. I
> would argue that it is the opposite of classification: it allows you to
> develop algorithms that can be applied to types that have some features,
> without requiring that these types have a common "is-a" relationship.

That does not make sense. "is-a" actually means nothing but "is a thing
with some features."

Do you propose not to formalize "some features"? This is not how Ada
generics work anyway. "Some features" are formalized in Ada through formal
generic parameters. The only difference to classes is that classes do that
through types, while generics do in an untyped manner.

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

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08  9:13                           ` Dmitry A. Kazakov
@ 2014-08-08 10:01                             ` J-P. Rosen
  2014-08-08 10:53                               ` Dmitry A. Kazakov
  0 siblings, 1 reply; 73+ messages in thread
From: J-P. Rosen @ 2014-08-08 10:01 UTC (permalink / raw)


Le 08/08/2014 11:13, Dmitry A. Kazakov a écrit :
> How mathematics may not apply to the elementary types like Integer?
Because computer integers are not the same as mathematical ones, and the
way they are used are different.

Moreover, classification is used in mathematics for the theory of
numbers, which is not relevant to practical usage of numbers.

> Do you propose not to formalize "some features"? This is not how Ada
> generics work anyway. "Some features" are formalized in Ada through formal
> generic parameters. The only difference to classes is that classes do that
> through types, while generics do in an untyped manner.

And those types must be related through inheritance, while generics may
be instantiated on types that have no conceptual relationship.

Of course, at implementation level it boils down to managing pointers to
subprograms, but conceptually, it is quite different.


-- 
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] 73+ messages in thread

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08 10:01                             ` J-P. Rosen
@ 2014-08-08 10:53                               ` Dmitry A. Kazakov
  2014-08-08 10:56                                 ` Victor Porton
  2014-08-08 12:00                                 ` J-P. Rosen
  0 siblings, 2 replies; 73+ messages in thread
From: Dmitry A. Kazakov @ 2014-08-08 10:53 UTC (permalink / raw)


On Fri, 08 Aug 2014 12:01:48 +0200, J-P. Rosen wrote:

> Le 08/08/2014 11:13, Dmitry A. Kazakov a écrit :
>> How mathematics may not apply to the elementary types like Integer?
> Because computer integers are not the same as mathematical ones, and the
> way they are used are different.

Interesting, it was always OO proponents' argument that numbers are not
numbers.
 
> Moreover, classification is used in mathematics for the theory of
> numbers, which is not relevant to practical usage of numbers.

Having integers ordered is unpractical? Being them additive has no usage?

>> Do you propose not to formalize "some features"? This is not how Ada
>> generics work anyway. "Some features" are formalized in Ada through formal
>> generic parameters. The only difference to classes is that classes do that
>> through types, while generics do in an untyped manner.
> 
> And those types must be related through inheritance, while generics may
> be instantiated on types that have no conceptual relationship.

I don't know which relationships are "conceptual" and which are not.

generic
   type Element_Type is private;
   with function "<" (Left, Right : Element_Type) return Boolean is <>;
   with function "=" (Left, Right : Element_Type) return Boolean is <>;
package Ada.Containers.Ordered_Sets is

Isn't all types acceptable as Element_Type a "conceptual" class?

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


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08 10:53                               ` Dmitry A. Kazakov
@ 2014-08-08 10:56                                 ` Victor Porton
  2014-08-08 12:00                                 ` J-P. Rosen
  1 sibling, 0 replies; 73+ messages in thread
From: Victor Porton @ 2014-08-08 10:56 UTC (permalink / raw)


Dmitry A. Kazakov wrote:

> On Fri, 08 Aug 2014 12:01:48 +0200, J-P. Rosen wrote:
> 
>> Le 08/08/2014 11:13, Dmitry A. Kazakov a écrit :
>>> How mathematics may not apply to the elementary types like Integer?
>> Because computer integers are not the same as mathematical ones, and the
>> way they are used are different.
> 
> Interesting, it was always OO proponents' argument that numbers are not
> numbers.
>  
>> Moreover, classification is used in mathematics for the theory of
>> numbers, which is not relevant to practical usage of numbers.
> 
> Having integers ordered is unpractical? Being them additive has no usage?
> 
>>> Do you propose not to formalize "some features"? This is not how Ada
>>> generics work anyway. "Some features" are formalized in Ada through
>>> formal generic parameters. The only difference to classes is that
>>> classes do that through types, while generics do in an untyped manner.
>> 
>> And those types must be related through inheritance, while generics may
>> be instantiated on types that have no conceptual relationship.
> 
> I don't know which relationships are "conceptual" and which are not.
> 
> generic
>    type Element_Type is private;
>    with function "<" (Left, Right : Element_Type) return Boolean is <>;
>    with function "=" (Left, Right : Element_Type) return Boolean is <>;
> package Ada.Containers.Ordered_Sets is
> 
> Isn't all types acceptable as Element_Type a "conceptual" class?

Making elementary classes would certainly require multiple inheritance (and 
even "virtual" multiple inheritance, in C++ terms).

I think it would be very hard to modify Ada standard to support this.

-- 
Victor Porton - http://portonvictor.org


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08  8:26                         ` Dmitry A. Kazakov
@ 2014-08-08 11:10                           ` Shark8
  2014-08-08 11:20                             ` Dmitry A. Kazakov
  0 siblings, 1 reply; 73+ messages in thread
From: Shark8 @ 2014-08-08 11:10 UTC (permalink / raw)


On 08-Aug-14 02:26, Dmitry A. Kazakov wrote:
> The idea that subtyping can be directly reflect substitutability is the
> root problem and the idea that the set of values could somehow define the
> type so generalization or specialization might mean something. Ada's
> subtypes suffer this as well. Both are wrong.

I don't understand this; subtypes are perfectly fine: essentially they 
are subsets over the set of values that a type may take. -- Is this to 
say they are a magic bullet? Nope.

But that certainly covers a lot of things that would otherwise make for 
sloppy and error-prone programs -- it keeps things neat, being able to 
[essentially] say parameter [or return-value] X of subprogram K is a 
subset of the values of Type T.


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08 11:10                           ` Shark8
@ 2014-08-08 11:20                             ` Dmitry A. Kazakov
  2014-08-08 19:34                               ` Shark8
  0 siblings, 1 reply; 73+ messages in thread
From: Dmitry A. Kazakov @ 2014-08-08 11:20 UTC (permalink / raw)


On Fri, 08 Aug 2014 05:10:25 -0600, Shark8 wrote:

> On 08-Aug-14 02:26, Dmitry A. Kazakov wrote:
>> The idea that subtyping can be directly reflect substitutability is the
>> root problem and the idea that the set of values could somehow define the
>> type so generalization or specialization might mean something. Ada's
>> subtypes suffer this as well. Both are wrong.
> 
> I don't understand this; subtypes are perfectly fine: essentially they 
> are subsets over the set of values that a type may take.

And they break in-operations. As an example consider:

   X : Integer := -1;

Now substitute Positive for Integer.

Subsetting means nothing to subtyping and both very little to
substitutability. All three are different things.

> -- Is this to say they are a magic bullet? Nope.

Huh, great mathematical problems are about fighting constraints. E.g.
solving x**n + y**n = z**n in real numbers vs. in natural ones. No big
deal? Same applies to programming, it is mostly about working around
constraints.

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


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08 10:53                               ` Dmitry A. Kazakov
  2014-08-08 10:56                                 ` Victor Porton
@ 2014-08-08 12:00                                 ` J-P. Rosen
  2014-08-08 13:11                                   ` Dmitry A. Kazakov
  1 sibling, 1 reply; 73+ messages in thread
From: J-P. Rosen @ 2014-08-08 12:00 UTC (permalink / raw)


Le 08/08/2014 12:53, Dmitry A. Kazakov a écrit :
>> Moreover, classification is used in mathematics for the theory of
>> numbers, which is not relevant to practical usage of numbers.
> 
> Having integers ordered is unpractical? Being them additive has no usage?
> 
Yes of course, but the /theory/ of it, and especially group theory etc.
that you mentioned is not a programmer's concern.

> I don't know which relationships are "conceptual" and which are not.
> 
> generic
>    type Element_Type is private;
>    with function "<" (Left, Right : Element_Type) return Boolean is <>;
>    with function "=" (Left, Right : Element_Type) return Boolean is <>;
> package Ada.Containers.Ordered_Sets is
> 
> Isn't all types acceptable as Element_Type a "conceptual" class?
> 
I argue they are not. If you provide an operation that operates on a
class wide type, then it can be used only on types belonging to the
class, which means there is a dependency between these types.

A generic can be applied to types that are not related in any way.

This reminds me of a (bad) example of inheritance I once saw in a book:
the class "parrot" inherited from the class "human" because it needed
the method "can_speak". I'm somewhat uncomfortable with the notion that
a parrot is a special kind of human ;-). Well, it's a bad example
because inheritance should not be used just to grab any method you need.
There must be some /conceptual/ dependence, i.e. some "is-a" dependency.
That's what I meant: a generic "can_speak" function that could be
instantiated on humans or parrots would be much less disturbing - to my
taste.

-- 
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] 73+ messages in thread

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08  8:34             ` Shark8
@ 2014-08-08 12:59               ` Maciej Sobczak
  2014-08-08 22:37                 ` Randy Brukardt
  0 siblings, 1 reply; 73+ messages in thread
From: Maciej Sobczak @ 2014-08-08 12:59 UTC (permalink / raw)


W dniu piątek, 8 sierpnia 2014 10:34:43 UTC+2 użytkownik Shark8 napisał:

> Can't you use some class-wide functions, some primitive functions, and 
> the Generic_Dispatching_Constructor function to do this?

Sure. That's why I call it "broken". It's not "broken beyond all repair", but rather "broken so that working around it is painful".

Proper use of OO should not require any workarounds.

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

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08  8:14             ` Dmitry A. Kazakov
@ 2014-08-08 13:06               ` Maciej Sobczak
  2014-08-08 13:22                 ` Dmitry A. Kazakov
  2014-08-08 22:26                 ` Randy Brukardt
  0 siblings, 2 replies; 73+ messages in thread
From: Maciej Sobczak @ 2014-08-08 13:06 UTC (permalink / raw)


W dniu piątek, 8 sierpnia 2014 10:14:27 UTC+2 użytkownik Dmitry A. Kazakov napisał:

> I still do not understand the example.

http://en.wikipedia.org/wiki/Covariant_return_type

> Is the operation in question
> primitive for both the factory and product hierarchy? That is MD.

I don't consider it to be an example of MD, because the two types (factory and product) do not play equal roles in the dispatch. Namely, the operation is expected to dispatch on the factory type only.

The example from Wikipedia is straightforward and does not require any hacks in C++ and in (newer versions of) Java. Moreover, it represents a quite frequent design problem (special coffee machine can prepare special coffee, etc.) and all creational design patterns have potential for its applications.

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


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08 12:00                                 ` J-P. Rosen
@ 2014-08-08 13:11                                   ` Dmitry A. Kazakov
  2014-08-08 13:53                                     ` J-P. Rosen
  0 siblings, 1 reply; 73+ messages in thread
From: Dmitry A. Kazakov @ 2014-08-08 13:11 UTC (permalink / raw)


On Fri, 08 Aug 2014 14:00:26 +0200, J-P. Rosen wrote:

> Le 08/08/2014 12:53, Dmitry A. Kazakov a écrit :
>>> Moreover, classification is used in mathematics for the theory of
>>> numbers, which is not relevant to practical usage of numbers.
>> 
>> Having integers ordered is unpractical? Being them additive has no usage?
>> 
> Yes of course, but the /theory/ of it, and especially group theory etc.
> that you mentioned is not a programmer's concern.

How so? If integer is not ordered there is no "<" defined, if there is no
"<" how are you going to have an ordered map with integer keys?

>> I don't know which relationships are "conceptual" and which are not.
>> 
>> generic
>>    type Element_Type is private;
>>    with function "<" (Left, Right : Element_Type) return Boolean is <>;
>>    with function "=" (Left, Right : Element_Type) return Boolean is <>;
>> package Ada.Containers.Ordered_Sets is
>> 
>> Isn't all types acceptable as Element_Type a "conceptual" class?
>> 
> I argue they are not. If you provide an operation that operates on a
> class wide type, then it can be used only on types belonging to the
> class, which means there is a dependency between these types.

I don't see any dependency, but that was not the question. It was - do
private types with "<" and "=" form a "conceptual" class. Do acceptable
actual types of a generic form one?

> A generic can be applied to types that are not related in any way.

They are related in exactly the way that this generic can be applied to
them. Is the feature of being applicable in a generic relevant for
programmers? I think it is. 

> This reminds me of a (bad) example of inheritance I once saw in a book:
> the class "parrot" inherited from the class "human" because it needed
> the method "can_speak". I'm somewhat uncomfortable with the notion that
> a parrot is a special kind of human ;-). Well, it's a bad example
> because inheritance should not be used just to grab any method you need.

It is bad design, because the class of things that can speak is not the
class of humans. Parrots and humans certainly participate in some classes,
e.g. in Chordates, Tetrapoda etc.

> There must be some /conceptual/ dependence, i.e. some "is-a" dependency.
> That's what I meant: a generic "can_speak" function that could be
> instantiated on humans or parrots would be much less disturbing - to my
> taste.

It is incredibly disturbing because there is no difference between:

   function Can_Speak (X : Thing) return Boolean;

and

   function Is_Empty (X : Thing) return Boolean;

This is exactly the point why generics are untyped in their heart. There is
tight relationship between operations =, /=, <, >, >=, <=, 'Prev, 'Next of
an ordered set. This is what makes it such a thing. Inheriting to Ordered
tells to the reader all this in just one source line. Moreover, it allows
the compiler to check if the manifested type is indeed ordered and even
prove some of this like x=y <=> not x/=y. Compare this with generics. They
just name some operations and the programmer should guess about the purpose
of what the actual type should be. Yes there is no dependency ... on the
application domain. Just an ad-hoc mess.

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


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08 13:06               ` Maciej Sobczak
@ 2014-08-08 13:22                 ` Dmitry A. Kazakov
  2014-08-08 22:32                   ` Randy Brukardt
  2014-08-09 16:11                   ` Maciej Sobczak
  2014-08-08 22:26                 ` Randy Brukardt
  1 sibling, 2 replies; 73+ messages in thread
From: Dmitry A. Kazakov @ 2014-08-08 13:22 UTC (permalink / raw)


On Fri, 8 Aug 2014 06:06:41 -0700 (PDT), Maciej Sobczak wrote:

> W dniu piątek, 8 sierpnia 2014 10:14:27 UTC+2 użytkownik Dmitry A. Kazakov napisał:
> 
>> I still do not understand the example.
> 
> http://en.wikipedia.org/wiki/Covariant_return_type

type A is tagged null record;
function getFoo return A;

type B is new A with null record;
overriding function getFoo return B; -- Covariant!

>> Is the operation in question
>> primitive for both the factory and product hierarchy? That is MD.
> 
> I don't consider it to be an example of MD, because the two types (factory
> and product) do not play equal roles in the dispatch. Namely, the
> operation is expected to dispatch on the factory type only.

No dispatch, no covariance. If you are in the hierarchy of the factory
type, there cannot be any covariance in an unrelated hierarchy. Unless you
make it MD. Even then inheriting to factory would have no effect on
product.

The only case where this may happen is parallel type hierarchies when two
types are inherited synchronously, e.g.

   type Object is tagged ...
   type Handle is tagged ...
   function Access (X : Handle_To_Object) return Object;

   type New_Object is new Object with ...

must produce

   type New_Handle is new Handle with ...

and

   function Access (X : New_Handle) return New_Object;

No OOPL I know can handle this.

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

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08  8:51             ` J-P. Rosen
@ 2014-08-08 13:25               ` Maciej Sobczak
  2014-08-08 13:34                 ` J-P. Rosen
  2014-08-08 22:18                 ` Randy Brukardt
  0 siblings, 2 replies; 73+ messages in thread
From: Maciej Sobczak @ 2014-08-08 13:25 UTC (permalink / raw)


W dniu piątek, 8 sierpnia 2014 10:51:15 UTC+2 użytkownik J-P. Rosen napisał:

> 1) I never missed the features that you (and others) argue are missing
> to Ada, therefore I don't feel that Ada is "broken" in that aspect

I can assure you that almost 100% of C programmers do not miss range checking, for example. :-D

For each possible language feature there is at least one programmer who does not miss it.

> 2) I am afraid that adding those features would have an adverse effect
> on other parts of the language that I do use.

Can we try to analyse some of the features in question?

> <rant> (not specially addressing anybody in particular)
> I'm a bit tired of those messages here claiming that Ada is "broken".
> Ada is not perfect, it is "only" the best language for software engineering.
> Ada has a big disadvantage: like any sophisticated technic, it needs to
> be taught, and it needs to be learned. My general advice is: learn how
> to use it; sometimes, you'll have to do things in less straightforward
> ways than in other languages, but that's the price to pay for the added
> safety. In the end, you'll win.
> </rant>

I mostly agree, except that the "safety" argument is also already worn out. That is, it is too frequently used to escape from the discussion. If I claim that some feature is missing from Ada and you say that it is the price to pay for the added safety, then I ask for a proper argument showing that a given feature would indeed impair the language safety in some way. Without such demonstration your position is incomplete and therefore unconvincing.

In particular (1), I have pointed that that Ada's handling of dispatch during initialization/finalization is *unsafe*. Obviously I'm not going to buy the argument that a missing feature here is a price for added safety!

In particular (2), the part that took Dmitry's attention (convariance on return type) can be also analysed in terms of language safety. I claim that the feature is safe in a) it does not lead to unsafe situations (please someone correct me on this) and b) the workarounds are ugly and therefore have potential for introducing bugs. In other words, having this feature would be actually safer than not having it.
So, again, I'm not convinced by the argument that every Ada problem can be justified by some virtual added safety.

Note: I agree with your claim that Ada is "only" the best language for SE.

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

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08 13:25               ` Maciej Sobczak
@ 2014-08-08 13:34                 ` J-P. Rosen
  2014-08-08 13:52                   ` Dmitry A. Kazakov
  2014-08-08 22:18                 ` Randy Brukardt
  1 sibling, 1 reply; 73+ messages in thread
From: J-P. Rosen @ 2014-08-08 13:34 UTC (permalink / raw)


Le 08/08/2014 15:25, Maciej Sobczak a écrit :
> W dniu piątek, 8 sierpnia 2014 10:51:15 UTC+2 użytkownik J-P. Rosen napisał:
> 
>> 1) I never missed the features that you (and others) argue are missing
>> to Ada, therefore I don't feel that Ada is "broken" in that aspect
> 
> I can assure you that almost 100% of C programmers do not miss range checking, for example. :-D
:-) Note that I didn't say the features were useless, just that I didn't
/feel/ Ada broken...

> Can we try to analyse some of the features in question?
[...]

The features you mention may actually be cases for improvements (I would
have to dig further). I was more thinking about the calls for MD, etc..

-- 
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] 73+ messages in thread

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08 13:34                 ` J-P. Rosen
@ 2014-08-08 13:52                   ` Dmitry A. Kazakov
  2014-08-08 14:21                     ` J-P. Rosen
  2014-08-08 22:08                     ` Randy Brukardt
  0 siblings, 2 replies; 73+ messages in thread
From: Dmitry A. Kazakov @ 2014-08-08 13:52 UTC (permalink / raw)


On Fri, 08 Aug 2014 15:34:41 +0200, J-P. Rosen wrote:

> I was more thinking about the calls for MD, etc..

How MD can be less safe?

1. Consider non-dispatching calls. Uncontrolled overloading were safer?

2. Consider dispatching calls. Constraint_Error on different tags is safer?

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

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08 13:11                                   ` Dmitry A. Kazakov
@ 2014-08-08 13:53                                     ` J-P. Rosen
  2014-08-08 20:23                                       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 73+ messages in thread
From: J-P. Rosen @ 2014-08-08 13:53 UTC (permalink / raw)


Le 08/08/2014 15:11, Dmitry A. Kazakov a écrit :
>> Yes of course, but the /theory/ of it, and especially group theory etc.
>> that you mentioned is not a programmer's concern.
> 
> How so? If integer is not ordered there is no "<" defined, if there is no
> "<" how are you going to have an ordered map with integer keys?
Well, of course the computer Integer has "<", but to use it I don't need
to know (nor do I give a damn) that it is a group, and that other types
are also groups.


>> A generic can be applied to types that are not related in any way.
> 
> They are related in exactly the way that this generic can be applied to
> them. Is the feature of being applicable in a generic relevant for
> programmers? I think it is. 
The point is that of logical dependency. If I have a type T, and want to
use an operation defined on class C, I have to make my type a member of
C. And C has other members, that become somehow the brothers of T. LSP
means that they can be interchanged in some situations.

With a generic G, of course T has to match the contract imposed by the
formals of G, but there is no connection to other types that may
instantiate the same generic.

Now, you can define the "class of all types that can instantiate G".
Possible, but useless.

>> This reminds me of a (bad) example of inheritance I once saw in a book:
>> the class "parrot" inherited from the class "human" because it needed
>> the method "can_speak". I'm somewhat uncomfortable with the notion that
>> a parrot is a special kind of human ;-). Well, it's a bad example
>> because inheritance should not be used just to grab any method you need.
> 
> It is bad design, because the class of things that can speak is not the
> class of humans. Parrots and humans certainly participate in some classes,
> e.g. in Chordates, Tetrapoda etc.
The point is that often people write a method on a class, and then
inherit from it because they want to reuse a method. Inheritance is used
for "uses" relationship, not for "is-a". It is an abuse of inheritance,
but very frequent (even in basic Java classes).

> This is exactly the point why generics are untyped in their heart.
In the sense that they can be applied to any kind of type that matches
the contract, yes. And that's a good thing.

> There is
> tight relationship between operations =, /=, <, >, >=, <=, 'Prev, 'Next of
> an ordered set. This is what makes it such a thing. Inheriting to Ordered
> tells to the reader all this in just one source line. Moreover, it allows
> the compiler to check if the manifested type is indeed ordered and even
> prove some of this like x=y <=> not x/=y. 
Certainly not. Inheriting from Ordered guarantees that all these
operations are available, but say nothing about the semantics. If you
want to add semantics, use type invariants and the like.

> Compare this with generics. They
> just name some operations and the programmer should guess about the purpose
> of what the actual type should be. Yes there is no dependency ... on the
> application domain. Just an ad-hoc mess.
> 
It's not a mess. It's generality. The actual type should be anything
that matches the contract.

-- 
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] 73+ messages in thread

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08 13:52                   ` Dmitry A. Kazakov
@ 2014-08-08 14:21                     ` J-P. Rosen
  2014-08-08 20:23                       ` Dmitry A. Kazakov
  2014-08-08 22:08                     ` Randy Brukardt
  1 sibling, 1 reply; 73+ messages in thread
From: J-P. Rosen @ 2014-08-08 14:21 UTC (permalink / raw)


Le 08/08/2014 15:52, Dmitry A. Kazakov a écrit :

> 1. Consider non-dispatching calls. Uncontrolled overloading were safer?
What is uncontrolled overloading?

> 2. Consider dispatching calls. Constraint_Error on different tags is safer?
> 
At least, well defined. And does not require writing N**2 functions...
Or how would you implement MD?

-- 
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] 73+ messages in thread

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08 11:20                             ` Dmitry A. Kazakov
@ 2014-08-08 19:34                               ` Shark8
  2014-08-08 20:23                                 ` Dmitry A. Kazakov
  0 siblings, 1 reply; 73+ messages in thread
From: Shark8 @ 2014-08-08 19:34 UTC (permalink / raw)


On 08-Aug-14 05:20, Dmitry A. Kazakov wrote:
> And they [subtypes] break in-operations. As an example consider:
>
>     X : Integer := -1;
>
> Now substitute Positive for Integer.

That's going the wrong way.
You're narrowing the set when you move to the subtype, so obviously not 
all values will be present; this is a Good Thing.

For example, we can enforce consistency [and correctness] in a DB with 
subtypes:

     Subtype Digit is Character range '0'..'9';

     -- The following is a string, of length 9, that has ONLY digits.
     Subtype Social_Security_Number is String(1..9)
     with Dynamic_Predicate =>
       (for all C of Social_Security_Number => C in Digit);

     -- The following function cannot have an invalid invalid SSN parameter.
     Procedure Save( SSN : Social_Security_Number; ID: User_ID);
     Function  Load(ID: User_ID) return Social_Security_Number;

And this is good because we *don't* want any string in the DB's SSN 
field, we only want strings which are SSNs.

Likewise, we may want Ada-like identifiers, say in a mapping:

     -- Validation rules:
     -- #1 - Identifier cannot be the empty-string.
     -- #2 - Identifier must contain only alphanumeric characters + 
underscore.
     -- #3 - Identifier cannot begin with a digit.
     -- #4 - Identifier cannot begin or end with an underscore.
     -- #5 - Identifier cannot have two consecutive underscores.
     Function Valid_Identifier(Input : String) return Boolean;

     -- A string containing an identifier.
     Subtype Identifier is String
       with Dynamic_Predicate => Valid_Identifier( Identifier )
                                 or else raise Constraint_Error;

     -- This package defines a mapping of a name to a type; both of these
     -- are instances of Identifier.
     Package Attribute_List is new Ada.Containers.Indefinite_Ordered_Maps(
         Key_Type     => Identifier,
         Element_Type => Identifier
       );

     -- ...in body.

     Function Valid_Identifier(Input : String) return Boolean is
         Subtype Internal_Range is Natural range 
Input'First+1..Input'Last-1;
         First : Character renames Input(Input'First);
         Last  : Character renames Input(Input'Last);

         Use Ada.Characters.Handling;
     Begin
         -- Initialize w/ conformance to rule #1.
         Return Result : Boolean:= Input'Length in Positive do
             -- Rule 2
             Result:= Result and
               (For all C of Input => Is_Alphanumeric(C) OR C = '_');
             -- Rule 3
             Result:= Result and not Is_Decimal_Digit(First);
             -- Rule 4
             Result:= Result and First /= '_' and Last /= '_';
             -- Rule 5
             Result:= Result and
               (for all Index in Internal_Range =>
                  (if Input(Index) = '_' then Input(Index+1) /= '_')
               );
         end return;
     End Valid_Identifier;


And this is good.
We *don't* want to substitute STRING for Social_Security_Number or 
Identifier as the values that STRING can take are outside what we want 
to deal with... and if we had to deal with validation at every 
subprogram-call or function-return then Ada would be little better than PHP.

 > Subsetting means nothing to subtyping and both very little to
substitutability. All three are different things.

Ridiculous; as shown above subtyping *is* the subsetting of the valid 
values: Social_Security_Number in particular has only 10**9 values 
rather than the Σ(n=0..Positive'Last) 256**n values that the STRING type 
would have.

>
> Huh, great mathematical problems are about fighting constraints. E.g.
> solving x**n + y**n = z**n in real numbers vs. in natural ones. No big
> deal? Same applies to programming, it is mostly about working around
> constraints.

...that's the most idiotic thing I've *ever* heard you say.
Constraints are fundamental for mathematical proofs; they are essential 
for making robust programs. (HINT: definitions are often constraints.)

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08 13:53                                     ` J-P. Rosen
@ 2014-08-08 20:23                                       ` Dmitry A. Kazakov
  0 siblings, 0 replies; 73+ messages in thread
From: Dmitry A. Kazakov @ 2014-08-08 20:23 UTC (permalink / raw)


On Fri, 08 Aug 2014 15:53:52 +0200, J-P. Rosen wrote:

> Le 08/08/2014 15:11, Dmitry A. Kazakov a écrit :
>>> Yes of course, but the /theory/ of it, and especially group theory etc.
>>> that you mentioned is not a programmer's concern.
>> 
>> How so? If integer is not ordered there is no "<" defined, if there is no
>> "<" how are you going to have an ordered map with integer keys?
> Well, of course the computer Integer has "<", but to use it I don't need
> to know (nor do I give a damn) that it is a group, and that other types
> are also groups.

The question was about maps. Should maps be restricted strictly integer
keys?

>>> A generic can be applied to types that are not related in any way.
>> 
>> They are related in exactly the way that this generic can be applied to
>> them. Is the feature of being applicable in a generic relevant for
>> programmers? I think it is. 
> The point is that of logical dependency. If I have a type T, and want to
> use an operation defined on class C, I have to make my type a member of
> C. And C has other members, that become somehow the brothers of T. LSP
> means that they can be interchanged in some situations.

So are formal generic types. They are somehow brothers and they can be
interchanged in instantiations. You can instantiate a generic with one type
or another.

> Now, you can define the "class of all types that can instantiate G".
> Possible, but useless.

And having a useless class makes an advantage over having a useful class? I
don't understand the logic.
 
>>> This reminds me of a (bad) example of inheritance I once saw in a book:
>>> the class "parrot" inherited from the class "human" because it needed
>>> the method "can_speak". I'm somewhat uncomfortable with the notion that
>>> a parrot is a special kind of human ;-). Well, it's a bad example
>>> because inheritance should not be used just to grab any method you need.
>> 
>> It is bad design, because the class of things that can speak is not the
>> class of humans. Parrots and humans certainly participate in some classes,
>> e.g. in Chordates, Tetrapoda etc.
> The point is that often people write a method on a class, and then
> inherit from it because they want to reuse a method.

While you don't want to reuse any operations defined in a generic package.
People put operations into generic packages out feeling of pure joy. No bad
intentions to reuse them anyhow. Is that your point?

>> There is
>> tight relationship between operations =, /=, <, >, >=, <=, 'Prev, 'Next of
>> an ordered set. This is what makes it such a thing. Inheriting to Ordered
>> tells to the reader all this in just one source line. Moreover, it allows
>> the compiler to check if the manifested type is indeed ordered and even
>> prove some of this like x=y <=> not x/=y. 
> Certainly not. Inheriting from Ordered guarantees that all these
> operations are available, but say nothing about the semantics. If you
> want to add semantics, use type invariants and the like.

Sure I can. And I can reuse Ordered interface in other places, probably put
it into the standard library. And programmers can accustom to it as they
are to built-in scalar types.

>> Compare this with generics. They
>> just name some operations and the programmer should guess about the purpose
>> of what the actual type should be. Yes there is no dependency ... on the
>> application domain. Just an ad-hoc mess.
>> 
> It's not a mess. It's generality. The actual type should be anything
> that matches the contract.

The "contract" is a mess. It is not much better than C++ template
"contract," anything that passes compilation is OK. Contracts must be
verifiable, have predictable consequences, recognizable from the
application domain.

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


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08 14:21                     ` J-P. Rosen
@ 2014-08-08 20:23                       ` Dmitry A. Kazakov
  0 siblings, 0 replies; 73+ messages in thread
From: Dmitry A. Kazakov @ 2014-08-08 20:23 UTC (permalink / raw)


On Fri, 08 Aug 2014 16:21:56 +0200, J-P. Rosen wrote:

> Le 08/08/2014 15:52, Dmitry A. Kazakov a écrit :
> 
>> 1. Consider non-dispatching calls. Uncontrolled overloading were safer?
> What is uncontrolled overloading?

Like instances of Put for every thinkable integer type.

>> 2. Consider dispatching calls. Constraint_Error on different tags is safer?
>> 
> At least, well defined.

Is it safe?

> And does not require writing N**2 functions...

It certainly require defining these functions. Raising Constraint_Error is
such a definition.

> Or how would you implement MD?

That is a different question.

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

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08 19:34                               ` Shark8
@ 2014-08-08 20:23                                 ` Dmitry A. Kazakov
  0 siblings, 0 replies; 73+ messages in thread
From: Dmitry A. Kazakov @ 2014-08-08 20:23 UTC (permalink / raw)


On Fri, 08 Aug 2014 13:34:36 -0600, Shark8 wrote:

> On 08-Aug-14 05:20, Dmitry A. Kazakov wrote:
>> And they [subtypes] break in-operations. As an example consider:
>>
>>     X : Integer := -1;
>>
>> Now substitute Positive for Integer.
> 
> That's going the wrong way.
> You're narrowing the set when you move to the subtype, so obviously not 
> all values will be present; this is a Good Thing.

No idea what you mean. It is not substitutable. Period.

[...]
>      Subtype Social_Security_Number is String(1..9)
>      with Dynamic_Predicate =>
>        (for all C of Social_Security_Number => C in Digit);
[...]

> We *don't* want to substitute STRING for Social_Security_Number or

You substitute Social_Security_Number for String when you inherit String
operations, like S'Length.

You substitute String for Social_Security_Number when you export
Social_Security_Number operations to String. Ada subtypes allows that too.
 
>> Subsetting means nothing to subtyping and both very little to
>> substitutability. All three are different things.
> 
> Ridiculous; as shown above subtyping *is* the subsetting of the valid 
> values: Social_Security_Number in particular has only 10**9 values 
> rather than the Σ(n=0..Positive'Last) 256**n values that the STRING type 
> would have.

Which does not imply anything to either subtyping or substitutability. Here
are the definitions:

def. S is a subtype T if it inherits the interface of T. E.g. inherits an
operation of T. It is also called subclassing.

Example: Positive is a subtype of Integer because it inherits +.

def. S is substitutable for T in an operation f if you can pass an instance
of S where an instance of T is expected.

Example: Circle is substitutable for Ellipse in Area. Circle is not
substitutable for Ellipse in Resize. This is so-called Circle-Ellipse or
Square-Rectangle controversy.

The notion of subtypes based on substitutablity (behavioral subtyping) is
so-called LSP-subtyping.

>> Huh, great mathematical problems are about fighting constraints. E.g.
>> solving x**n + y**n = z**n in real numbers vs. in natural ones. No big
>> deal? Same applies to programming, it is mostly about working around
>> constraints.
> 
> ...that's the most idiotic thing I've *ever* heard you say.
> Constraints are fundamental for mathematical proofs; they are essential 
> for making robust programs. (HINT: definitions are often constraints.)

Hint: Diophantine equation

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


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08 13:52                   ` Dmitry A. Kazakov
  2014-08-08 14:21                     ` J-P. Rosen
@ 2014-08-08 22:08                     ` Randy Brukardt
  1 sibling, 0 replies; 73+ messages in thread
From: Randy Brukardt @ 2014-08-08 22:08 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:1v63jbcfxdtgi$.zc49bw7ne9gn.dlg@40tude.net...
> On Fri, 08 Aug 2014 15:34:41 +0200, J-P. Rosen wrote:
>
>> I was more thinking about the calls for MD, etc..
>
> How MD can be less safe?

That's irrelevant. It's unimplementable (at least correctly in an Ada 
context), so it cannot exist.

                               Randy.


 




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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08 13:25               ` Maciej Sobczak
  2014-08-08 13:34                 ` J-P. Rosen
@ 2014-08-08 22:18                 ` Randy Brukardt
  1 sibling, 0 replies; 73+ messages in thread
From: Randy Brukardt @ 2014-08-08 22:18 UTC (permalink / raw)


"Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message 
news:cc1e7f8d-e1f6-4e37-833c-da745e5a1a3c@googlegroups.com...
...
>In particular (1), I have pointed that that Ada's handling of dispatch 
>during
> initialization/finalization is *unsafe*. Obviously I'm not going to buy 
> the
> argument that a missing feature here is a price for added safety!

No, all you did is point out the (obvious) fact that Ada's handling of 
object initialization (or lack thereof) is unsafe. How that works for 
Initialization is just a tiny corner of the whole. It really does not make 
any sense to try to make some corner safer when the underpinnings are many 
times less safe to begin with. (In addition, this is not a solvable 
problem -- there are many types where no defined order of initialization 
would be safe. [Requiring the programmer to define such a thing simply 
provides an illusion of safety -- programmers make mistakes, and the 
consequences are much worse when safety appears to be achieved.])

There's a strong argument that Ada handles this area wrong from the 
beginning, but that will have to be fixed in other languages (we've done all 
we can for Ada).

                                                       Randy.


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08 13:06               ` Maciej Sobczak
  2014-08-08 13:22                 ` Dmitry A. Kazakov
@ 2014-08-08 22:26                 ` Randy Brukardt
  1 sibling, 0 replies; 73+ messages in thread
From: Randy Brukardt @ 2014-08-08 22:26 UTC (permalink / raw)


"Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message 
news:e1a445fa-b3b8-4b3d-a856-3e0ccbc737bf@googlegroups.com...
W dniu piatek, 8 sierpnia 2014 10:14:27 UTC+2 uzytkownik Dmitry A. Kazakov 
napisal:

>> I still do not understand the example.
>
>http://en.wikipedia.org/wiki/Covariant_return_type
>
>> Is the operation in question
>> primitive for both the factory and product hierarchy? That is MD.
>
>I don't consider it to be an example of MD, because the two types (factory 
>and product)
>do not play equal roles in the dispatch. Namely, the operation is expected 
>to dispatch on
>the factory type only.

That''s not how Ada looks at things (as I'm sure you know). The result type 
participates in resolution and can participate in dispatch. Ergo, if an 
operation is primitive on multiple tagged types, then it is by definition 
MD.

Almost all other languages do not have the result type participate in 
resolution (and thus it makes no sense for it to participate in dispatch). 
This is a fundemental difference of Ada that clearly is unchangable at this 
point (we're not going to break thousands of programs that use return type 
resolution to meet someone's idea of language purity).

                                             Randy.



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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08 13:22                 ` Dmitry A. Kazakov
@ 2014-08-08 22:32                   ` Randy Brukardt
  2014-08-09 16:11                   ` Maciej Sobczak
  1 sibling, 0 replies; 73+ messages in thread
From: Randy Brukardt @ 2014-08-08 22:32 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:2extr7bydwfw.tcda12f9xnq9.dlg@40tude.net...
...
> The only case where this may happen is parallel type hierarchies when two
> types are inherited synchronously, e.g.
>
>   type Object is tagged ...
>   type Handle is tagged ...
>   function Access (X : Handle_To_Object) return Object;
>
>   type New_Object is new Object with ...
>
> must produce
>
>   type New_Handle is new Handle with ...
>
> and
>
>   function Access (X : New_Handle) return New_Object;
>
> No OOPL I know can handle this.

I've toyed with proposing this for Ada (seriously). The containers in 
particular are tagged but cannot be usefully extended because of this 
problem. It's unclear, though, that the model would actually work.

In any case, this is the only way to do covariance of unrelated types. 
Otherwise, you're just in the realm of overloading (usually a better 
solution anyway, IMHO).

                                Randy.


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08 12:59               ` Maciej Sobczak
@ 2014-08-08 22:37                 ` Randy Brukardt
  2014-08-08 22:53                   ` Jeffrey Carter
  0 siblings, 1 reply; 73+ messages in thread
From: Randy Brukardt @ 2014-08-08 22:37 UTC (permalink / raw)


"Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message 
news:3adb10ba-feab-4385-833b-417ecf5d66cb@googlegroups.com...
...
>Proper use of OO should not require any workarounds.

But how defines "proper use"? I'd argue it's the language designers -- it's 
impossible for a real language to meet everyone's idea of "proper use". (To 
paraphrase Abe Lincoln, in language design you can please some of the people 
all of the time, and please all of the people some of the time, but you 
can't please all of the people all of the time.) I very much doubt that it 
is possible for any language to meet your idea of "proper use of OO", and 
Dmitry's, and mine, and ..., while still meeting the goals of efficiency and 
correctness that Ada has.

                                 Randy.




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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08 22:37                 ` Randy Brukardt
@ 2014-08-08 22:53                   ` Jeffrey Carter
  0 siblings, 0 replies; 73+ messages in thread
From: Jeffrey Carter @ 2014-08-08 22:53 UTC (permalink / raw)


On 08/08/2014 03:37 PM, Randy Brukardt wrote:
>
> But how defines "proper use"? I'd argue it's the language designers -- it's
> impossible for a real language to meet everyone's idea of "proper use". (To
> paraphrase Abe Lincoln, in language design you can please some of the people
> all of the time, and please all of the people some of the time, but you
> can't please all of the people all of the time.) I very much doubt that it
> is possible for any language to meet your idea of "proper use of OO", and
> Dmitry's, and mine, and ..., while still meeting the goals of efficiency and
> correctness that Ada has.

Especially since proper use of type extension is none at all :)

-- 
Jeff Carter
"We call your door-opening request a silly thing."
Monty Python & the Holy Grail
17


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-08 13:22                 ` Dmitry A. Kazakov
  2014-08-08 22:32                   ` Randy Brukardt
@ 2014-08-09 16:11                   ` Maciej Sobczak
  2014-08-09 16:48                     ` Dmitry A. Kazakov
  1 sibling, 1 reply; 73+ messages in thread
From: Maciej Sobczak @ 2014-08-09 16:11 UTC (permalink / raw)


On Friday, August 8, 2014 3:22:56 PM UTC+2, Dmitry A. Kazakov wrote:

> >> I still do not understand the example.
> 
> > http://en.wikipedia.org/wiki/Covariant_return_type
> 
> type A is tagged null record;
> function getFoo return A;

Wrong. getFoo should have a factory as a parameter (in the Wikipedia example this is hidden as "this" parameter). More complete example would be:

   package Products is
      type A is tagged null record;
      type B is new A with null record;
   end Products;
   
   package Factories is
      type A_Factory is tagged null record;
      function Make (AF : in A_Factory) return Products.A;

      type B_Factory is tagged null record;
      overriding function Make (BF : in B_Factory) return Products.B;
   end Factories;

and GNAT says:

   subprogram "Make" is not overriding
   not type conformant with declaration at line XXX
   return type does not match

As Randy pointed out, this cannot work in Ada. It's not even a matter of "fixing" something.

> No dispatch, no covariance.

Feel free to make up your own definitions.

> If you are in the hierarchy of the factory
> type, there cannot be any covariance in an unrelated hierarchy.

This is *exactly* the definition of covariance, at least the one I know:

http://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29#Covariant_method_return_type

> The only case where this may happen is parallel type hierarchies when two
> types are inherited synchronously, e.g.
> 
>    type Object is tagged ...
>    type Handle is tagged ...
> 
>    function Access (X : Handle_To_Object) return Object;
> 
>    type New_Object is new Object with ...
> 
> must produce
> 
>    type New_Handle is new Handle with ...
> 
> and
> 
>    function Access (X : New_Handle) return New_Object;

Yes.

> No OOPL I know can handle this.

Have you heard about those niche and unpopular languages like C++ and Java? ;-)

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


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-09 16:11                   ` Maciej Sobczak
@ 2014-08-09 16:48                     ` Dmitry A. Kazakov
  2014-08-10 20:55                       ` Maciej Sobczak
  0 siblings, 1 reply; 73+ messages in thread
From: Dmitry A. Kazakov @ 2014-08-09 16:48 UTC (permalink / raw)


On Sat, 9 Aug 2014 09:11:43 -0700 (PDT), Maciej Sobczak wrote:

> On Friday, August 8, 2014 3:22:56 PM UTC+2, Dmitry A. Kazakov wrote:
> 
>>>> I still do not understand the example.
>> 
>>> http://en.wikipedia.org/wiki/Covariant_return_type
>> 
>> type A is tagged null record;
>> function getFoo return A;
> 
> Wrong. getFoo should have a factory as a parameter (in the Wikipedia
> example this is hidden as "this" parameter). More complete example would
> be:
> 
>    package Products is
>       type A is tagged null record;
>       type B is new A with null record;
>    end Products;
>    
>    package Factories is
>       type A_Factory is tagged null record;
>       function Make (AF : in A_Factory) return Products.A;
> 
>       type B_Factory is tagged null record;
>       overriding function Make (BF : in B_Factory) return Products.B;
>    end Factories;
> 
> and GNAT says:
>
>    subprogram "Make" is not overriding
>    not type conformant with declaration at line XXX
>    return type does not match

The example does not make any sense. Since it would be impossible to
dispatch on Make without knowing the type of the outcome.
 
Factory pattern in Ada is this:

   type Factory is abstract tagged null record;
   function Make (F : not null access Factory) return A'Class;

Then you do:

   type A_Factory is new Factory with ...
   override function Make (F : not null access A_Factory) return A'Class;

   type B_Factory is new Factory with ...
   override function Make (F : not null access B_Factory) return A'Class;

And in case you do know the result type no factory object is ever needed,
because you just do:

   X : A;

> As Randy pointed out, this cannot work in Ada. It's not even a matter of "fixing" something.

It cannot work in any language, even if full MD were supported, which would
make your example possible. The pattern is just useless.

>> If you are in the hierarchy of the factory
>> type, there cannot be any covariance in an unrelated hierarchy.
> 
> This is *exactly* the definition of covariance, at least the one I know:

The notion of co- and contra-variance was given by Luca Cardelli. It is
related strictly to inheritance <=> a hierarchy. Outside a hierarchy it is
just meaningless.

>> No OOPL I know can handle this.
> 
> Have you heard about those niche and unpopular languages like C++ and Java? ;-)

Yes. They cannot handle this either.

Usual technique in C++ and Ada is to use template or generic to produce the
handle type. It is quite nasty and it loses the second hierarchy (of
handles). 

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

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-09 16:48                     ` Dmitry A. Kazakov
@ 2014-08-10 20:55                       ` Maciej Sobczak
  2014-08-11  7:41                         ` Dmitry A. Kazakov
  0 siblings, 1 reply; 73+ messages in thread
From: Maciej Sobczak @ 2014-08-10 20:55 UTC (permalink / raw)


W dniu sobota, 9 sierpnia 2014 18:48:33 UTC+2 użytkownik Dmitry A. Kazakov napisał:

> The example does not make any sense. Since it would be impossible to
> dispatch on Make without knowing the type of the outcome.

The example does not make any sense, because it is not supported by Ada. It does make perfect sense in those languages that support it.

> Factory pattern in Ada is this:
> 
>    type Factory is abstract tagged null record;
> 
>    function Make (F : not null access Factory) return A'Class;
> 
> Then you do:
> 
>    type A_Factory is new Factory with ...
> 
>    override function Make (F : not null access A_Factory) return A'Class;
> 
>    type B_Factory is new Factory with ...
> 
>    override function Make (F : not null access B_Factory) return A'Class;
> 
> And in case you do know the result type no factory object is ever needed,
> because you just do:
> 
>    X : A;

Wrong. Or rather half-way right. I also want to do this:

   Y : B := Make (B_F);

In other words, if I know that I have a Cat_Shelter, then I want to get a real Cat from it, not some unspecified Animal (nor Animal'Class). So I want this to be possible:

   X : A := Make (A_F);  -- base obj from base factory
   Y : B := Make (B_F);  -- derived obj from derived fry
   Z_1 : A'Class := Make (A_F);  -- class-wide from base fry
   Z_2 : A'Class := Make (B_F);  -- class-wide from derived fry

All of them have real-life interpretations with any of the example use-cases that I have listed below. I can do all of them in C++.

> It cannot work in any language, even if full MD were supported, which would
> make your example possible. The pattern is just useless.

Useless?

- A Singer can sing a Song, but a Blues_Singer can sing a Blues_Song.
- I can get an Animal from an Animal_Shelter, but I can get a Cat from the Cat_Shelter (this is the Wikipedia example).
- A Coffee_Machine can make a Coffee, but a Special_Coffee_Machine can make a Special_Coffee.
- A Programmer can write a Program, but an Ada_Programmer can write an Ada_Program.
- (etc. billion of other such examples)

As I have already stated, every creational design patter can benefit from covariance on return type. I would not call this "useless".

> > This is *exactly* the definition of covariance, at least the one I know:
> 
> The notion of co- and contra-variance was given by Luca Cardelli. It is
> related strictly to inheritance <=> a hierarchy. Outside a hierarchy it is
> just meaningless.

You must have failed to read the Wikipedia articles that I have pointed.

> >> No OOPL I know can handle this.
> 
> > Have you heard about those niche and unpopular languages like C++ and Java? ;-)
> 
> Yes. They cannot handle this either.

You must have failed to read the Wikipedia articles that I have pointed.

> Usual technique in C++ and Ada is to use template or generic to produce the
> handle type.

Unrelated. Please focus on the examples that I have provided.

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


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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-10 20:55                       ` Maciej Sobczak
@ 2014-08-11  7:41                         ` Dmitry A. Kazakov
  2014-08-11  7:58                           ` Maciej Sobczak
  0 siblings, 1 reply; 73+ messages in thread
From: Dmitry A. Kazakov @ 2014-08-11  7:41 UTC (permalink / raw)


On Sun, 10 Aug 2014 13:55:00 -0700 (PDT), Maciej Sobczak wrote:

> W dniu sobota, 9 sierpnia 2014 18:48:33 UTC+2 użytkownik Dmitry A. Kazakov napisał:
> 
>> The example does not make any sense. Since it would be impossible to
>> dispatch on Make without knowing the type of the outcome.
> 
> The example does not make any sense, because it is not supported by Ada.
> It does make perfect sense in those languages that support it.

Nope, it would not work in any language, unless you redefine the word
dispatching as you tried with covariance. There is no dispatching when
types are known.

>> Factory pattern in Ada is this:
>> 
>>    type Factory is abstract tagged null record;
>> 
>>    function Make (F : not null access Factory) return A'Class;
>> 
>> Then you do:
>> 
>>    type A_Factory is new Factory with ...
>> 
>>    override function Make (F : not null access A_Factory) return A'Class;
>> 
>>    type B_Factory is new Factory with ...
>> 
>>    override function Make (F : not null access B_Factory) return A'Class;
>> 
>> And in case you do know the result type no factory object is ever needed,
>> because you just do:
>> 
>>    X : A;
> 
> Wrong. Or rather half-way right. I also want to do this:
> 
>    Y : B := Make (B_F);

Where is a problem? Do this (in another package):

   not overriding
      function Make (F : not null access B_Factory) return B;

Observe: not overriding.

Which is not needed either, because:

   Y : B; -- That is

>> It cannot work in any language, even if full MD were supported, which would
>> make your example possible. The pattern is just useless.
> 
> Useless?

Yes, useless. If you know all types involved you call a specific subprogram
or simply declare the object. Work done.

Factories are used *only* when types are unknown in advance. Or, in the
case of Ada, due to the language design bug that does not allow to pass
parameters to Initialize.

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

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-11  7:41                         ` Dmitry A. Kazakov
@ 2014-08-11  7:58                           ` Maciej Sobczak
  2014-08-11  8:23                             ` Dmitry A. Kazakov
  2014-08-11 11:35                             ` G.B.
  0 siblings, 2 replies; 73+ messages in thread
From: Maciej Sobczak @ 2014-08-11  7:58 UTC (permalink / raw)


W dniu poniedziałek, 11 sierpnia 2014 09:41:09 UTC+2 użytkownik Dmitry A. Kazakov napisał:

> Nope, it would not work in any language, unless you redefine the word
> dispatching as you tried with covariance. There is no dispatching when
> types are known.

OK, so you still don't get it. The (potential) dispatch is on the factory type:

procedure Use_Whatever_Factory (F : in Factory'Class) is

   P : Product'Class := F.Make_Product;

begin
   -- ...
end;

Now you have dispatch on the factory type.
Of course, I still want all the specific calls work, too, that's why the return type cannot be Product'Class, otherwise I will be forced to cast types.
In other words, this has to work as well:

procedure Use_Specific_Factory (F : in Specific_Factory) is

   SP : Specific_Product := F.Make_Product;

begin
   -- ...
end;

And there is no way to make *both* work in Ada. You can get one or the other but not both.

> Where is a problem? Do this (in another package):
> 
>    not overriding
>       function Make (F : not null access B_Factory) return B;
> 
> Observe: not overriding.

And this is where your idea breaks down. The Make operation *must* be overriding, otherwise I will not be able to use Factory'Class.

> > Useless?
> 
> Yes, useless. If you know all types involved you call a specific subprogram
> or simply declare the object. Work done.

I might not know the specific factory type. That's the whole point of all creational design patterns, which I have mentioned several times already.

> Factories are used *only* when types are unknown in advance.

Not only. I might want to use specific factory from the hierarchy of factories, too. The OOP does not force me to use class-wide types only.

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

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-11  7:58                           ` Maciej Sobczak
@ 2014-08-11  8:23                             ` Dmitry A. Kazakov
  2014-08-12  7:50                               ` Maciej Sobczak
  2014-08-11 11:35                             ` G.B.
  1 sibling, 1 reply; 73+ messages in thread
From: Dmitry A. Kazakov @ 2014-08-11  8:23 UTC (permalink / raw)


On Mon, 11 Aug 2014 00:58:12 -0700 (PDT), Maciej Sobczak wrote:

> W dniu poniedziałek, 11 sierpnia 2014 09:41:09 UTC+2 użytkownik Dmitry A. Kazakov napisał:
> 
> In other words, this has to work as well:
> 
> procedure Use_Specific_Factory (F : in Specific_Factory) is
> 
>    SP : Specific_Product := F.Make_Product;

And it worked in the example I provided.

> And there is no way to make *both* work in Ada. You can get one or the
> other but not both.

Of course there is a way. If you have two operations with different
profiles you can overload them.
 
>> Where is a problem? Do this (in another package):
>> 
>>    not overriding
>>       function Make (F : not null access B_Factory) return B;
>> 
>> Observe: not overriding.
> 
> And this is where your idea breaks down. The Make operation *must* be
> overriding, otherwise I will not be able to use Factory'Class.

You don't need Factory'Class since the return type is fixed to B.

If it were B'Class you could have a hierarchy of
B-and-its-descendant-factories. But that won't be a hierarchy of
A-factories or A-and-its-descendant-factories.

You need something to vary to have a hierarchy. Which is why it is called
covariance or contravariance. Varying could be Factory or Product or both
(MD). No hierarchy, no variance.

>>> Useless?
>> 
>> Yes, useless. If you know all types involved you call a specific subprogram
>> or simply declare the object. Work done.
> 
> I might not know the specific factory type.

No, you know it, because the only factory that returns B is the B-factory
and nowhere in your examples you have one with a class-wide factory and a
specific product type. If you wrote one, you would see what is wrong with
your idea:

procedure Foo (F : A_Factory'Class) is
   X : B := Make (F);

This does not work because it could be *any* factory, e.g. an A-factory.
You *must* specify the factory type:

procedure Foo (F : A_Factory'Class) is
   X : B := B (Make (B_Factory (F)));

MD would do this automatically.

But, again, the whole exercise is useless. If you know it must be B, there
is no need in any factories:

   X : B;

>> Factories are used *only* when types are unknown in advance.
> 
> Not only. I might want to use specific factory from the hierarchy of
> factories, too.

The type of the product is unknown when a factory is used, that is all and
single idea of having a factory.

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

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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-11  7:58                           ` Maciej Sobczak
  2014-08-11  8:23                             ` Dmitry A. Kazakov
@ 2014-08-11 11:35                             ` G.B.
  1 sibling, 0 replies; 73+ messages in thread
From: G.B. @ 2014-08-11 11:35 UTC (permalink / raw)


On 11.08.14 09:58, Maciej Sobczak wrote:
> procedure Use_Specific_Factory (F : in Specific_Factory) is
>
>     SP : Specific_Product := F.Make_Product;
>
> begin
>     -- ...
> end;
>
> And there is no way to make*both*  work in Ada. You can get one or the other but not both.


Is this a correct paraphrase?

"To make this practically work in Ada, one has to write

procedure Use_Specific_Factory (F : in Specific_Factory) is

     SP : Specific_Product := Specific_Product (F.Make_Product);

begin
     -- ...
end;

"and watch for run-time dispatching."

Where

   function Make_Product (Shop : access Factory)
     return Product'Class is abstract;

can be overridden as a prim op of Factory.
The variance becomes a property of its invocation context.




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

* Re: A bad counterintuitive behaviour of Ada about OO
  2014-08-11  8:23                             ` Dmitry A. Kazakov
@ 2014-08-12  7:50                               ` Maciej Sobczak
  0 siblings, 0 replies; 73+ messages in thread
From: Maciej Sobczak @ 2014-08-12  7:50 UTC (permalink / raw)


W dniu poniedziałek, 11 sierpnia 2014 10:23:09 UTC+2 użytkownik Dmitry A. Kazakov napisał:

> > And there is no way to make *both* work in Ada. You can get one or the
> > other but not both.
> 
> Of course there is a way. If you have two operations with different
> profiles you can overload them.

Hm... And then one overloaded version would delegate to another one.
I have to admit that this sounds like a plausible work-around. It requires more scaffolding than in C++ or Java (there are additional functions that exist only for technical reasons and that do not represent any design-level concepts), but it allows seamless integration at the call side, which was the actual goal.

I have learned something from this discussion. For future reference I paste the complete example program that shows the concepts in action:

with Ada.Text_IO;

procedure Test is
   
   package Products is
      
      type Any_Product is interface;
      
      type A_Product is new Any_Product with null record;
      type B_Product is new Any_Product with null record;
      
   end Products;
   
   package Factories is
      
      type Any_Factory is interface;
      function Make (F : in Any_Factory)
                    return Products.Any_Product'Class is abstract;
      
      type A_Factory is new Any_Factory with null record;
      overriding function Make (F : in A_Factory)
                    return Products.Any_Product'Class;
      function Make (F : in A_Factory)
                    return Products.A_Product;
      
      type B_Factory is new Any_Factory with null record;
      overriding function Make (F : in B_Factory)
                    return Products.Any_Product'Class;
      function Make (F : in B_Factory)
                    return Products.B_Product;
      
   end Factories;
   
   package body Factories is
      
      overriding
      function Make (F : in A_Factory)
                    return Products.Any_Product'Class is
      begin
         -- delegates to actual maker:
         return Products.A_Product'(F.Make);
      end Make;
      
      function Make (F : in A_Factory)
                    return Products.A_Product is
         Result : Products.A_Product;
      begin
         Ada.Text_IO.Put_Line ("Making A_Product");
         return Result;
      end Make;
      
      overriding
      function Make (F : in B_Factory)
                    return Products.Any_Product'Class is
      begin
         -- delegates to actual maker:
         return Products.B_Product'(F.Make);
      end Make;
      
      function Make (F : in B_Factory)
                    return Products.B_Product is
         Result : Products.B_Product;
      begin
         Ada.Text_IO.Put_Line ("Making B_Product");
         return Result;
      end Make;
      
   end Factories;
   
   procedure Use_Any_Factory (F : in Factories.Any_Factory'Class) is
      P : Products.Any_Product'Class := F.Make;
   begin
      null;
   end Use_Any_Factory;
   
   A_F : Factories.A_Factory;
   B_F : Factories.B_Factory;
   
begin
   Ada.Text_IO.Put_Line ("Using A_Factory (via class-wide)");
   Use_Any_Factory (A_F);
   
   Ada.Text_IO.Put_Line ("Using B_Factory (via class-wide)");
   Use_Any_Factory (B_F);
   
   Ada.Text_IO.Put_Line ("Using A_Factory (specific)");
   declare
      A_P : Products.A_Product := A_F.Make;
   begin
      null;
   end;
   
   Ada.Text_IO.Put_Line ("Using B_Factory (specific)");
   declare
      B_P : Products.B_Product := B_F.Make;
   begin
      null;
   end;
end Test;

All calls do what I wanted.

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

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

end of thread, other threads:[~2014-08-12  7:50 UTC | newest]

Thread overview: 73+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-05 20:09 A bad counterintuitive behaviour of Ada about OO Victor Porton
2014-08-05 20:58 ` Simon Wright
2014-08-05 21:06   ` Victor Porton
2014-08-05 21:51     ` Niklas Holsti
2014-08-05 22:13       ` Victor Porton
2014-08-05 22:35   ` Victor Porton
2014-08-05 23:25     ` Adam Beneschan
2014-08-05 20:59 ` Dmitry A. Kazakov
2014-08-05 21:07   ` Victor Porton
2014-08-05 22:39     ` Shark8
2014-08-05 21:11   ` Victor Porton
2014-08-06  7:26     ` Dmitry A. Kazakov
2014-08-07  7:41       ` Maciej Sobczak
2014-08-07  8:50         ` Dmitry A. Kazakov
2014-08-08  7:54           ` Maciej Sobczak
2014-08-08  8:14             ` Dmitry A. Kazakov
2014-08-08 13:06               ` Maciej Sobczak
2014-08-08 13:22                 ` Dmitry A. Kazakov
2014-08-08 22:32                   ` Randy Brukardt
2014-08-09 16:11                   ` Maciej Sobczak
2014-08-09 16:48                     ` Dmitry A. Kazakov
2014-08-10 20:55                       ` Maciej Sobczak
2014-08-11  7:41                         ` Dmitry A. Kazakov
2014-08-11  7:58                           ` Maciej Sobczak
2014-08-11  8:23                             ` Dmitry A. Kazakov
2014-08-12  7:50                               ` Maciej Sobczak
2014-08-11 11:35                             ` G.B.
2014-08-08 22:26                 ` Randy Brukardt
2014-08-08  8:34             ` Shark8
2014-08-08 12:59               ` Maciej Sobczak
2014-08-08 22:37                 ` Randy Brukardt
2014-08-08 22:53                   ` Jeffrey Carter
2014-08-07  8:58         ` J-P. Rosen
2014-08-07  9:40           ` Dmitry A. Kazakov
2014-08-07 11:17             ` J-P. Rosen
2014-08-07 12:28               ` Dmitry A. Kazakov
2014-08-07 13:34                 ` J-P. Rosen
2014-08-07 16:10                   ` Dmitry A. Kazakov
2014-08-07 18:14                     ` Robert A Duff
2014-08-07 19:41                       ` Dmitry A. Kazakov
2014-08-07 20:53                         ` Robert A Duff
2014-08-08  7:43                           ` Dmitry A. Kazakov
2014-08-08  8:18                             ` Shark8
2014-08-08  7:45                     ` J-P. Rosen
2014-08-08  8:04                       ` Dmitry A. Kazakov
2014-08-08  8:55                         ` J-P. Rosen
2014-08-08  9:13                           ` Dmitry A. Kazakov
2014-08-08 10:01                             ` J-P. Rosen
2014-08-08 10:53                               ` Dmitry A. Kazakov
2014-08-08 10:56                                 ` Victor Porton
2014-08-08 12:00                                 ` J-P. Rosen
2014-08-08 13:11                                   ` Dmitry A. Kazakov
2014-08-08 13:53                                     ` J-P. Rosen
2014-08-08 20:23                                       ` Dmitry A. Kazakov
2014-08-07 20:29                   ` Shark8
2014-08-08  7:49                     ` J-P. Rosen
2014-08-08  8:12                       ` Shark8
2014-08-08  8:26                         ` Dmitry A. Kazakov
2014-08-08 11:10                           ` Shark8
2014-08-08 11:20                             ` Dmitry A. Kazakov
2014-08-08 19:34                               ` Shark8
2014-08-08 20:23                                 ` Dmitry A. Kazakov
2014-08-07 15:03           ` Jeffrey Carter
2014-08-08  7:48           ` Maciej Sobczak
2014-08-08  8:51             ` J-P. Rosen
2014-08-08 13:25               ` Maciej Sobczak
2014-08-08 13:34                 ` J-P. Rosen
2014-08-08 13:52                   ` Dmitry A. Kazakov
2014-08-08 14:21                     ` J-P. Rosen
2014-08-08 20:23                       ` Dmitry A. Kazakov
2014-08-08 22:08                     ` Randy Brukardt
2014-08-08 22:18                 ` Randy Brukardt
2014-08-06  4:50 ` Per Sandberg

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