comp.lang.ada
 help / color / mirror / Atom feed
* T'Interface attribute
@ 2017-08-02 13:43 Dmitry A. Kazakov
  2017-08-02 14:23 ` Eryndlia Mavourneen
  2017-08-03  4:46 ` Randy Brukardt
  0 siblings, 2 replies; 20+ messages in thread
From: Dmitry A. Kazakov @ 2017-08-02 13:43 UTC (permalink / raw)


In order to reduce name space contamination I would propose attribute 
T'Interface which for any tagged type T would denote an interface type 
with all *new* primitive operations, e.g.

    type Derived is new Parent with ...;
    not overriding procedure Foo (X : Derived);

is equivalent to

    type Derived'Interface is [limited etc] interface;
    procedure Foo (X : Derived'Interface);

    type Derived is new Parent and Derived'Interface with ...;

T'Interface is visible at the declaration point of T. Its use is same as 
of T. E.g. prior to the freezing point of T is "premature".

Question. If T has any discriminants so does T'Interface.

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


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

* Re: T'Interface attribute
  2017-08-02 13:43 T'Interface attribute Dmitry A. Kazakov
@ 2017-08-02 14:23 ` Eryndlia Mavourneen
  2017-08-03 12:52   ` Dmitry A. Kazakov
  2017-08-03  4:46 ` Randy Brukardt
  1 sibling, 1 reply; 20+ messages in thread
From: Eryndlia Mavourneen @ 2017-08-02 14:23 UTC (permalink / raw)


On Wednesday, August 2, 2017 at 8:43:41 AM UTC-5, Dmitry A. Kazakov wrote:
> In order to reduce name space contamination I would propose attribute 
> T'Interface which for any tagged type T would denote an interface type 
> with all *new* primitive operations, e.g.
> 
>     type Derived is new Parent with ...;
>     not overriding procedure Foo (X : Derived);
> 
> is equivalent to
> 
>     type Derived'Interface is [limited etc] interface;
>     procedure Foo (X : Derived'Interface);
> 
>     type Derived is new Parent and Derived'Interface with ...;
> 
> T'Interface is visible at the declaration point of T. Its use is same as 
> of T. E.g. prior to the freezing point of T is "premature".
> 
> Question. If T has any discriminants so does T'Interface.
> 
> -- 
> Regards,
> Dmitry A. Kazakov
> http://www.dmitry-kazakov.de

I believe this is a good idea.

Regarding discriminants:  Yes, they should extend to T'Interface, and T'Interface should be able to add discriminants, as desired/necessary.


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

* Re: T'Interface attribute
  2017-08-02 13:43 T'Interface attribute Dmitry A. Kazakov
  2017-08-02 14:23 ` Eryndlia Mavourneen
@ 2017-08-03  4:46 ` Randy Brukardt
  2017-08-03  7:26   ` Dmitry A. Kazakov
  2017-08-03 17:27   ` Eryndlia Mavourneen
  1 sibling, 2 replies; 20+ messages in thread
From: Randy Brukardt @ 2017-08-03  4:46 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:olskua$1bfd$1@gioia.aioe.org...
> In order to reduce name space contamination I would propose attribute 
> T'Interface which for any tagged type T would denote an interface type 
> with all *new* primitive operations, e.g.

Past experience say that such attributes (that is, those that designate some 
sort of type or subtype) don't work out very well in Ada. For instance, we 
considered T'Access in Ada 2005, but gave that up because of various 
problems (and replaced with with anonymous access types, which are worse). 
The worst problem was that there was no limit to the attribute, you could 
write T'Access'Access'Access - and you can't prevent this since T could be a 
generic formal type that itself is some T'Access.

Almost all Ada compilers materialize all Ada types in their symbol table, so 
the effect of having a T'Interface would be that it would be automatically 
declared for all tagged type declarations. Most Ada compilers also 
materialize all of the primitive operations in their symbol table, so there 
would be a large increase in memory usage and some time increase (all 
lookups would have twice as many primitives to look through).

All that said, it may make sense to work out the details; clearly an 
interface (which is indefinite) has less of these issues than an elementary 
type like T'Access. But I'm certain that it would have a distributed 
overhead on a compiler (maybe not as much of a concern as a distributed 
overhead on a compiled program, but it still matters).

                                  Randy.

P.S. And as always, explain the problem to be solved as well as the possible 
solution. That is always necessary to understand the value of a proposal.

P.P.S. I personally have never seen a real-world example where an interface 
actually helps. There's lots and lots of book examples and show examples and 
so on, but in practice you end up with only a single implementation so there 
really is nothing gained by involving a lot of dispatching calls. Ergo, I'm 
against anything (new) involving interfaces. YMMV. 


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

* Re: T'Interface attribute
  2017-08-03  4:46 ` Randy Brukardt
@ 2017-08-03  7:26   ` Dmitry A. Kazakov
  2017-08-04 23:51     ` Randy Brukardt
  2017-08-03 17:27   ` Eryndlia Mavourneen
  1 sibling, 1 reply; 20+ messages in thread
From: Dmitry A. Kazakov @ 2017-08-03  7:26 UTC (permalink / raw)


On 2017-08-03 06:46, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:olskua$1bfd$1@gioia.aioe.org...
>> In order to reduce name space contamination I would propose attribute
>> T'Interface which for any tagged type T would denote an interface type
>> with all *new* primitive operations, e.g.
> 
> Past experience say that such attributes (that is, those that designate some
> sort of type or subtype) don't work out very well in Ada. For instance, we
> considered T'Access in Ada 2005, but gave that up because of various
> problems (and replaced with with anonymous access types, which are worse).
> The worst problem was that there was no limit to the attribute, you could
> write T'Access'Access'Access - and you can't prevent this since T could be a
> generic formal type that itself is some T'Access.

In this case generic would not be a problem because T must be tagged to 
have T'Interface.

As a side note, differently to 'Access, 'Length and actually 'Class, 
'Interface is idempotent:

    T'Interface ::= T'Interface'Interface

> Almost all Ada compilers materialize all Ada types in their symbol table, so
> the effect of having a T'Interface would be that it would be automatically
> declared for all tagged type declarations. Most Ada compilers also
> materialize all of the primitive operations in their symbol table, so there
> would be a large increase in memory usage and some time increase (all
> lookups would have twice as many primitives to look through).

This is an intended effect. Yes, there would likely be two tags for each 
declared type.

Which by the way will fix Ada.Streams and System.Storage_Pools design 
for free. Since we will finally have:

    Root_Stream_Type'Interface

and

    Root_Storage_Pool'Interface

E.g.

    type Serialized_Widget is
       new Gtk_Widget_Record and Root_Stream_Type'Interface with private;

> P.S. And as always, explain the problem to be solved as well as the possible
> solution. That is always necessary to understand the value of a proposal.

I have a design rule to have an explicit interface declared for each 
tagged type. It saves much of redesign later.

> P.P.S. I personally have never seen a real-world example where an interface
> actually helps. There's lots and lots of book examples and show examples and
> so on, but in practice you end up with only a single implementation so there
> really is nothing gained by involving a lot of dispatching calls. Ergo, I'm
> against anything (new) involving interfaces. YMMV.

I have no idea how you manage keep Claw out of interfaces, really. 
Multiple inheritance is a huge help and relief. I am using interfaces 
extensively unless backward Ada 95 compatibility hinders me. E.g. in 
AICWL all widget layers implement interfaces like Scalable_Layer, 
Gauge_Needle, Waveform_Amplifier etc. It would not work otherwise.

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


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

* Re: T'Interface attribute
  2017-08-02 14:23 ` Eryndlia Mavourneen
@ 2017-08-03 12:52   ` Dmitry A. Kazakov
  0 siblings, 0 replies; 20+ messages in thread
From: Dmitry A. Kazakov @ 2017-08-03 12:52 UTC (permalink / raw)


On 2017-08-02 16:23, Eryndlia Mavourneen wrote:

> Regarding discriminants:  Yes, they should extend to T'Interface, and
> T'Interface should be able to add discriminants, as
> desired/necessary.
Yes. It seems that if T is an interface, then T and T'Interface must be 
same exactly types. Therefore discriminants must be retained.

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

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

* Re: T'Interface attribute
  2017-08-03  4:46 ` Randy Brukardt
  2017-08-03  7:26   ` Dmitry A. Kazakov
@ 2017-08-03 17:27   ` Eryndlia Mavourneen
  2017-08-05  0:09     ` Randy Brukardt
  1 sibling, 1 reply; 20+ messages in thread
From: Eryndlia Mavourneen @ 2017-08-03 17:27 UTC (permalink / raw)


On Wednesday, August 2, 2017 at 11:46:56 PM UTC-5, Randy Brukardt wrote:
> 
> P.S. And as always, explain the problem to be solved as well as the possible 
> solution. That is always necessary to understand the value of a proposal.
> 
> P.P.S. I personally have never seen a real-world example where an interface 
> actually helps. There's lots and lots of book examples and show examples and 
> so on, but in practice you end up with only a single implementation so there 
> really is nothing gained by involving a lot of dispatching calls. Ergo, I'm 
> against anything (new) involving interfaces. YMMV.

I use task interfaces in the case in which I have a basic task design that has certain core functionality and additionally may have any of a variety of other functionalities, too.  At the point at which I am ready to consolidate the interfaces into a specific kind of task, combining the interfaces, which already have declared the necessary entries (as procedures), becomes akin to building using Legos.

I find this kind of construction most pleasurable to design and implement.  It also is easy to understand.


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

* Re: T'Interface attribute
  2017-08-03  7:26   ` Dmitry A. Kazakov
@ 2017-08-04 23:51     ` Randy Brukardt
  2017-08-05  7:49       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 20+ messages in thread
From: Randy Brukardt @ 2017-08-04 23:51 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:oluj7t$8uo$1@gioia.aioe.org...
> On 2017-08-03 06:46, Randy Brukardt wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>> news:olskua$1bfd$1@gioia.aioe.org...
>>> In order to reduce name space contamination I would propose attribute
>>> T'Interface which for any tagged type T would denote an interface type
>>> with all *new* primitive operations, e.g.
>>
>> Past experience say that such attributes (that is, those that designate 
>> some
>> sort of type or subtype) don't work out very well in Ada. For instance, 
>> we
>> considered T'Access in Ada 2005, but gave that up because of various
>> problems (and replaced with with anonymous access types, which are 
>> worse).
>> The worst problem was that there was no limit to the attribute, you could
>> write T'Access'Access'Access - and you can't prevent this since T could 
>> be a
>> generic formal type that itself is some T'Access.
>
> In this case generic would not be a problem because T must be tagged to 
> have T'Interface.
>
> As a side note, differently to 'Access, 'Length and actually 'Class, 
> 'Interface is idempotent:
>
>    T'Interface ::= T'Interface'Interface

Ada defines 'Class this way, too, I think in part to mitigate these 
problems.

The problem with formals is from the actual being T'Interface:

    generic
       type T is abstract tagged private;
    package Gen is
        procedure P (Item : in T'Interface);
    end Gen;

    package Inst is new Gen (Some_Tagged_Type'Interface);

The parameter of P is essentially Some_Tagged_Type'Interface'Interface.

>> Almost all Ada compilers materialize all Ada types in their symbol table, 
>> so
>> the effect of having a T'Interface would be that it would be 
>> automatically
>> declared for all tagged type declarations. Most Ada compilers also
>> materialize all of the primitive operations in their symbol table, so 
>> there
>> would be a large increase in memory usage and some time increase (all
>> lookups would have twice as many primitives to look through).
>
> This is an intended effect. Yes, there would likely be two tags for each 
> declared type.
>
> Which by the way will fix Ada.Streams and System.Storage_Pools design for 
> free. Since we will finally have:
>
>    Root_Stream_Type'Interface
>
> and
>
>    Root_Storage_Pool'Interface
>
> E.g.
>
>    type Serialized_Widget is
>       new Gtk_Widget_Record and Root_Stream_Type'Interface with private;

The problem with "fixing" Root_Stream_Type etc. is the "no hidden 
interfaces" rule. These types are often used in private derivations, and 
that is illegal for interfaces. (Attempts to weaken the "no hidden 
interfaces" rule have led to various definitional nightmares - it does not 
look likely. AI12-0023-1 discusses the latest attempts - it's still open but 
hasn't been discussed since Stockholm.)

That suggests a problem with this idea: effectivelly all types would have an 
associated interface. But interfaces can never be hidden (certainly not 
without restrictions as discussed in AI12-0023-1), so that would seem to 
imply that no hidden type derivations could occur. That would be a massive 
compatibility problem.

>> P.S. And as always, explain the problem to be solved as well as the 
>> possible
>> solution. That is always necessary to understand the value of a proposal.
>
> I have a design rule to have an explicit interface declared for each 
> tagged type. It saves much of redesign later.

I've generally materialized that as "the root of an abstraction should 
always be declared abstract".

>> P.P.S. I personally have never seen a real-world example where an 
>> interface
>> actually helps. There's lots and lots of book examples and show examples 
>> and
>> so on, but in practice you end up with only a single implementation so 
>> there
>> really is nothing gained by involving a lot of dispatching calls. Ergo, 
>> I'm
>> against anything (new) involving interfaces. YMMV.
>
> I have no idea how you manage keep Claw out of interfaces, really. 
> Multiple inheritance is a huge help and relief. I am using interfaces 
> extensively unless backward Ada 95 compatibility hinders me. E.g. in AICWL 
> all widget layers implement interfaces like Scalable_Layer, Gauge_Needle, 
> Waveform_Amplifier etc. It would not work otherwise.

In Claw, the only places that we got much benefit from OOP (beyond 
dispatching callbacks, the reason we used OOP in the first place) was in 
sharing implementations across related types. But that doesn't work for Ada 
interfaces, because you can't have any components in the type -- meaning 
that writing real implementations is impossible. One can use abstract types 
in this way (and we did so extensively).

We didn't find much use for dispatching (outside of the callbacks as 
previously mentioned; those only need to work on root types since they come 
directly from the message loop engine). If you don't need (or can use) 
dispatching, and since you can't use implementation inheritance, the use of 
interfaces buys nothing.

(Of course, we didn't have interfaces when Claw was designed, so it wasn't 
even an option. Perhaps we'd have done something differently had they been 
available -- but I doubt it.)

That pattern has persisted in pretty much all of my recent programs; I don't 
usually have very deep hierarchies and dispatching is limited to the root 
types (which I declare abstract for maximum sharing).

I realize other people end up with other patterns, but I'm not going to 
champion something I don't find useful. (I doubt I could do a good job of 
championing it anyway).

                                       Randy.



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

* Re: T'Interface attribute
  2017-08-03 17:27   ` Eryndlia Mavourneen
@ 2017-08-05  0:09     ` Randy Brukardt
  2017-08-05 19:02       ` Eryndlia Mavourneen
  0 siblings, 1 reply; 20+ messages in thread
From: Randy Brukardt @ 2017-08-05  0:09 UTC (permalink / raw)


"Eryndlia Mavourneen" <eryndlia@gmail.com> wrote in message 
news:f647e80e-7171-47be-83f2-f68eb68cb2f2@googlegroups.com...
On Wednesday, August 2, 2017 at 11:46:56 PM UTC-5, Randy Brukardt wrote:
...
> P.P.S. I personally have never seen a real-world example where an 
> interface
> actually helps. There's lots and lots of book examples and show examples 
> and
> so on, but in practice you end up with only a single implementation so 
> there
> really is nothing gained by involving a lot of dispatching calls. Ergo, 
> I'm
> against anything (new) involving interfaces. YMMV.
>
>I use task interfaces in the case in which I have a basic task design that 
>has
>certain core functionality and additionally may have any of a variety of 
>other
>functionalities, too.  At the point at which I am ready to consolidate the
>interfaces into a specific kind of task, combining the interfaces, which 
>already
>have declared the necessary entries (as procedures), becomes akin to 
>building
>using Legos.

This is the sort of thing that doesn't make a lot of sense to me. Interfaces 
are only useful if there are going to be multiple implementations of them. 
Otherwise, they just add unspeakable runtime overhead and you're getting 
nothing for them. Specifically, you have to be able to have useful routines 
made up of only dispatching calls. When I tried that in the Claw Builder, it 
turned into a maintenance nightmare - any significant change required a 
change to every specific type. And adding a new specific type took multiple 
days (there being so many routines to implement). It just doesn't fit with 
the agile-style programming that I do.

>I find this kind of construction most pleasurable to design and implement. 
>It also
>is easy to understand.

Obviously, YMMV. Just don't expect me to push for anything involving 
interfaces.

                        Randy. 


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

* Re: T'Interface attribute
  2017-08-04 23:51     ` Randy Brukardt
@ 2017-08-05  7:49       ` Dmitry A. Kazakov
  2017-08-07 22:59         ` Randy Brukardt
  0 siblings, 1 reply; 20+ messages in thread
From: Dmitry A. Kazakov @ 2017-08-05  7:49 UTC (permalink / raw)


On 2017-08-05 01:51, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:oluj7t$8uo$1@gioia.aioe.org...
>> On 2017-08-03 06:46, Randy Brukardt wrote:
>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>>> news:olskua$1bfd$1@gioia.aioe.org...
>>>> In order to reduce name space contamination I would propose attribute
>>>> T'Interface which for any tagged type T would denote an interface type
>>>> with all *new* primitive operations, e.g.
>>>
>>> Past experience say that such attributes (that is, those that designate
>>> some
>>> sort of type or subtype) don't work out very well in Ada. For instance,
>>> we
>>> considered T'Access in Ada 2005, but gave that up because of various
>>> problems (and replaced with with anonymous access types, which are
>>> worse).
>>> The worst problem was that there was no limit to the attribute, you could
>>> write T'Access'Access'Access - and you can't prevent this since T could
>>> be a
>>> generic formal type that itself is some T'Access.
>>
>> In this case generic would not be a problem because T must be tagged to
>> have T'Interface.
>>
>> As a side note, differently to 'Access, 'Length and actually 'Class,
>> 'Interface is idempotent:
>>
>>     T'Interface ::= T'Interface'Interface
> 
> Ada defines 'Class this way, too, I think in part to mitigate these
> problems.
> 
> The problem with formals is from the actual being T'Interface:
> 
>      generic
>         type T is abstract tagged private;
>      package Gen is
>          procedure P (Item : in T'Interface);
>      end Gen;
> 
>      package Inst is new Gen (Some_Tagged_Type'Interface);
> 
> The parameter of P is essentially Some_Tagged_Type'Interface'Interface.

But P is not primitive. So effectively it can be compiled into

    procedure P (Item : in T);

There is no requirement on what would evaluate this:

    package body Gen is
       function Check (X : T'Interface; Y : T) return Boolean
       begin
          return X'Tag = Y'Tag;
       end Check;

> That suggests a problem with this idea: effectivelly all types would have an
> associated interface. But interfaces can never be hidden (certainly not
> without restrictions as discussed in AI12-0023-1), so that would seem to
> imply that no hidden type derivations could occur. That would be a massive
> compatibility problem.

Yes, you mean this:

       type I is interface;
       type T is new I with null record;

       type S is tagged private;
    private
       type S is new T with null record; -- Illegal? Come on!

This mess should be fixed someday.

BTW, there is nothing wrong with hidden interfaces. There apparent 
problems come from an misunderstanding, IMO.

There is nothing wrong with additive inheritance. The same interface 
when added twice once publicly once privately could simply allocate new 
slots. In all contexts where both become visible must require explicit 
name resolution, e.g. by renaming one of the types and/or primitive 
operations.

The typical use-case is a linked list interface, when elements 
participate in several lists.

    type Linked is limited interface;
    function Next (Element : Linked) return Linked;
    ...

    type Triple_Queue is new Linked or Linked or Linked with ...

>>> P.S. And as always, explain the problem to be solved as well as the possible
>>> solution. That is always necessary to understand the value of a proposal.
>>
>> I have a design rule to have an explicit interface declared for each
>> tagged type. It saves much of redesign later.
> 
> I've generally materialized that as "the root of an abstraction should
> always be declared abstract".

Yes, but this is not enough, because it kills potential 
multiple-inheritance cases.

> In Claw, the only places that we got much benefit from OOP (beyond
> dispatching callbacks, the reason we used OOP in the first place) was in
> sharing implementations across related types. But that doesn't work for Ada
> interfaces, because you can't have any components in the type -- meaning
> that writing real implementations is impossible. One can use abstract types
> in this way (and we did so extensively).

Reuse happens on the client's side, when you share interface-wide 
implementations. This includes helper types which refer to [access] 
I'Class. Surely you have lots of them to pass widgets around, in events, 
in handlers etc.

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

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

* Re: T'Interface attribute
  2017-08-05  0:09     ` Randy Brukardt
@ 2017-08-05 19:02       ` Eryndlia Mavourneen
  2017-08-07 22:49         ` Randy Brukardt
  0 siblings, 1 reply; 20+ messages in thread
From: Eryndlia Mavourneen @ 2017-08-05 19:02 UTC (permalink / raw)


On Friday, August 4, 2017 at 7:09:19 PM UTC-5, Randy Brukardt wrote:
> ...
> Interfaces 
> are only useful if there are going to be multiple implementations of them. 
> Otherwise, they just add unspeakable runtime overhead and you're getting 
> nothing for them. Specifically, you have to be able to have useful routines 
> made up of only dispatching calls. When I tried that in the Claw Builder, it 
> turned into a maintenance nightmare - any significant change required a 
> change to every specific type. And adding a new specific type took multiple 
> days (there being so many routines to implement). It just doesn't fit with 
> the agile-style programming that I do.
> 
> >I find this kind of construction most pleasurable to design and implement. 
> >It also
> >is easy to understand.
> 
> Obviously, YMMV. Just don't expect me to push for anything involving 
> interfaces.
> 
>                         Randy.

The whole idea is to have "multiple implementations" of the core task, tacking on whatever additional functions may be desired to result in different tasks but with some shared functionality.  I'm not an Ada language designer, but my understanding is that the piecing together of tasks in this way is handled largely by the compiler and does not *necessarily* involve dispatching:

     type Base_Task is task interface;
     procedure Awaken (...) is abstract;

     type Random_Things is task interface;
     procedure Do_Random_Things is abstract;

     type Persistent is task interface and Base_Task;
     procedure Do_Something (...) is abstract;

     type Temp is task interface and Base_Task;
     procedure Do_Something_Else (...) is abstract;

     ...

     task type Persistent_Task (...) is new Common and Persistent with

        entry Awaken (...);

        entry Do_Random_Things;

        entry Do_Something (...);

     end Persistent_Task;

     ...

This code is "off-the-cuff" and so may be a little off, but I think the intention is clear enough.

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

* Re: T'Interface attribute
  2017-08-05 19:02       ` Eryndlia Mavourneen
@ 2017-08-07 22:49         ` Randy Brukardt
  0 siblings, 0 replies; 20+ messages in thread
From: Randy Brukardt @ 2017-08-07 22:49 UTC (permalink / raw)



"Eryndlia Mavourneen" <eryndlia@gmail.com> wrote in message 
news:74abc378-88a6-49bd-997b-fe25871b7303@googlegroups.com...
...
>The whole idea is to have "multiple implementations" of the core task, 
>tacking on
>whatever additional functions may be desired to result in different tasks 
>but with
>some shared functionality.  I'm not an Ada language designer, but my
>understanding is that the piecing together of tasks in this way is handled 
>largely
>by the compiler and does not *necessarily* involve dispatching:

You're right that the specific tasks don't involve dispatching, but if the 
interfaces are going to have any value at all for their costs, you have to 
use them by themselves (typically as class-wide parameters to routines). 
Thus calls to those uses (parameters) them are necessarily dispatching.

If you don't actually have dispatching calls, then you are generating a lot 
of expensive unused code in your program, and most likely bloating your 
application size. (Janus/Ada can trim unused primitives at link-time, but I 
don't think any other Ada compiler offers an optimization like that.) And 
it's very unclear to me what possible gain you get from using interfaces in 
such a case rather than just declaring the operations you need.

                                 Randy.

P.S. I see a bit more value to task and protected interfaces to the normal 
kind, because there is no other way to get dispatching for those types. But 
still, it seems reasonably rare that dispatching would be useful, since you 
need a program with multiple tasks implementing the same interface. That 
doesn't happen often.



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

* Re: T'Interface attribute
  2017-08-05  7:49       ` Dmitry A. Kazakov
@ 2017-08-07 22:59         ` Randy Brukardt
  2017-08-08  6:13           ` Dmitry A. Kazakov
  0 siblings, 1 reply; 20+ messages in thread
From: Randy Brukardt @ 2017-08-07 22:59 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:om3ta9$fnc$1@gioia.aioe.org...
...
> There is nothing wrong with additive inheritance. The same interface when 
> added twice once publicly once privately could simply allocate new slots.

We tried that. But...

>...  In all contexts where both become visible must require explicit name 
>resolution, e.g. by renaming one of the types and/or primitive operations.

Ada doesn't have type renaming, so this is not possible in general. And 
having calls be illegal in such cases is a massive problem in generic 
bodies. Typical assume-the-worst rules would have to make calling any 
interface related to a formal illegal in a generic body.

It was a massive can of worms.

The alternative approach (the interface is the same) breaks privacy pretty 
badly.

We essentially gave up, and more recent attempts to allow a limited set of 
"hidable interfaces" didn't fare any better.

...

...
>> I've generally materialized that as "the root of an abstraction should
>> always be declared abstract".
>
> Yes, but this is not enough, because it kills potential 
> multiple-inheritance cases.

As an implementer, knowing that multiple-inheritance is just barely possible 
to implement, I'm unwilling to consider that unless no other possibility 
exists. And some other way always exists. :-)

>> In Claw, the only places that we got much benefit from OOP (beyond
>> dispatching callbacks, the reason we used OOP in the first place) was in
>> sharing implementations across related types. But that doesn't work for 
>> Ada
>> interfaces, because you can't have any components in the type -- meaning
>> that writing real implementations is impossible. One can use abstract 
>> types
>> in this way (and we did so extensively).
>
> Reuse happens on the client's side, when you share interface-wide 
> implementations. This includes helper types which refer to [access] 
> I'Class. Surely you have lots of them to pass widgets around, in events, 
> in handlers etc.

Not really. The implementation has such things, but we only exposed 
parameters of Root_Window_Type'Class (with a couple of exceptions). The vast 
majority of routines only take a single object.

The other hierarchies (canvas, menus, etc.) work similarly.

                                       Randy.



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

* Re: T'Interface attribute
  2017-08-07 22:59         ` Randy Brukardt
@ 2017-08-08  6:13           ` Dmitry A. Kazakov
  2017-08-09  0:38             ` Randy Brukardt
  0 siblings, 1 reply; 20+ messages in thread
From: Dmitry A. Kazakov @ 2017-08-08  6:13 UTC (permalink / raw)


On 2017-08-08 00:59, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message

>> ...  In all contexts where both become visible must require explicit name
>> resolution, e.g. by renaming one of the types and/or primitive operations.
> 
> Ada doesn't have type renaming, so this is not possible in general.

Not exactly renaming, but a schema to qualify the parent:

    type T is new I as I1 and new I as I2 with null record;
    overriding I1 procedure Foo (X : T);
    overriding I2 procedure Foo (X : T);

>>> I've generally materialized that as "the root of an abstraction should
>>> always be declared abstract".
>>
>> Yes, but this is not enough, because it kills potential
>> multiple-inheritance cases.
> 
> As an implementer, knowing that multiple-inheritance is just barely possible
> to implement, I'm unwilling to consider that unless no other possibility
> exists. And some other way always exists. :-)

But Ada 2005 did it, so I am happily using it. (:-))

