comp.lang.ada
 help / color / mirror / Atom feed
* abstract types and subprograms
@ 2014-05-20 10:22 Victor Porton
  2014-05-20 10:51 ` mockturtle
  2014-05-20 11:55 ` Dmitry A. Kazakov
  0 siblings, 2 replies; 10+ messages in thread
From: Victor Porton @ 2014-05-20 10:22 UTC (permalink / raw)


I am now an Ada novice. I started to write librdf bindings for Ada.

The following produces the error:

gnatmake -ws -c -u -P/home/porton/Projects/librdf-ada/librdf.gpr rdf-
base.adb
gcc-4.6 -c -g -O2 -gnat2012 -I- -gnatA /home/porton/Projects/librdf-ada/rdf-
base.adb
rdf-base.ads:20:04: function that returns abstract type must be abstract
gnatmake: "/home/porton/Projects/librdf-ada/rdf-base.adb" compilation error


By the philosophy of programming From_Handle should be non-abstract but 
return an abstract object, and From_Handle should be automatically 
overridden for descendants non-abstract objects.

What is wrong?


-- rdf-base.ads
with Ada.Finalization;
with Interfaces.C.Pointers;

package RDF.Base is

   -- Internal
   type Dummy_Record is null record;

   -- Internal
   type Dummy_Record_Access is access Dummy_Record;
   
   type Base_Object is abstract new Ada.Finalization.Limited_Controlled with 
private;
   
   function Get_Handle(Object: Base_Object) return Dummy_Record_Access with 
Inline;
   
   function From_Handle(Handle: Dummy_Record_Access) return Base_Object with 
Inline;
   
private
   
   type Base_Object is new Ada.Finalization.Limited_Controlled with
      record
         Handle: Dummy_Record_Access;
      end record;     
   
end RDF.Base;

-- rdf-base.adb
package body RDF.Base is
   
   function Get_Handle(Object: Base_Object) return Dummy_Record_Access is 
(Object.Handle);
   
   function From_Handle(Handle: Dummy_Record_Access) return Base_Object is
      (Ada.Finalization.Limited_Controlled with Handle=>Handle);
   
end RDF.Base;

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


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

* Re: abstract types and subprograms
  2014-05-20 10:22 abstract types and subprograms Victor Porton
@ 2014-05-20 10:51 ` mockturtle
  2014-05-20 11:45   ` Victor Porton
  2014-05-20 11:55 ` Dmitry A. Kazakov
  1 sibling, 1 reply; 10+ messages in thread
From: mockturtle @ 2014-05-20 10:51 UTC (permalink / raw)


On Tuesday, May 20, 2014 12:22:30 PM UTC+2, Victor Porton wrote:

> 
> 
> rdf-base.ads:20:04: function that returns abstract type must be abstract
> gnatmake: "/home/porton/Projects/librdf-ada/rdf-base.adb" compilation error
> 
> By the philosophy of programming From_Handle should be non-abstract but 
> return an abstract object, and From_Handle should be automatically 
> overridden for descendants non-abstract objects.
> 

In my opinion, there is a contradiction: an abstract type is, by definition, a type "without objects," in the sense that you cannot have a value whose type is an abstract type.   Therefore, you cannot have a non-abstract function that returns an abstract type, since by calling it you would create a value of an abstract type.

Functions that return abstract types make sense.  For example, they can be used to "force" who derives from you abstract type to provide a constructor for the derived type.  I use them, for example, to implement "plugins" in order to have a standard constructor for the derived type.

I hope this can help you a bit.

Riccardo


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

* Re: abstract types and subprograms
  2014-05-20 10:51 ` mockturtle
@ 2014-05-20 11:45   ` Victor Porton
  2014-05-20 16:27     ` Robert A Duff
  0 siblings, 1 reply; 10+ messages in thread
From: Victor Porton @ 2014-05-20 11:45 UTC (permalink / raw)