>>> In Claw, the only places that we got much benefit from OOP (beyond
>>> dispatching callbacks, the reason we used OOP in the first place) was in
>>> sharing implementations across related types. But that doesn't work for Ada
>>> interfaces, because you can't have any components in the type -- meaning
>>> that writing real implementations is impossible. One can use abstract types
>>> in this way (and we did so extensively).
>>
>> Reuse happens on the client's side, when you share interface-wide
>> implementations. This includes helper types which refer to [access]
>> I'Class. Surely you have lots of them to pass widgets around, in events,
>> in handlers etc.
> 
> Not really. The implementation has such things, but we only exposed
> parameters of Root_Window_Type'Class (with a couple of exceptions). The vast
> majority of routines only take a single object.

If you have a On_Button_Click event handler you want to pass there only 
implementations from Window_Clickable_Type'Class. Not just any 
Root_Window_Type'Class. And there is no way to place all they subclasses 
into single chain of inheritance. Some of Window_Clickable_Type are also 
Window_File_Selector_Type and Window_DnD_Type etc.

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


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

* Re: T'Interface attribute
  2017-08-08  6:13           ` Dmitry A. Kazakov
@ 2017-08-09  0:38             ` Randy Brukardt
  2017-08-09  7:06               ` Dmitry A. Kazakov
  0 siblings, 1 reply; 20+ messages in thread
From: Randy Brukardt @ 2017-08-09  0:38 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:ombkql$rjr$1@gioia.aioe.org...
> On 2017-08-08 00:59, Randy Brukardt wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>
>>> ...  In all contexts where both become visible must require explicit 
>>> name
>>> resolution, e.g. by renaming one of the types and/or primitive 
>>> operations.
>>
>> Ada doesn't have type renaming, so this is not possible in general.
>
> Not exactly renaming, but a schema to qualify the parent:
>
>    type T is new I as I1 and new I as I2 with null record;
>    overriding I1 procedure Foo (X : T);
>    overriding I2 procedure Foo (X : T);

This sort of thing is *precisely* what we mean when we talk about "type 
renaming". Renaming has to bring along the primitives. Sadly, we've never 
been able to work out a version that isn't evil (the effect of the simple 
version is as nasty as a package use clause, and less obvious, so it tends 
not to fly).

>>>> I've generally materialized that as "the root of an abstraction should
>>>> always be declared abstract".
>>>
>>> Yes, but this is not enough, because it kills potential
>>> multiple-inheritance cases.
>>
>> As an implementer, knowing that multiple-inheritance is just barely 
>> possible
>> to implement, I'm unwilling to consider that unless no other possibility
>> exists. And some other way always exists. :-)
>
> But Ada 2005 did it, so I am happily using it. (:-))

Well, I only use the parts of Ada implemented in Janus/Ada, and interfaces 
aren't there. (Indeed, the majority of Ada 2005 isn't there, I've kinda 
skipped ahead to Ada 2012 which is more interesting and implementable.)

>>>> In Claw, the only places that we got much benefit from OOP (beyond
>>>> dispatching callbacks, the reason we used OOP in the first place) was 
>>>> in
>>>> sharing implementations across related types. But that doesn't work for 
>>>> Ada
>>>> interfaces, because you can't have any components in the type --  
>>>> meaning
>>>> that writing real implementations is impossible. One can use abstract 
>>>> types
>>>> in this way (and we did so extensively).
>>>
>>> Reuse happens on the client's side, when you share interface-wide
>>> implementations. This includes helper types which refer to [access]
>>> I'Class. Surely you have lots of them to pass widgets around, in events,
>>> in handlers etc.
>>
>> Not really. The implementation has such things, but we only exposed
>> parameters of Root_Window_Type'Class (with a couple of exceptions). The 
>> vast
>> majority of routines only take a single object.
>
> If you have a On_Button_Click event handler you want to pass there only 
> implementations from Window_Clickable_Type'Class. Not just any 
> Root_Window_Type'Class. And there is no way to place all they subclasses 
> into single chain of inheritance. Some of Window_Clickable_Type are also 
> Window_File_Selector_Type and Window_DnD_Type etc.

We didn't bother. My recollection is that Windows doesn't make a distinction 
anyway, I believe all Windows "windows" can be clicked, just some have 
default actions in that case, and others do nothing. So you can use the 
handler on any item that has focus, and if you wanted to do something when 
someone clicked a text label, you could. That allows building new kinds of 
controls out of existing ones, among other things.

In the long run, it because fairly obvious that the best design was to make 
everything primitive and never use class-wide items anywhere (and only use 
dispatching in call-backs). Places where we didn't do that we often lived to 
regret and in extreme cases, change (like the Move Window routine, which 
started out class-wide and ended up both -- as we couldn't remove the 
class-wide routine for compatibility reasons).

                              Randy. 



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

* Re: T'Interface attribute
  2017-08-09  0:38             ` Randy Brukardt
@ 2017-08-09  7:06               ` Dmitry A. Kazakov
  2017-08-09 23:03                 ` Randy Brukardt
  0 siblings, 1 reply; 20+ messages in thread
From: Dmitry A. Kazakov @ 2017-08-09  7:06 UTC (permalink / raw)


On 2017-08-09 02:38, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message

> We didn't bother. My recollection is that Windows doesn't make a distinction
> anyway, I believe all Windows "windows" can be clicked, just some have
> default actions in that case, and others do nothing.

So you basically drop typing. I don't. There are lots of languages going 
this path. Why use Ada?

> In the long run, it because fairly obvious that the best design was to make
> everything primitive and never use class-wide items anywhere (and only use
> dispatching in call-backs).

Huh, without multiple dispatch this has no chance to work. Anyway 
multiple dispatch does not supersede multiple inheritance.

> Places where we didn't do that we often lived to
> regret and in extreme cases, change (like the Move Window routine, which
> started out class-wide and ended up both -- as we couldn't remove the
> class-wide routine for compatibility reasons).

I agree that there are difficult choices between class-wide and 
primitive. If you make everything primitive you may be hit by 
re-dispatch issues later. However this is more related to alternative 
decomposition methods Ada does not have, e.g. operation extension, 
delegation etc.

Nothing of this can ever eliminate interfaces.

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


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