mockturtle wrote:
> On Tuesday, May 20, 2014 12:22:30 PM UTC+2, Victor Porton wrote:
> 
>> 
>> 
>> rdf-base.ads:20:04: function that returns abstract type must be abstract
>> gnatmake: "/home/porton/Projects/librdf-ada/rdf-base.adb" compilation
>> error
>> 
>> By the philosophy of programming From_Handle should be non-abstract but
>> return an abstract object, and From_Handle should be automatically
>> overridden for descendants non-abstract objects.
>> 
> 
> In my opinion, there is a contradiction: an abstract type is, by
> definition, a type "without objects," in the sense that you cannot have a
> value whose type is an abstract type.   Therefore, you cannot have a
> non-abstract function that returns an abstract type, since by calling it
> you would create a value of an abstract type.
> 
> Functions that return abstract types make sense.  For example, they can be
> used to "force" who derives from you abstract type to provide a
> constructor for the derived type.  I use them, for example, to implement
> "plugins" in order to have a standard constructor for the derived type.
> 
> I hope this can help you a bit.

But does it make sense (philosophically, not accordingly the current 
specification) to use a function which returns an abstract type for a record 
extension aggregate?

In my humble opinion, this use may be useful in a future Ada standard.

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


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

* Re: abstract types and subprograms
  2014-05-20 10:22 abstract types and subprograms Victor Porton
  2014-05-20 10:51 ` mockturtle
@ 2014-05-20 11:55 ` Dmitry A. Kazakov
  2014-05-20 12:28   ` Victor Porton
  1 sibling, 1 reply; 10+ messages in thread
From: Dmitry A. Kazakov @ 2014-05-20 11:55 UTC (permalink / raw)


On Tue, 20 May 2014 13:22:30 +0300, Victor Porton wrote:

> By the philosophy of programming From_Handle should be non-abstract but 
> return an abstract object, and From_Handle should be automatically 
> overridden for descendants non-abstract objects.
> 
> What is wrong?

You cannot automatically override without knowing the implementation, which
you don't in advance. If you know it, then it is same for all class. See
below.

> -- rdf-base.ads
> with Ada.Finalization;
> with Interfaces.C.Pointers;
> 
> package RDF.Base is
> 
>    -- Internal
>    type Dummy_Record is null record;
> 
>    -- Internal
>    type Dummy_Record_Access is access Dummy_Record;
>    
>    type Base_Object is abstract new Ada.Finalization.Limited_Controlled with 
> private;
>    
>    function Get_Handle(Object: Base_Object) return Dummy_Record_Access with 
> Inline;
>    
>    function From_Handle(Handle: Dummy_Record_Access) return Base_Object with 
> Inline;

function From_Handle(Handle: Dummy_Record_Access) return Base_Object'Class;

Logically, a handle can point on an object of any type derived from
Base_Object, so it is a class.

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


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

* Re: abstract types and subprograms
  2014-05-20 11:55 ` Dmitry A. Kazakov
@ 2014-05-20 12:28   ` Victor Porton
  2014-05-20 14:11     ` Dmitry A. Kazakov
  0 siblings, 1 reply; 10+ messages in thread
From: Victor Porton @ 2014-05-20 12:28 UTC (permalink / raw)


Dmitry A. Kazakov wrote:

> On Tue, 20 May 2014 13:22:30 +0300, Victor Porton wrote:
> 
>> By the philosophy of programming From_Handle should be non-abstract but
>> return an abstract object, and From_Handle should be automatically
>> overridden for descendants non-abstract objects.
>> 
>> What is wrong?
> 
> You cannot automatically override without knowing the implementation,
> which you don't in advance. If you know it, then it is same for all class.
> See below.
> 
>> -- rdf-base.ads
>> with Ada.Finalization;
>> with Interfaces.C.Pointers;
>> 
>> package RDF.Base is
>> 
>>    -- Internal
>>    type Dummy_Record is null record;
>> 
>>    -- Internal
>>    type Dummy_Record_Access is access Dummy_Record;
>>    
>>    type Base_Object is abstract new Ada.Finalization.Limited_Controlled
>>    with
>> private;
>>    
>>    function Get_Handle(Object: Base_Object) return Dummy_Record_Access
>>    with
>> Inline;
>>    
>>    function From_Handle(Handle: Dummy_Record_Access) return Base_Object
>>    with
>> Inline;
> 
> function From_Handle(Handle: Dummy_Record_Access) return
> Base_Object'Class;
> 
> Logically, a handle can point on an object of any type derived from
> Base_Object, so it is a class.

But can this:

   function From_Handle(Handle: Dummy_Record_Access) return Base_Object is
      (Ada.Finalization.Limited_Controlled with Handle=>Handle);

be implemented if the return type changes to Base_Object'Class?

It seems for me that I should define it as above and override From_Handle 
for each derived tagged type.

It seems that returning Base_Object'Class wouldn't magically make it work 
(without explicit override).

Or can it be done implementing Frorm_Handle only once (for Base_Object) with 
automatic changing its signature for derived tagged types?

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

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

* Re: abstract types and subprograms
  2014-05-20 12:28   ` Victor Porton
@ 2014-05-20 14:11     ` Dmitry A. Kazakov
  0 siblings, 0 replies; 10+ messages in thread
From: Dmitry A. Kazakov @ 2014-05-20 14:11 UTC (permalink / raw)


On Tue, 20 May 2014 15:28:29 +0300, Victor Porton wrote:

> Dmitry A. Kazakov wrote:
> 
>> function From_Handle(Handle: Dummy_Record_Access) return
>> Base_Object'Class;
>> 
>> Logically, a handle can point on an object of any type derived from
>> Base_Object, so it is a class.
> 
> But can this:
> 
>    function From_Handle(Handle: Dummy_Record_Access) return Base_Object is
>       (Ada.Finalization.Limited_Controlled with Handle=>Handle);
> 
> be implemented if the return type changes to Base_Object'Class?

It does not make sense to me. Probably because it is not clear what you are
going to achieve, smart pointer, an opaque handle to a C object, no idea.

> It seems that returning Base_Object'Class wouldn't magically make it work 
> (without explicit override).

Either you override or you don't. As I said, the criterion is whether the
implementation is same for all class or different for some instances.
 
> Or can it be done implementing Frorm_Handle only once (for Base_Object) with 
> automatic changing its signature for derived tagged types?

Signature changes if the operation is primitive. It does not change if it
is not primitive, e.g. class-wide.

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


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

* Re: abstract types and subprograms
  2014-05-20 11:45   ` Victor Porton
@ 2014-05-20 16:27     ` Robert A Duff
  2014-05-20 19:52       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 10+ messages in thread
From: Robert A Duff @ 2014-05-20 16:27 UTC (permalink / raw)


Victor Porton <porton@narod.ru> writes:

> But does it make sense (philosophically, not accordingly the current 
> specification) to use a function which returns an abstract type for a record 
> extension aggregate?

Yes, it makes sense to create objects of an abstract type,
and the most likely place to use such a thing is as the 
ancestor part in an extension aggregate.  So this rule could
be relaxed.

What should be forbidden is to convert such an object to a class-wide
type (explicitly or implicitly), because that can lead to dangling
dispatch (i.e. calling an abstract subprogram, which of course
has no body).

Other languages that don't clearly distinguish specific and
class-wide types have to forbid creating objects of abstract type,
and I guess Ada just copied that.

> In my humble opinion, this use may be useful in a future Ada standard.

I mentioned this idea to Tucker once, and as I recall he didn't much
like it, but I'm not sure why.

- Bob


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

* Re: abstract types and subprograms
  2014-05-20 16:27     ` Robert A Duff
@ 2014-05-20 19:52       ` Dmitry A. Kazakov
  2014-05-24 18:49         ` Robert A Duff
  0 siblings, 1 reply; 10+ messages in thread
From: Dmitry A. Kazakov @ 2014-05-20 19:52 UTC (permalink / raw)


On Tue, 20 May 2014 12:27:49 -0400, Robert A Duff wrote:

> Victor Porton <porton@narod.ru> writes:
> 
>> But does it make sense (philosophically, not accordingly the current 
>> specification) to use a function which returns an abstract type for a record 
>> extension aggregate?
> 
> Yes, it makes sense to create objects of an abstract type,
> and the most likely place to use such a thing is as the 
> ancestor part in an extension aggregate.

I disagree. There is no need for instances of abstract objects, as there is
no need of extension aggregates. There should be proper constructors
instead.

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

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

* Re: abstract types and subprograms
  2014-05-20 19:52       ` Dmitry A. Kazakov
@ 2014-05-24 18:49         ` Robert A Duff
  2014-05-24 19:41           ` Dmitry A. Kazakov
  0 siblings, 1 reply; 10+ messages in thread
From: Robert A Duff @ 2014-05-24 18:49 UTC (permalink / raw)


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

> I disagree. There is no need for instances of abstract objects, as there is
> no need of extension aggregates. There should be proper constructors
> instead.

You've said that many times, but I've never seen a detailed description
of what you mean.  (Sorry if I missed it -- I don't read newsgroups
regularly.)  Can you please show us your language design for "proper
constructors"?

It seems like something like extension aggregates are needed -- you
need a way to create an object of a type, given the value of
an ancestor, and the values of the extension components.

- Bob


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

* Re: abstract types and subprograms
  2014-05-24 18:49         ` Robert A Duff
@ 2014-05-24 19:41           ` Dmitry A. Kazakov
  0 siblings, 0 replies; 10+ messages in thread
From: Dmitry A. Kazakov @ 2014-05-24 19:41 UTC (permalink / raw)


On Sat, 24 May 2014 14:49:55 -0400, Robert A Duff wrote:

> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes:
> 
>> I disagree. There is no need for instances of abstract objects, as there is
>> no need of extension aggregates. There should be proper constructors
>> instead.
> 
> You've said that many times, but I've never seen a detailed description
> of what you mean.  (Sorry if I missed it -- I don't read newsgroups
> regularly.)  Can you please show us your language design for "proper
> constructors"?

I did several times. But it can be summarized in a single sentence.

For *any* type there should be a way to define user procedure(s) [with some
parameters or without] called when the object has been created before, it
becomes available to any clients.

If an abstract parent type requires initialization the developer of the
type defines a corresponding procedure. The derived type is responsible to
provide parameters for the procedure, if any, upon its initialization.

> It seems like something like extension aggregates are needed -- you
> need a way to create an object of a type, given the value of
> an ancestor, and the values of the extension components.

No, they fail the purpose of objects creation even with that awful hack of
limited returns. It simply does not work as was demonstrated multiple
times. And that little what is supposed to work, still does not. The
semantics seems so complicated that even the latest GNAT 4.9 has bugs
there, many years since introduction of the kludge.

Aggregates should never have been misused for the purpose.

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

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

end of thread, other threads:[~2014-05-24 19:41 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-05-20 10:22 abstract types and subprograms Victor Porton
2014-05-20 10:51 ` mockturtle
2014-05-20 11:45   ` Victor Porton
2014-05-20 16:27     ` Robert A Duff
2014-05-20 19:52       ` Dmitry A. Kazakov
2014-05-24 18:49         ` Robert A Duff
2014-05-24 19:41           ` Dmitry A. Kazakov
2014-05-20 11:55 ` Dmitry A. Kazakov
2014-05-20 12:28   ` Victor Porton
2014-05-20 14:11     ` Dmitry A. Kazakov

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