* Re: T'Interface attribute
  2017-08-09  7:06               ` Dmitry A. Kazakov
@ 2017-08-09 23:03                 ` Randy Brukardt
  2017-08-10  7:13                   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 20+ messages in thread
From: Randy Brukardt @ 2017-08-09 23:03 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:omeca9$11pb$1@gioia.aioe.org...
> On 2017-08-09 02:38, Randy Brukardt wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>
>> We didn't bother. My recollection is that Windows doesn't make a 
>> distinction
>> anyway, I believe all Windows "windows" can be clicked, just some have
>> default actions in that case, and others do nothing.
>
> So you basically drop typing. I don't. There are lots of languages going 
> this path. Why use Ada?

We were binding Windows (specifically Win32), not creating some abstract 
GUI. Trying to impose typing on an underlying design (especially one as 
complex as Win32) that doesn't have it is almost always a losing game. The 
goal of Claw was to allow anything that Win32 would allow, just in a 
higher-level manner. Moreover, allowing all of the messages to be delivered 
to every Window, besides being necessary if Claw could be used on window 
types that it wasn't aware of, also allows creating interesting new types of 
windows from low-level operations. The Claw Builder uses this extensively in 
supporting its editing mode (which relies heavily on overlays over otherwise 
normal windows).

                       Randy. 


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

* Re: T'Interface attribute
  2017-08-09 23:03                 ` Randy Brukardt
@ 2017-08-10  7:13                   ` Dmitry A. Kazakov
  2017-08-11  0:33                     ` Randy Brukardt
  0 siblings, 1 reply; 20+ messages in thread
From: Dmitry A. Kazakov @ 2017-08-10  7:13 UTC (permalink / raw)


On 2017-08-10 01:03, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:omeca9$11pb$1@gioia.aioe.org...
>> On 2017-08-09 02:38, Randy Brukardt wrote:
>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>>
>>> We didn't bother. My recollection is that Windows doesn't make a distinction
>>> anyway, I believe all Windows "windows" can be clicked, just some have
>>> default actions in that case, and others do nothing.
>>
>> So you basically drop typing. I don't. There are lots of languages going
>> this path. Why use Ada?
> 
> We were binding Windows (specifically Win32), not creating some abstract
> GUI. Trying to impose typing on an underlying design (especially one as
> complex as Win32) that doesn't have it is almost always a losing game.

I am not a fan of MFC, yet they tried that. But basically you confirmed 
my point, it is either interfaces or low-level and weakly-typed.

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


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

* Re: T'Interface attribute
  2017-08-10  7:13                   ` Dmitry A. Kazakov
@ 2017-08-11  0:33                     ` Randy Brukardt
  2017-08-11  6:55                       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 20+ messages in thread
From: Randy Brukardt @ 2017-08-11  0:33 UTC (permalink / raw)



"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:omh11u$1bto$1@gioia.aioe.org...
> On 2017-08-10 01:03, Randy Brukardt wrote:
...
>> We were binding Windows (specifically Win32), not creating some abstract
>> GUI. Trying to impose typing on an underlying design (especially one as
>> complex as Win32) that doesn't have it is almost always a losing game.
>
> I am not a fan of MFC, yet they tried that. But basically you confirmed my 
> point, it is either interfaces or low-level and weakly-typed.

I don't think they tried it much, there are only a handful of basic 
callbacks in Win32, and those are presented to all window types. They may 
have had more synthesized callbacks than we do, but we do have some. They 
just belong to a single branch of types and are directly implemented by the 
root type of the branch. (Yes, if some child type overrides the general 
routine and failed to call the parent routine, the whole thing will fall 
over in a heap. Not much to do about that in Ada 95.)

There just are a number of these derived actions that are commonly used 
enough that we put them at the top level. That prevents the overriding 
problem (no one can override the message dispatching loop itself). It 
doesn't make sense to define, say, When_Horizontal_Scroll, on ten different 
window types. (Note that using interfaces, you'd *still* have to define the 
default implementation on all of those window types, and even with multiple 
inheritance that Ada doesn't have, you'd still have to override the general 
message routine for each of those window types [multiple inheritance can't 
combine the differing implementation inherited from different ancestors, 
that has to be done manually].

So, I don't see that interfaces or even multiple inheritance really buys 
much here.

                                              Randy.



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

* Re: T'Interface attribute
  2017-08-11  0:33                     ` Randy Brukardt
@ 2017-08-11  6:55                       ` Dmitry A. Kazakov
  2017-08-11 20:49                         ` Randy Brukardt
  0 siblings, 1 reply; 20+ messages in thread
From: Dmitry A. Kazakov @ 2017-08-11  6:55 UTC (permalink / raw)


On 2017-08-11 02:33, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:omh11u$1bto$1@gioia.aioe.org...
>> On 2017-08-10 01:03, Randy Brukardt wrote:
> ...
>>> We were binding Windows (specifically Win32), not creating some abstract
>>> GUI. Trying to impose typing on an underlying design (especially one as
>>> complex as Win32) that doesn't have it is almost always a losing game.
>>
>> I am not a fan of MFC, yet they tried that. But basically you confirmed my
>> point, it is either interfaces or low-level and weakly-typed.
> 
> I don't think they tried it much, there are only a handful of basic
> callbacks in Win32, and those are presented to all window types. They may
> have had more synthesized callbacks than we do, but we do have some. They
> just belong to a single branch of types and are directly implemented by the
> root type of the branch. (Yes, if some child type overrides the general
> routine and failed to call the parent routine, the whole thing will fall
> over in a heap. Not much to do about that in Ada 95.)
> 
> There just are a number of these derived actions that are commonly used
> enough that we put them at the top level. That prevents the overriding
> problem (no one can override the message dispatching loop itself). It
> doesn't make sense to define, say, When_Horizontal_Scroll, on ten different
> window types. (Note that using interfaces, you'd *still* have to define the
> default implementation on all of those window types, and even with multiple
> inheritance that Ada doesn't have, you'd still have to override the general
> message routine for each of those window types [multiple inheritance can't
> combine the differing implementation inherited from different ancestors,
> that has to be done manually].

It could provide hook within the loop. And you would have to call 
parent's part from the override. This is the case of overriding by an 
extension.

> So, I don't see that interfaces or even multiple inheritance really buys
> much here.

It adds type safety. It a quite frequent error in GUI design to write a 
handler for an event that never comes.

Then it allows typed arguments in the event handler. In Windows 
everything is LPARAM, same in Gtk.

When using GtkAda it makes a huge difference. GtkAda defines some typed 
handlers, but not all. When you get hit by necessity to extract 
marshaled signal arguments and convert them to the designated types 
manually you thank GtkAda for all cases when you don't have to.

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


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

* Re: T'Interface attribute
  2017-08-11  6:55                       ` Dmitry A. Kazakov
@ 2017-08-11 20:49                         ` Randy Brukardt
  0 siblings, 0 replies; 20+ messages in thread
From: Randy Brukardt @ 2017-08-11 20:49 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:omjkds$1lob$1@gioia.aioe.org...
> On 2017-08-11 02:33, Randy Brukardt wrote:
...
>> So, I don't see that interfaces or even multiple inheritance really buys
>> much here.
>
> It adds type safety. It a quite frequent error in GUI design to write a 
> handler for an event that never comes.

That hasn't happened to me much, probably because the specific handlers are 
typed (most of the handlers I've needed are edit restrictions or handling 
buttons). Besides, constructing this sort of code is too tedious. I 
generally use the Claw Builder to make the outline of the code (which 
includes the handlers) and manually fill in the details.

> Then it allows typed arguments in the event handler. In Windows everything 
> is LPARAM, same in Gtk.

Yes, but that is only true in the general handler; all of the specific 
handlers are properly typed. Hopefully, no one will actually have to use the 
general handler - it's there just in case something Claw doesn't consider 
needs to be done.

> When using GtkAda it makes a huge difference. GtkAda defines some typed 
> handlers, but not all. When you get hit by necessity to extract marshaled 
> signal arguments and convert them to the designated types manually you 
> thank GtkAda for all cases when you don't have to.

Right. Sounds like using Claw.

                               Randy.



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

end of thread, other threads:[~2017-08-11 20:49 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-08-02 13:43 T'Interface attribute Dmitry A. Kazakov
2017-08-02 14:23 ` Eryndlia Mavourneen
2017-08-03 12:52   ` Dmitry A. Kazakov
2017-08-03  4:46 ` Randy Brukardt
2017-08-03  7:26   ` Dmitry A. Kazakov
2017-08-04 23:51     ` Randy Brukardt
2017-08-05  7:49       ` Dmitry A. Kazakov
2017-08-07 22:59         ` Randy Brukardt
2017-08-08  6:13           ` Dmitry A. Kazakov
2017-08-09  0:38             ` Randy Brukardt
2017-08-09  7:06               ` Dmitry A. Kazakov
2017-08-09 23:03                 ` Randy Brukardt
2017-08-10  7:13                   ` Dmitry A. Kazakov
2017-08-11  0:33                     ` Randy Brukardt
2017-08-11  6:55                       ` Dmitry A. Kazakov
2017-08-11 20:49                         ` Randy Brukardt
2017-08-03 17:27   ` Eryndlia Mavourneen
2017-08-05  0:09     ` Randy Brukardt
2017-08-05 19:02       ` Eryndlia Mavourneen
2017-08-07 22:49         ` Randy Brukardt

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