comp.lang.ada
 help / color / mirror / Atom feed
* Ada Annoyances
@ 2017-06-21  1:12 pythoner6
  2017-06-21 10:13 ` Lucretia
  2017-06-21 11:58 ` Ada Annoyances joakimds
  0 siblings, 2 replies; 116+ messages in thread
From: pythoner6 @ 2017-06-21  1:12 UTC (permalink / raw)


I've recently been trying to learn some Ada, however, I've encountered a few annoyances. I tend to perhaps be a bit too concerned about performance, so I try to stay away from things like tagged types when I don't actually need them (which is most of the time). But for some reason, there are some features that seemingly require tagged types for no reason - custom indexing and iterators. 

My specific case is a large buffer which I want to be able to pass around a sub-range of (i.e. I have concrete types). I could just use explicit functions to do what I want, but I'd really rather have the more convenient syntax of providing custom indexing and iterators.

I just can't understand why these features require tagged types (especially because I can implement custom indexing and iterators in C++ without involving any kind of abstract classes or virtual functions). I assume though that the requirement is there for some reason, so I'm curious if anyone knows what that reason might be.

I really want to like Ada, and there's some really cool things it does like allowing you to very exactly specify how types should be laid out in memory that are very useful for low level programming, but then I run into these features requiring tagged types when I very much don't need them, which just drives me crazy.


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

* Re: Ada Annoyances
  2017-06-21  1:12 Ada Annoyances pythoner6
@ 2017-06-21 10:13 ` Lucretia
  2017-06-23 15:27   ` raph.amiard
  2017-06-21 11:58 ` Ada Annoyances joakimds
  1 sibling, 1 reply; 116+ messages in thread
From: Lucretia @ 2017-06-21 10:13 UTC (permalink / raw)


On Wednesday, 21 June 2017 02:12:51 UTC+1, pyth...@gmail.com  wrote:
> I've recently been trying to learn some Ada, however, I've encountered a few annoyances. I tend to perhaps be a bit too concerned about performance, so I try to stay away from things like tagged types when I don't actually need them (which is most of the time). But for some reason, there are some features that seemingly require tagged types for no reason - custom indexing and iterators. 
> 

Your thinking is pretty stupid tbh. I've come across this numerous times. "Oh, don't use a virtual, it's slow!" It's "slower" because it needs another load, big fucking deal, CPU's are fast enough now.

In Ada, you can mostly do static calls, whereas with C++ you can't, so avoiding tagged types is really stupid because it's going to hinder what you can do.

Ada isn't as braindead as C++ so stop thinking in C++ ways when writing Ada, it's not the right thing to do.

I'm surprised you're even trying Ada given that most, if not all of it's types will have dope vectors, but you're not even checking to see what the compiler is generating, so you've no clue as to whether it's using a fast path or not.

> My specific case is a large buffer which I want to be able to pass around a sub-range of (i.e. I have concrete types). I could just use explicit functions to do what I want, but I'd really rather have the more convenient syntax of providing custom indexing and iterators.

The iterators have a specific interface that the designers wanted to enforce so it's easier to grasp. TBH, the current iterator stuff isn't that easy to implement.

> I just can't understand why these features require tagged types (especially because I can implement custom indexing and iterators in C++ without involving any kind of abstract classes or virtual functions). I assume though that the requirement is there for some reason, so I'm curious if anyone knows what that reason might be.

You mean, C++'s template "system?"

> I really want to like Ada, and there's some really cool things it does like allowing you to very exactly specify how types should be laid out in memory that are very useful for low level programming, but then I run into these features requiring tagged types when I very much don't need them, which just drives me crazy.

Stop thinking in C++ then and just use the language the way it's supposed to be used. The profile and see where your bottlenecks are, I'm betting they're nowhere where you think.

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

* Re: Ada Annoyances
  2017-06-21  1:12 Ada Annoyances pythoner6
  2017-06-21 10:13 ` Lucretia
@ 2017-06-21 11:58 ` joakimds
  2017-06-21 12:29   ` Pascal Obry
  1 sibling, 1 reply; 116+ messages in thread
From: joakimds @ 2017-06-21 11:58 UTC (permalink / raw)


Hi! I am also concerned about performance. I really love the object-prefix notation but "it's only available for tagged types" (i.e. type Car_Type is tagged private;) and thus I also avoid tagged types except for when applicable (i.e. large types i.e. containers). I make heavy use of "use all type" instead. Needless to say I am also curious about using tagged types in custom indexers and iterators.

I don't know of a nice solution to your specific case in the Ada language. If you use aliased parameters and implicit dereference you will expose the whole of your buffer not part of it. The cleanest way forward is for you to use a generic function that will expose part of your array. To see an example of this see "procedure Act_On_Immutable_Text (..) " in the Aida.Bounded_String package:
https://github.com/joakim-strandberg/aida_2012/blob/master/config/aida_src/aida-bounded_string.ads

Another thought on performance is avoiding controlled types where possible.

Best regards,
Joakim


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

* Re: Ada Annoyances
  2017-06-21 11:58 ` Ada Annoyances joakimds
@ 2017-06-21 12:29   ` Pascal Obry
  2017-06-21 14:52     ` pythoner6
  2017-06-26 11:01     ` Vincent
  0 siblings, 2 replies; 116+ messages in thread
From: Pascal Obry @ 2017-06-21 12:29 UTC (permalink / raw)


Le mercredi 21 juin 2017 à 04:58 -0700, joakimds@kth.se a écrit :
> Hi! I am also concerned about performance.

I'm always like most of programmers. But that's why I do not try to
optimize anything early. A good design, architecture will always
propose a fast application. And it is a waste of programmer time to
optimize a routine that count for 0.1% of the total time in the final
application.

So do check for performance when the application actually run.

I've come across contrived code just for the sake of trying to gain
some CPU cycle. There was nothing gained and for sure it costs lot of
review time and recoding.

My 2 cents,

-- 
  Pascal Obry /  Magny Les Hameaux (78)

  The best way to travel is by means of imagination

  http://www.obry.net

  gpg --keyserver keys.gnupg.net --recv-key F949BD3B


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

* Re: Ada Annoyances
  2017-06-21 12:29   ` Pascal Obry
@ 2017-06-21 14:52     ` pythoner6
  2017-06-21 16:11       ` J-P. Rosen
                         ` (2 more replies)
  2017-06-26 11:01     ` Vincent
  1 sibling, 3 replies; 116+ messages in thread
From: pythoner6 @ 2017-06-21 14:52 UTC (permalink / raw)


I definitely agree that performance is best measured, not guessed about. However, the way I see it, this restriction is (at least for my use case where I know I don't need tagged types) at best making the compiler work much harder to see that it can devirtualize the function calls and at worst making my code run slower with no benefit - other than providing a slightly nicer syntax.

I assume there was some rationale behind the decision, though, so I'd be interested if anyone has any insight on that.

As a side note, I did do a test at one point and if I remember right, the compiler didn't devirtualize the custom indexing even for my simple test. I'll have to see if I can recreate the test and try with a newer compiler though.

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

* Re: Ada Annoyances
  2017-06-21 14:52     ` pythoner6
@ 2017-06-21 16:11       ` J-P. Rosen
  2017-06-21 16:12       ` Dmitry A. Kazakov
  2017-06-21 20:40       ` G.B.
  2 siblings, 0 replies; 116+ messages in thread
From: J-P. Rosen @ 2017-06-21 16:11 UTC (permalink / raw)


Le 21/06/2017 à 16:52, pythoner6@gmail.com a écrit :
> I assume there was some rationale behind the decision, though, so I'd
> be interested if anyone has any insight on that.
Mainly to provide prefixed notation.

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

* Re: Ada Annoyances
  2017-06-21 14:52     ` pythoner6
  2017-06-21 16:11       ` J-P. Rosen
@ 2017-06-21 16:12       ` Dmitry A. Kazakov
  2017-06-21 22:45         ` pythoner6
  2017-06-23 15:23         ` raph.amiard
  2017-06-21 20:40       ` G.B.
  2 siblings, 2 replies; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-06-21 16:12 UTC (permalink / raw)


On 2017-06-21 16:52, pythoner6@gmail.com wrote:
> I definitely agree that performance is best measured, not guessed
> about. However, the way I see it, this restriction is (at least for my
> use case where I know I don't need tagged types) at best making the
> compiler work much harder to see that it can devirtualize the function
> calls and at worst making my code run slower with no benefit - other
> than providing a slightly nicer syntax.

In Ada there is no penalty of calling a "method" vs. a "free" function. 
None, whatsoever. This per language type system design and different 
from C++.

I don't consider here the overhead of using any helper types/objects 
and/or class-wide objects. That has nothing to do with the type under 
consideration being tagged or not.

The penalty of a tagged type is only this:

1. Space to keep the type tag
2. By-reference passing only, even if the object is small.

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

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

* Re: Ada Annoyances
  2017-06-21 14:52     ` pythoner6
  2017-06-21 16:11       ` J-P. Rosen
  2017-06-21 16:12       ` Dmitry A. Kazakov
@ 2017-06-21 20:40       ` G.B.
  2017-06-21 22:25         ` pythoner6
  2 siblings, 1 reply; 116+ messages in thread
From: G.B. @ 2017-06-21 20:40 UTC (permalink / raw)


On 21.06.17 16:52, pythoner6@gmail.com wrote:
> making the compiler work much harder to see that it can devirtualize the function calls

Not in Ada, like Dmitry explains; in fact, "devirtualization"
isn't really applicable to a language that requires explicit
notation for dynamic dispatch in the first place. What did
your example do?

The earlier proposals for Ada's STL had, e.g., (then) more efficient,
but less safe Cursor types whose objects would not know the structure
they were running along. Today, faster container operations are
available via checking control semantics, part of the language,
so if you are sure about what your algorithms are doing...

Another thing to consider is that, like in Python, a plain old
for loop might be a simple and fast solution if one can overcome
"functionist" fear for a moment, or focusing on both sides
of iteration control. (Demonstrably parallel loops are in the
making BTW.) A low level data structure like a plain old
built-in array can be at the heart of a (e.g. generic) subprogram
that iterates calling another subprogram (e.g. its generic actual)
with each of the array's components.

More involved recursive compile time resolution is unlikely to be
possible in Ada if its generics remain non-recursive.


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

* Re: Ada Annoyances
  2017-06-21 20:40       ` G.B.
@ 2017-06-21 22:25         ` pythoner6
  0 siblings, 0 replies; 116+ messages in thread
From: pythoner6 @ 2017-06-21 22:25 UTC (permalink / raw)


On Wednesday, June 21, 2017 at 4:40:21 PM UTC-4, G.B. wrote:
> Not in Ada, like Dmitry explains; in fact, "devirtualization"
> isn't really applicable to a language that requires explicit
> notation for dynamic dispatch in the first place. What did
> your example do?

After reading through the thread and some more documentation on Ada, I realized that I had a misconception about exactly when dynamic dispatch happened: I hadn't quite grasped the difference between T and T'Class. I don't know where the test I wrote went, but my guess is that I found an example of doing user defined indexing that used T'Class and copied that. I just tried something quickly using an indexing function that takes a T instead of T'Class, and it does appear to not be making a virtual call.

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

* Re: Ada Annoyances
  2017-06-21 16:12       ` Dmitry A. Kazakov
@ 2017-06-21 22:45         ` pythoner6
  2017-06-22  7:29           ` Dmitry A. Kazakov
  2017-06-23 15:23         ` raph.amiard
  1 sibling, 1 reply; 116+ messages in thread
From: pythoner6 @ 2017-06-21 22:45 UTC (permalink / raw)


On Wednesday, June 21, 2017 at 12:12:53 PM UTC-4, Dmitry A. Kazakov wrote:
> In Ada there is no penalty of calling a "method" vs. a "free" function. 
> None, whatsoever. This per language type system design and different 
> from C++.

I would say the same is true of C++ -- a method in C++ just has an implicit parameter that would be explicit in Ada (the only potential difference I can think of is that the implicit parameter is always by reference in C++ where Ada may choose to pass it by value, unless as you note you are dealing with a tagged type).

> I don't consider here the overhead of using any helper types/objects 
> and/or class-wide objects. That has nothing to do with the type under 
> consideration being tagged or not.
> 
> The penalty of a tagged type is only this:
> 
> 1. Space to keep the type tag
> 2. By-reference passing only, even if the object is small.
> 
> -- 
> Regards,
> Dmitry A. Kazakov
> http://www.dmitry-kazakov.de

Thanks for the clarifications - as mentioned in my previous post, I think the main misconception I had was about when dynamic dispatch happens: I rather naively assumed that dynamic dispatch happened whenever tagged types were involved. After reading this it sounds like using tagged types in Ada is quite similar to dealing with classes in C++ (i.e. in C++, methods have the implicit this parameter which is also only ever passed by reference). Now that I better understand how tagged types work, I think I don't really mind the restriction.

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

* Re: Ada Annoyances
  2017-06-21 22:45         ` pythoner6
@ 2017-06-22  7:29           ` Dmitry A. Kazakov
  2017-06-22 10:29             ` pythoner6
  0 siblings, 1 reply; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-06-22  7:29 UTC (permalink / raw)


On 22/06/2017 00:45, pythoner6@gmail.com wrote:
> On Wednesday, June 21, 2017 at 12:12:53 PM UTC-4, Dmitry A. Kazakov wrote:
>> In Ada there is no penalty of calling a "method" vs. a "free" function.
>> None, whatsoever. This per language type system design and different
>> from C++.
> 
> I would say the same is true of C++

In C++ calls to a method go through the virtual table. In Ada they never 
do because Ada is strongly typed. This gives you performance and type 
safety (LSP stuff etc) upon inheritance. Re-dispatch is evil from SW 
design POV.

> Thanks for the clarifications - as mentioned in my previous post, I
> think the main misconception I had was about when dynamic dispatch
> happens: I rather naively assumed that dynamic dispatch happened
> whenever tagged types were involved.
It is controlled by the type, because see above, Ada is properly typed. 
The dispatch never happens on a tagged type T. It always do on a 
class-wide type T'Class, which is not tagged. T /= T'Class.

> After reading this it sounds like using tagged types in Ada is quite
> similar to dealing with classes in C++ (i.e. in C++, methods have the
> implicit this parameter which is also only ever passed by reference).

Not so much similar, C++ type system is broken in that respect. C++ does 
not distinguish T and T'Class. Semantically C++ class type is sometimes 
one and sometimes another. E.g. in a constructor or destructor it acts 
as T. Elsewhere it does as T'Class.

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

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

* Re: Ada Annoyances
  2017-06-22  7:29           ` Dmitry A. Kazakov
@ 2017-06-22 10:29             ` pythoner6
  2017-06-22 11:04               ` Egil H H
  2017-06-22 13:30               ` Dmitry A. Kazakov
  0 siblings, 2 replies; 116+ messages in thread
From: pythoner6 @ 2017-06-22 10:29 UTC (permalink / raw)


On Thursday, June 22, 2017 at 3:29:23 AM UTC-4, Dmitry A. Kazakov wrote: 
> In C++ calls to a method go through the virtual table. In Ada they never 
> do because Ada is strongly typed. This gives you performance and type 
> safety (LSP stuff etc) upon inheritance. Re-dispatch is evil from SW 
> design POV.

C++ is also strongly typed (though one might consider Ada a bit more strongly typed), and the vtable is used only if a method is marked virtual.

What do you mean by "re-dispatch" here? How is it different from the dynamic dispatch that happens in Ada with class-wide types?

> It is controlled by the type, because see above, Ada is properly typed. 
> The dispatch never happens on a tagged type T. It always do on a 
> class-wide type T'Class, which is not tagged. T /= T'Class.

Yes, this is exactly this (rather crucial) distinction I didn't really understand. Part of it I think was that the word class didn't have the right associations in my mind, coming from C++ where a class is just one kind of type. In Ada it seems that class refers to a type and it's descendants, e.g. a class of types.

> Not so much similar, C++ type system is broken in that respect. C++ does 
> not distinguish T and T'Class. Semantically C++ class type is sometimes 
> one and sometimes another. E.g. in a constructor or destructor it acts 
> as T. Elsewhere it does as T'Class.

In C++ it is potentially more confusing, as something of type T is always exactly of type T (because it usually lives on the stack and therefore must have a statically known size), but a reference or pointer to T might be of a derived type. Whether or not a method is dynamically dispatched using the vtable is determined by whether or not the method is marked as virtual.

While I'm not so sure that I'd go so far to say that the C++ way is broken, now that I understand how Ada works a bit better, I would probably agree that Ada's solution is cleaner.


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

* Re: Ada Annoyances
  2017-06-22 10:29             ` pythoner6
@ 2017-06-22 11:04               ` Egil H H
  2017-06-22 13:30               ` Dmitry A. Kazakov
  1 sibling, 0 replies; 116+ messages in thread
From: Egil H H @ 2017-06-22 11:04 UTC (permalink / raw)


On Thursday, June 22, 2017 at 12:29:47 PM UTC+2, pyth...@gmail.com wrote:
> 
> In C++ it is potentially more confusing, as something of type T is always exactly of type T (because it usually lives on the stack and therefore must have a statically known size), but a reference or pointer to T might be of a derived type. Whether or not a method is dynamically dispatched using the vtable is determined by whether or not the method is marked as virtual.
> 
> While I'm not so sure that I'd go so far to say that the C++ way is broken, now that I understand how Ada works a bit better, I would probably agree that Ada's solution is cleaner.

You may find this document useful:
http://www.adacore.com/knowledge/technical-papers/ada-for-the-c-or-java-developer/

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

* Re: Ada Annoyances
  2017-06-22 10:29             ` pythoner6
  2017-06-22 11:04               ` Egil H H
@ 2017-06-22 13:30               ` Dmitry A. Kazakov
  2017-06-22 19:22                 ` Niklas Holsti
  2017-06-23  1:00                 ` pythoner6
  1 sibling, 2 replies; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-06-22 13:30 UTC (permalink / raw)


On 22/06/2017 12:29, pythoner6@gmail.com wrote:

> What do you mean by "re-dispatch" here? How is it different from the
> dynamic dispatch that happens in Ada with class-wide types?

Re-dispatch is dynamic dispatch when you go through the same virtual 
table twice. Since you are already there = you have determined the 
actual specific type, it does not make sense (and dangerous) to do this 
again.

(I know that there are software patterns based on re-dispatch, they all 
are wrong.)

>> It is controlled by the type, because see above, Ada is properly typed.
>> The dispatch never happens on a tagged type T. It always do on a
>> class-wide type T'Class, which is not tagged. T /= T'Class.
> 
> Yes, this is exactly this (rather crucial) distinction I didn't
> really  understand. Part of it I think was that the word class didn't have the
> right associations in my mind, coming from C++ where a class is just one
> kind of type.

A class rooted in the type T (T'Class) is a new type with values 
corresponding to the values of T and the values of all types derived from T.

The idea of class is to have an object that may hold any value of T or 
of any of its descendants.

Trivially as a type T'Class cannot be T. It has a different set values.

> In Ada it seems that class refers to a type and it's
> descendants, e.g. a class of types.

It is important to see the difference. There is a class T as a set of 
types derived from T. That is not a type, because it is a set of types.

Then there is a proper type with values corresponding to the closure of 
the values of the types from that set. That is the class type (a 
class-wide type in Ada terms).

   class T is a set
   T'Class is a type (to mimic the closure of class T)

A value of T'Class has in Ada as in C++ the same representation as the 
value of some derived type S from the set class T. This allows 
conversion forth and back between T'Class and S. In Ada terms this is 
called "view conversion". In C++ it is simply there.

Confusion between T'Class and T prevents from having classes of scalar 
types with class-wide objects supporting dynamic dispatch. Ada does not 
have this either, but there is nothing that would prevent it to have 
them. In that case Integer'Class object would have different 
representation from Integer because we don't want to keep tag or vptr 
inside Integer. We would put that into Integer'Class and use proper type 
conversion instead of view conversion.

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

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

* Re: Ada Annoyances
  2017-06-22 13:30               ` Dmitry A. Kazakov
@ 2017-06-22 19:22                 ` Niklas Holsti
  2017-06-22 21:52                   ` Dmitry A. Kazakov
  2017-06-23  1:00                 ` pythoner6
  1 sibling, 1 reply; 116+ messages in thread
From: Niklas Holsti @ 2017-06-22 19:22 UTC (permalink / raw)


On 17-06-22 16:30 , Dmitry A. Kazakov wrote:
> On 22/06/2017 12:29, pythoner6@gmail.com wrote:
>
>> What do you mean by "re-dispatch" here? How is it different from the
>> dynamic dispatch that happens in Ada with class-wide types?
>
> Re-dispatch is dynamic dispatch when you go through the same virtual
> table twice.

I think that is inaccurate, unless you have a different definition of 
"re-dispatch" from what I remember of discussions re this topic.

Consider:

    type Parent is tagged record .... end record;

    procedure Foo (P : Parent);
    procedure Bar (P : Parent);

    type Child is new Parent with record ... end record;

    -- Child inherits Foo from Parent.

    overriding procedure Bar (C : Child);

followed by

    C : Child;

    Foo (C);

That call is not dispatching, so it does not go through the "virtual 
table". It calls the inherited Foo for Child.

Now suppose Foo (P : Parent) does a (re-) dispatching call to Bar, which 
in this example calls the overriding Bar (C : Child):

    procedure Foo (P : Parent)
    is
    begin
       Bar (Parent'Class (P));
    end Foo;

I believe this call of Bar is considered "re-dispatching", because there 
is a conversion from Parent to Parent'Class (effectively, Child). But 
there is only one use of the "virtual table".

> Since you are already there = you have determined the
> actual specific type, it does not make sense (and dangerous) to do this
> again.
>
> (I know that there are software patterns based on re-dispatch, they all
> are wrong.)

As you have often said. I still disagree. Just to let the OP know that 
opinions differ on this topic.

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

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

* Re: Ada Annoyances
  2017-06-22 19:22                 ` Niklas Holsti
@ 2017-06-22 21:52                   ` Dmitry A. Kazakov
  2017-06-23  9:33                     ` AdaMagica
  0 siblings, 1 reply; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-06-22 21:52 UTC (permalink / raw)


On 2017-06-22 21:22, Niklas Holsti wrote:
> On 17-06-22 16:30 , Dmitry A. Kazakov wrote:
>> On 22/06/2017 12:29, pythoner6@gmail.com wrote:
>>
>>> What do you mean by "re-dispatch" here? How is it different from the
>>> dynamic dispatch that happens in Ada with class-wide types?
>>
>> Re-dispatch is dynamic dispatch when you go through the same virtual
>> table twice.
> 
> I think that is inaccurate, unless you have a different definition of 
> "re-dispatch" from what I remember of discussions re this topic.
> 
> Consider:
> 
>     type Parent is tagged record .... end record;
> 
>     procedure Foo (P : Parent);
>     procedure Bar (P : Parent);
> 
>     type Child is new Parent with record ... end record;
> 
>     -- Child inherits Foo from Parent.
> 
>     overriding procedure Bar (C : Child);
> 
> followed by
> 
>     C : Child;
> 
>     Foo (C);
> 
> That call is not dispatching, so it does not go through the "virtual 
> table". It calls the inherited Foo for Child.
> 
> Now suppose Foo (P : Parent) does a (re-) dispatching call to Bar, which 
> in this example calls the overriding Bar (C : Child):
> 
>     procedure Foo (P : Parent)
>     is
>     begin
>        Bar (Parent'Class (P));
>     end Foo;
> 
> I believe this call of Bar is considered "re-dispatching", because there 
> is a conversion from Parent to Parent'Class (effectively, Child). But 
> there is only one use of the "virtual table".

It is not good either for similar reasons of type violation. But I would 
not call it re-dispatch.

There is many ways to achieve the same [wrong] effect. E.g. without any 
dispatch:

    procedure Foo (P : Parent) is
    begin
       Bar (Some_Descendant_Of_Parent (P));
    end Foo;

> As you have often said. I still disagree. Just to let the OP know
> that opinions differ on this topic.
Yes, to elaborate a bit on the issue.

The problem is that the contract of Foo tells that P is of the type 
Parent and of nothing else. So any operations applied to P must of the 
same type.

If there must be other types the contract must say so. E.g. Parent'Class 
or some narrower class. Unfortunately there is no way to express 
anything in between Parent and Parent'Class. But that is a different story.

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

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

* Re: Ada Annoyances
  2017-06-22 13:30               ` Dmitry A. Kazakov
  2017-06-22 19:22                 ` Niklas Holsti
@ 2017-06-23  1:00                 ` pythoner6
  1 sibling, 0 replies; 116+ messages in thread
From: pythoner6 @ 2017-06-23  1:00 UTC (permalink / raw)


On Thursday, June 22, 2017 at 9:30:15 AM UTC-4, Dmitry A. Kazakov wrote:
> Re-dispatch is dynamic dispatch when you go through the same virtual 
> table twice. Since you are already there = you have determined the 
> actual specific type, it does not make sense (and dangerous) to do this 
> again.

I see. I think it's actually really cool that Ada allows this flexibility in choosing when dynamic dispatch happens.

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

* Re: Ada Annoyances
  2017-06-22 21:52                   ` Dmitry A. Kazakov
@ 2017-06-23  9:33                     ` AdaMagica
  2017-06-23 10:25                       ` Simon Wright
  0 siblings, 1 reply; 116+ messages in thread
From: AdaMagica @ 2017-06-23  9:33 UTC (permalink / raw)


Am Donnerstag, 22. Juni 2017 23:52:42 UTC+2 schrieb Dmitry A. Kazakov:
> There is many ways to achieve the same [wrong] effect. E.g. without any 
> dispatch:
>
>     procedure Foo (P : Parent) is
>     begin
>        Bar (Some_Descendant_Of_Parent (P));
>     end Foo;
>
This code seems illegal to me, at least for tagged types:
1. If Foo is a primitive operation, the body cannot know the descendants.
2. The type conversion is illegal - here, an extension aggregate is needed.

Niklas' example is a completely different thing.

  type Parent is tagged record .... end record;
  procedure Foo (P : Parent);  -- 1
  procedure Bar (P : Parent);  -- 2

  type Child is new Parent with record ... end record;
  -- Child inherits Foo from Parent.     -- 1'
  overriding procedure Bar (C : Child);  -- 3

  C: Child;

  Foo (C);  -- calls 1', i.e Foo (Parent (C));

  procedure Foo (P: Parent) is
  begin
    Bar (P);                  -- Bar 2
    Bar (Parent'Class (P));   -- Bar 3
  end Foo;

Whether this behaviour is wrong or not, is a different story. There are some contrived cases which only work correctly with redispatch.

I do aggree that the declaration of Foo at (1) cannot show whether the body has a redispatch or not - and that's bad. It's the chore of the writer of this code that it works correctly. The user (caller) simply has to believe the writer.


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

* Re: Ada Annoyances
  2017-06-23  9:33                     ` AdaMagica
@ 2017-06-23 10:25                       ` Simon Wright
  0 siblings, 0 replies; 116+ messages in thread
From: Simon Wright @ 2017-06-23 10:25 UTC (permalink / raw)


AdaMagica <christ-usch.grein@t-online.de> writes:

> Am Donnerstag, 22. Juni 2017 23:52:42 UTC+2 schrieb Dmitry A. Kazakov:
>> There is many ways to achieve the same [wrong] effect. E.g. without any 
>> dispatch:
>>
>>     procedure Foo (P : Parent) is
>>     begin
>>        Bar (Some_Descendant_Of_Parent (P));
>>     end Foo;
>>
> This code seems illegal to me, at least for tagged types:
> 1. If Foo is a primitive operation, the body cannot know the descendants.
> 2. The type conversion is illegal - here, an extension aggregate is needed.

Illegal as-is because "downward conversion of tagged objects not
allowed".

   procedure Foo (P : Parent) is
   begin
      Child (Parent'Class (P)).Bar;
   end Foo;

will compile (and, presumably, work - but, ugh, unless you are sure
there can't be a constraint error at the Child conversion, and even then
...)

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

* Re: Ada Annoyances
  2017-06-21 16:12       ` Dmitry A. Kazakov
  2017-06-21 22:45         ` pythoner6
@ 2017-06-23 15:23         ` raph.amiard
  2017-06-23 16:10           ` Dmitry A. Kazakov
                             ` (2 more replies)
  1 sibling, 3 replies; 116+ messages in thread
From: raph.amiard @ 2017-06-23 15:23 UTC (permalink / raw)


Le mercredi 21 juin 2017 18:12:53 UTC+2, Dmitry A. Kazakov a écrit :
> On 2017-06-21 16:52, pytho...@gmail.com wrote:
> > I definitely agree that performance is best measured, not guessed
> > about. However, the way I see it, this restriction is (at least for my
> > use case where I know I don't need tagged types) at best making the
> > compiler work much harder to see that it can devirtualize the function
> > calls and at worst making my code run slower with no benefit - other
> > than providing a slightly nicer syntax.
> 
> In Ada there is no penalty of calling a "method" vs. a "free" function. 
> None, whatsoever. This per language type system design and different 
> from C++.
> 
> I don't consider here the overhead of using any helper types/objects 
> and/or class-wide objects. That has nothing to do with the type under 
> consideration being tagged or not.
> 
> The penalty of a tagged type is only this:
> 
> 1. Space to keep the type tag
> 2. By-reference passing only, even if the object is small.
> 
> -- 
> Regards,
> Dmitry A. Kazakov
> http://www.dmitry-kazakov.de

Well that's really a strange way to put it: 

1. In Ada you dispatch via going through the class wide type. But if you do, then your call *will* go through a virtual table.

2. In C++ only virtual methods dispatch and go through the virtual table. The penalty on the type is exactly the same (by-ref passing and tag)

3. The ONLY thing that differs is the granularity of how you choose to dispatch or not. In C++, this choice is made by the method's implementer. In Ada, it is made at the call-site by every caller.

It could very well be argued that the C++ choice is a lot better. Most of the time, you never want to call a possibly dispatching method in without dispatching. Ada gives you a little bit more flexibility, at the cost of being much more error prone, because it's easy to make a non dispatching call instead of a dispatching one. Not a good point for Ada !

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

* Re: Ada Annoyances
  2017-06-21 10:13 ` Lucretia
@ 2017-06-23 15:27   ` raph.amiard
  2017-06-23 17:49     ` Randy Brukardt
  0 siblings, 1 reply; 116+ messages in thread
From: raph.amiard @ 2017-06-23 15:27 UTC (permalink / raw)


Le mercredi 21 juin 2017 12:13:14 UTC+2, Lucretia a écrit :
> On Wednesday, 21 June 2017 02:12:51 UTC+1, pyth...@gmail.com  wrote:
> > I've recently been trying to learn some Ada, however, I've encountered a few annoyances. I tend to perhaps be a bit too concerned about performance, so I try to stay away from things like tagged types when I don't actually need them (which is most of the time). But for some reason, there are some features that seemingly require tagged types for no reason - custom indexing and iterators. 
> > 
> 
> Your thinking is pretty stupid tbh. I've come across this numerous times. "Oh, don't use a virtual, it's slow!" It's "slower" because it needs another load, big fucking deal, CPU's are fast enough now.

This line of thinking is terrible, and you're being insulting to somebody asking questions about the language. Way to go !

Ada forcing tagged types on you to use certain features *is* a problem, if only because certain Ada users are forbidden to use tagged types altogether and thus are prevented to use a lot of useful features.

With that said, I agree that if you can use tagged types, and your only concern is an hypothetical performance problem, then go ahead and use tagged types. As explained in another mail you can even choose by call-site if you're going to dispatch or not.

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

* Re: Ada Annoyances
  2017-06-23 15:23         ` raph.amiard
@ 2017-06-23 16:10           ` Dmitry A. Kazakov
  2017-06-23 17:41           ` Randy Brukardt
  2017-06-23 18:56           ` Maciej Sobczak
  2 siblings, 0 replies; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-06-23 16:10 UTC (permalink / raw)


On 2017-06-23 17:23, raph.amiard@gmail.com wrote:

> Well that's really a strange way to put it:
> 
> 1. In Ada you dispatch via going through the class wide type But if 
> you do, then your call *will* go through a virtual table.
If that is a primitive operation, then it does, if it is a class-wide 
operation it does not.

> 2. In C++ only virtual methods dispatch and go through the virtual
> table. The penalty on the type is exactly the same (by-ref passing and tag)

Same in Ada. Non-primitive operations do not dispatch. Semantically 
there is no difference.

There are operations defined on the whole class ("virtual operations") 
and operations defined on a specific type. The operations defined on the 
whole class are further subdivided into:

1. Dispatching operations implemented in a way that each specific 
instance of the class has a separate operation body. Dispatching is an 
act of selecting that body according to the actual specific type the 
class-wide object holds.

2. Class-wide operations that have one body for all instances of the class.

> 3. The ONLY thing that differs is the granularity of how you choose
> to dispatch or not. In C++, this choice is made by the method's
> implementer. In Ada, it is made at the call-site by every caller.

It is not granularity it is untyped in C++ vs. typed in Ada.

As I said it is quite possible in Ada to declare a type-specific 
operation for a tagged type. That is, an operation defined on this 
concrete type only and undefined on other instances from the class. 
Usually it is used in the package bodies:

package P is
    type T is tagged ...
end P;

package body P is
    procedure Internal (X : in out T) is -- This does not dispatch
    begin
       ...
    end Internal;
end P;

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

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

* Re: Ada Annoyances
  2017-06-23 15:23         ` raph.amiard
  2017-06-23 16:10           ` Dmitry A. Kazakov
@ 2017-06-23 17:41           ` Randy Brukardt
  2017-06-23 18:56           ` Maciej Sobczak
  2 siblings, 0 replies; 116+ messages in thread
From: Randy Brukardt @ 2017-06-23 17:41 UTC (permalink / raw)


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

<raph.amiard@gmail.com> wrote in message 
news:8d3aff06-82df-485f-89e5-a50c326aab05@googlegroups.com...
Le mercredi 21 juin 2017 18:12:53 UTC+2, Dmitry A. Kazakov a écrit :
>...
>It could very well be argued that the C++ choice is a lot better.

Well, in the sense that you can argue anything. Some people argue the earth 
is flat, too.

>Most of the time, you never want to call a possibly dispatching method in 
>without dispatching.

This seems to be a viewpoint that comes from taking OOP religious dogma as 
some sort of fact. A much more sensible statement is that "most of the time, 
you want to call the correct subprogram body for your object". A sensible 
programmer will never care how that is determined or which mechanism is used 
to implement that. And the fact that a statically bound call is faster than 
a dynamically bound call suggests the former ought to be used.

>Ada gives you a little bit more flexibility, at the cost of being much more 
>error prone,
>because it's easy to make a non dispatching call instead of a dispatching 
>one. Not
>a good point for Ada !

Yeah, it's terrible that Ada avoids errors and ignores dogma.

A more sensible take on this is that it is insane to put the burden of what 
can be called with a dispatching call onto a library designer. The vast 
majority of routines in Claw have no (obvious) good reason to be called as 
dispatching calls. But I don't want to claim to know how every user of Claw 
might want to use it, so if Ada had followed the C++ rule, every routine 
would have had to be marked virtual, effectively making everything more 
expensive. Library designers are not omnipitent!

                              Randy.


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

* Re: Ada Annoyances
  2017-06-23 15:27   ` raph.amiard
@ 2017-06-23 17:49     ` Randy Brukardt
  2017-06-23 19:21       ` Niklas Holsti
                         ` (2 more replies)
  0 siblings, 3 replies; 116+ messages in thread
From: Randy Brukardt @ 2017-06-23 17:49 UTC (permalink / raw)


<raph.amiard@gmail.com> wrote in message 
news:be1619b4-2220-4287-8e67-1af32377d3f7@googlegroups.com...
...
>Ada forcing tagged types on you to use certain features *is* a problem, if 
>only
>because certain Ada users are forbidden to use tagged types altogether and 
>thus
>are prevented to use a lot of useful features.

Stupid language usage rules are not the problem of the language design, 
they're a management problem. I can understand banning T'Class (thus banning 
dynamic dispatching) and banning controlled types (thus banning hidden calls 
that can be harder to analyze), but not banning tagged types themselves. 
Indeed, (almost) all new types should be tagged - as Tucker said often 
during the Ada 9x development, "Tagged types work right"; for the most part, 
regular record types don't "work right" for various things and that can't be 
fixed because compatibility concerns. (Although Ada 2012 did bite the bullet 
about equality; that may be a significant reason why there is only one Ada 
2012 compiler to date.)

                                               Randy.



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

* Re: Ada Annoyances
  2017-06-23 15:23         ` raph.amiard
  2017-06-23 16:10           ` Dmitry A. Kazakov
  2017-06-23 17:41           ` Randy Brukardt
@ 2017-06-23 18:56           ` Maciej Sobczak
  2017-06-23 22:18             ` pythoner6
  2017-12-17 16:24             ` Mehdi Saada
  2 siblings, 2 replies; 116+ messages in thread
From: Maciej Sobczak @ 2017-06-23 18:56 UTC (permalink / raw)


> 3. The ONLY thing that differs is the granularity of how you choose to dispatch or not. In C++, this choice is made by the method's implementer. In Ada, it is made at the call-site by every caller.

In C++ it is always possible to do:

obj.SomeBaseClass::function();

where obj is some reference, or:

ptr->SomeBaseClass::function();

This means that it *is* possible to select T at the call site.

The implementer selects whether the function is virtual (dispatching) or not, but this is not much different from what Ada programmer can do by using T or T'Class in operation's signature.

In other words, you can implement the same object-oriented design in both languages. The syntax will differ, but the "philosophical" differences are greatly exaggerated here.

There is one place where Ada is broken in this regard - Controlled types. These should not be tagged. C++ got it right here.
Interestingly, C++ got it right also by forcing the object type in constructors and destructors - that is, you never see the object in a view that would not be compatible with the lifetime of its parts. Ada does not do this and it is a hole in the type system that can lead to serious errors.

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

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

* Re: Ada Annoyances
  2017-06-23 17:49     ` Randy Brukardt
@ 2017-06-23 19:21       ` Niklas Holsti
  2017-06-24  4:02         ` Shark8
                           ` (3 more replies)
  2017-06-23 19:22       ` Niklas Holsti
  2017-06-30 15:02       ` Norman Worth
  2 siblings, 4 replies; 116+ messages in thread
From: Niklas Holsti @ 2017-06-23 19:21 UTC (permalink / raw)


On 17-06-23 20:49 , Randy Brukardt wrote:
> <raph.amiard@gmail.com> wrote in message
> news:be1619b4-2220-4287-8e67-1af32377d3f7@googlegroups.com...
> ...
>> Ada forcing tagged types on you to use certain features *is* a
>> problem, if only because certain Ada users are forbidden to
>> use tagged types altogether and thus are prevented to use a
>> lot of useful features.
>
> Stupid language usage rules are not the problem of the language design,
> they're a management problem.

Sometimes usage rules are imposed by environment constraints, in 
particular limited resources in smallish embedded systems, combined with 
reliability requirements which mean that running out of resources at run 
time must be avoided.

> I can understand banning T'Class (thus banning
> dynamic dispatching) and banning controlled types (thus banning hidden calls
> that can be harder to analyze), but not banning tagged types themselves.

I have so far avoided using tagged types in my embedded applications 
because they indeed hamper the discovery of resource usage (execution 
time and stack space) by static analysis, as you said.

There are two reasons why tagged types hamper such analysis:

a) dispatching calls (as you said), where the actual callee is 
determined by run-time values (tags) which are hard to predict by static 
analysis

b) the non-static size of class-wide objects (of type T'Class), which 
means that the compiler and/or the programmer must use dynamic 
allocation (usually heap or secondary stack) for such objects.

Point (a) can be worked around: static analysis tools usually let the 
analyst specify the possible set of callees for a "dynamic call" (of 
which dispatching calls are one kind) and the analysis can then 
encompass all those callees. (Alternatively, the analysis tool can 
extract the class hierarchy from the debugging information, and itself 
discover the possible callees.)

Point (b) is more difficult and I know of no work-around that can be 
applied at analysis time.

For some time, I have had in mind a possible Ada extension to solve 
point (b): an attribute/aspect that would let the programmer set a 
static upper bound on the size of any object in T'Class. If we call this 
aspect Maximum_Size (or perhaps Maximum_Size'Class), the programmer 
could use it like this:

    type Root is tagged record ... end record
    with Maximum_Size => 128;

    type Child is new Root with record ... end record;
    -- The compiler checks that Child'Size is at most 128 bits, and
    -- rejects the program otherwise.

It would now be legal to create statically sized data structures using 
Root'Class, without dynamic memory allocation, by allocating 128 bits 
for each value of type Root'Class:

    type Object_List is array (List_Index) of Root'Class;

    type Object_Pair is record
       A, B : Root'Class;
    end record;

and so on.

With this extension, or some other means to solve point (b), I would 
start using tagged types in embedded SW. For example, I have a major SW 
component, used in several projects, which simulates a class hierarchy 
with variant records and case statements. This component would be 
greatly improved by using a tagged type instead, but it would need data 
structures with class-wide components of static (maximum) size.

What do people think of a Maximum_Size aspect? Should I consider writing 
a formal suggestion to ada-comment?

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

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

* Re: Ada Annoyances
  2017-06-23 17:49     ` Randy Brukardt
  2017-06-23 19:21       ` Niklas Holsti
@ 2017-06-23 19:22       ` Niklas Holsti
  2017-06-30 15:02       ` Norman Worth
  2 siblings, 0 replies; 116+ messages in thread
From: Niklas Holsti @ 2017-06-23 19:22 UTC (permalink / raw)


On 17-06-23 20:49 , Randy Brukardt wrote:
> <raph.amiard@gmail.com> wrote in message
> news:be1619b4-2220-4287-8e67-1af32377d3f7@googlegroups.com...
> ...
>> Ada forcing tagged types on you to use certain features *is* a
>> problem, if only because certain Ada users are forbidden to
>> use tagged types altogether and thus are prevented to use a
>> lot of useful features.
>
> Stupid language usage rules are not the problem of the language design,
> they're a management problem.

Sometimes usage rules are imposed by environment constraints, in 
particular limited resources in smallish embedded systems, combined with 
reliability requirements which mean that running out of resources at run 
time must be avoided.

> I can understand banning T'Class (thus banning
> dynamic dispatching) and banning controlled types (thus banning hidden calls
> that can be harder to analyze), but not banning tagged types themselves.

I have so far avoided using tagged types in my embedded applications 
because they indeed hamper the discovery of resource usage (execution 
time and stack space) by static analysis, as you said.

There are two reasons why tagged types hamper such analysis:

a) dispatching calls (as you said), where the actual callee is 
determined by run-time values (tags) which are hard to predict by static 
analysis

b) the non-static size of class-wide objects (of type T'Class), which 
means that the compiler and/or the programmer must use dynamic 
allocation (usually heap or secondary stack) for such objects.

Point (a) can be worked around: static analysis tools usually let the 
analyst specify the possible set of callees for a "dynamic call" (of 
which dispatching calls are one kind) and the analysis can then 
encompass all those callees. (Alternatively, the analysis tool can 
extract the class hierarchy from the debugging information, and itself 
discover the possible callees.)

Point (b) is more difficult and I know of no work-around that can be 
applied at analysis time.

For some time, I have had in mind a possible Ada extension to solve 
point (b): an attribute/aspect that would let the programmer set a 
static upper bound on the size of any object in T'Class. If we call this 
aspect Maximum_Size (or perhaps Maximum_Size'Class), the programmer 
could use it like this:

    type Root is tagged record ... end record
    with Maximum_Size => 128;

    type Child is new Root with record ... end record;
    -- The compiler checks that Child'Size is at most 128 bits, and
    -- rejects the program otherwise.

It would now be legal to create statically sized data structures using 
Root'Class, without dynamic memory allocation, by allocating 128 bits 
for each value of type Root'Class:

    type Object_List is array (List_Index) of Root'Class;

    type Object_Pair is record
       A, B : Root'Class;
    end record;

and so on.

With this extension, or some other means to solve point (b), I would 
start using tagged types in embedded SW. For example, I have a major SW 
component, used in several projects, which simulates a class hierarchy 
with variant records and case statements. This component would be 
greatly improved by using a tagged type instead, but it would need data 
structures with class-wide components of static (maximum) size.

What do people think of a Maximum_Size aspect? Should I consider writing 
a formal suggestion to ada-comment?

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

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

* Re: Ada Annoyances
  2017-06-23 18:56           ` Maciej Sobczak
@ 2017-06-23 22:18             ` pythoner6
  2017-06-24  8:05               ` Dmitry A. Kazakov
  2017-06-24  8:34               ` Maciej Sobczak
  2017-12-17 16:24             ` Mehdi Saada
  1 sibling, 2 replies; 116+ messages in thread
From: pythoner6 @ 2017-06-23 22:18 UTC (permalink / raw)


On Friday, June 23, 2017 at 2:56:09 PM UTC-4, Maciej Sobczak wrote:
> In C++ it is always possible to do:
> 
> obj.SomeBaseClass::function();
> 
> where obj is some reference, or:
> 
> ptr->SomeBaseClass::function();
> 
> This means that it *is* possible to select T at the call site.

Thanks for pointing this out. I had a feeling there was probably a way to do it, but I couldn't remember ever seeing the syntax for it.

> There is one place where Ada is broken in this regard - Controlled types. These should not be tagged. C++ got it right here.

Out of curiosity, why should controlled types not be tagged? And how is C++ much different - other than that you can make destructors non-virtual (and therefore never dynamically dispatch, though I think the advice I usually see is to make almost all destructors virtual to avoid the case where the wrong destructor gets called).

> Interestingly, C++ got it right also by forcing the object type in constructors and destructors - that is, you never see the object in a view that would not be compatible with the lifetime of its parts. Ada does not do this and it is a hole in the type system that can lead to serious errors.

Again, I'm not quite sure I follow you here. What do you mean by "not compatible with the lifetime of its parts"?

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

* Re: Ada Annoyances
  2017-06-23 19:21       ` Niklas Holsti
@ 2017-06-24  4:02         ` Shark8
  2017-06-24 19:55         ` Simon Wright
                           ` (2 subsequent siblings)
  3 siblings, 0 replies; 116+ messages in thread
From: Shark8 @ 2017-06-24  4:02 UTC (permalink / raw)


On Friday, June 23, 2017 at 1:21:36 PM UTC-6, Niklas Holsti wrote:
> 
> What do people think of a Maximum_Size aspect? Should I consider writing 
> a formal suggestion to ada-comment?

Please do.

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

* Re: Ada Annoyances
  2017-06-23 22:18             ` pythoner6
@ 2017-06-24  8:05               ` Dmitry A. Kazakov
  2017-06-24  8:35                 ` Maciej Sobczak
  2017-06-24  8:34               ` Maciej Sobczak
  1 sibling, 1 reply; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-06-24  8:05 UTC (permalink / raw)


On 2017-06-24 00:18, pythoner6@gmail.com wrote:

> Out of curiosity, why should controlled types not be tagged? And how
> is C++ much different - other than that you can make destructors
> non-virtual (and therefore never dynamically dispatch, though I think
> the advice I usually see is to make almost all destructors virtual to
> avoid the case where the wrong destructor gets called).

User-defined initialization/finalization is broken in both languages, 
but differently.

It does not need dispatch and tags. For class-wide objects as with all 
objects it is the responsibility of the type. Thus T and T'Class must 
have their own initialization/finalization hooks, which also would solve 
the issue of dispatch from constructor.

> Again, I'm not quite sure I follow you here. What do you mean by "not
> compatible with the lifetime of its parts"?
That is when, for example, you have a not fully constructed object of a 
type used as if it were constructed.

A class-wide object of type S derived from T must be constructed in this 
order:

    T
    S
    S'Class
    T'Class

For each stage a user-defined hook called.

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

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

* Re: Ada Annoyances
  2017-06-23 22:18             ` pythoner6
  2017-06-24  8:05               ` Dmitry A. Kazakov
@ 2017-06-24  8:34               ` Maciej Sobczak
  2017-06-24 13:06                 ` pythoner6
  2017-06-26  0:06                 ` Randy Brukardt
  1 sibling, 2 replies; 116+ messages in thread
From: Maciej Sobczak @ 2017-06-24  8:34 UTC (permalink / raw)



> > There is one place where Ada is broken in this regard - Controlled types. These should not be tagged. C++ got it right here.
> 
> Out of curiosity, why should controlled types not be tagged?

Because tagging (like v-table in C++) is a language design artefact that enables dynamic binding, which has its costs and has nothing to do with automated lifetime management. These concepts are orthogonal and there is no need to entangle them together.

This has practical implications. In C++ the auto_ptr or scoped_ptr (or similar) wrapper has literally zero cost, both in space and in time. If the raw pointer has 4 bytes (on a 32-bit machine), the scoped_ptr wrapper will have 4 bytes, too. Ada imposes unnecessary cost - again, both in space and time.

> And how is C++ much different - other than that you can make destructors non-virtual

In a class that is not intented for use in a class hierarchy (like said RAII wrappers) the destructor should *not* be virtual, as there is no reason for it to be.

> (and therefore never dynamically dispatch, though I think the advice I usually see is to make almost all destructors virtual to avoid the case where the wrong destructor gets called).

This is not a complete advice. If the class is not part of any hierarchy, there is only one destructor and always the right one will be called.

> Again, I'm not quite sure I follow you here. What do you mean by "not compatible with the lifetime of its parts"?

In C++ when the object of derived class is constructed, its base class constructor is called first and at that time the object is considered to have the Base dynamic type, which makes sense, as the derived parts have not yet been initialized (they will be initialized in the Derived constructor, which will happen later). Only after the base constructor finishes, the dynamic type of the object is "promoted" to Derived. This means that virtual calls within the Base constructor will never dispatch to Derived variants, which is safer, as it prevents accidental access to not-yet-initialized parts of the object from virtual functions. We say that from within constructors (and destructors, where the same process goes in the reverse direction) the static type is equal to the dynamic type of the object.
Ada does not have this feature and diaptching calls can access uninitialized components from derived parts by means of dispatching to the not-yet-born parts of the object.

In this sense and this particular context, C++ offers better and stronger (!) type safety than Ada.

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

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

* Re: Ada Annoyances
  2017-06-24  8:05               ` Dmitry A. Kazakov
@ 2017-06-24  8:35                 ` Maciej Sobczak
  2017-06-24  9:07                   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 116+ messages in thread
From: Maciej Sobczak @ 2017-06-24  8:35 UTC (permalink / raw)



> A class-wide object of type S derived from T must be constructed in this 
> order:
> 
>     T
>     S
>     S'Class
>     T'Class
> 
> For each stage a user-defined hook called.

I see no practical benefit from this. Can you provide some motivating example?

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


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

* Re: Ada Annoyances
  2017-06-24  8:35                 ` Maciej Sobczak
@ 2017-06-24  9:07                   ` Dmitry A. Kazakov
  2017-06-24 20:50                     ` Maciej Sobczak
  0 siblings, 1 reply; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-06-24  9:07 UTC (permalink / raw)


On 2017-06-24 10:35, Maciej Sobczak wrote:
> 
>> A class-wide object of type S derived from T must be constructed in this
>> order:
>>
>>      T
>>      S
>>      S'Class
>>      T'Class
>>
>> For each stage a user-defined hook called.
> 
> I see no practical benefit from this. Can you provide some motivating example?

Dispatch upon object construction.

    type T is tagged ...
    procedure Foo (X : in out T);
    procedure Bar (X : in out T) is abstract;

    procedure T'Initialize (X : in out T) is
    begin
       Foo (X); -- This is OK
       Bar (T'Class (X)); -- This is not OK
    end T'Initialize;

    procedure T'Class'Initialize (X : in out T'Class) is
    begin
       Bar (X); -- This is OK, all descendants constructed
    end T'Class'Initialize;

In C++ you can have T and S parts, plus a language hack that kills 
dispatching while there.

In Ada you can override T + S + S'Class + T'Class as a whole for a 
controlled type.

Neither is complete nor safe and causes a lot of problem. E.g. in Ada it 
is the latest stage of construction which apart from enforcing an 
error-prone practice calling parent's Initialize prevents us from having 
task components.

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


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

* Re: Ada Annoyances
  2017-06-24  8:34               ` Maciej Sobczak
@ 2017-06-24 13:06                 ` pythoner6
  2017-06-24 15:40                   ` Dmitry A. Kazakov
  2017-06-26  0:06                 ` Randy Brukardt
  1 sibling, 1 reply; 116+ messages in thread
From: pythoner6 @ 2017-06-24 13:06 UTC (permalink / raw)


On Saturday, June 24, 2017 at 4:34:32 AM UTC-4, Maciej Sobczak wrote:
> Because tagging (like v-table in C++) is a language design artefact that enables dynamic binding, which has its costs and has nothing to do with automated lifetime management. These concepts are orthogonal and there is no need to entangle them together.

Yes, I definitely agree with that - which is similar to the reason I started this thread.

> This has practical implications. In C++ the auto_ptr or scoped_ptr (or similar) wrapper has literally zero cost, both in space and in time. If the raw pointer has 4 bytes (on a 32-bit machine), the scoped_ptr wrapper will have 4 bytes, too. Ada imposes unnecessary cost - again, both in space and time.

As I understand it, the penalty in Ada is going to some extra space for the tag (how big is this? I haven't found much info on the size of a tag, which I'm assuming is because this may be implementation dependent?), and the smart pointer will get passed around by reference, as opposed to by value which would make more sense. While for most part I'm not too concerned about the extra space required for the tag (in other cases), for a smart pointer that's probably about doubling the size which is unfortunate.

Method calls won't be dynamically dispatched unless you're dealing with a Smart_Pointer'Class and calling methods that take a Smart_Pointer (which I don't see much reason to do if you want a low overhead smart pointer), right?

> > And how is C++ much different - other than that you can make destructors non-virtual
> 
> In a class that is not intented for use in a class hierarchy (like said RAII wrappers) the destructor should *not* be virtual, as there is no reason for it to be.
> 
> > (and therefore never dynamically dispatch, though I think the advice I usually see is to make almost all destructors virtual to avoid the case where the wrong destructor gets called).
> 
> This is not a complete advice. If the class is not part of any hierarchy, there is only one destructor and always the right one will be called.

Sure - I'm not saying it's necessarily the best practice, but I've certainly seen that advice given. Now that C++ has the final keyword, I think it's probably safer to provide nonvirtual destructors as they can be marked final to ensure that the destructor cannot be accidentally overridden.

> > Again, I'm not quite sure I follow you here. What do you mean by "not compatible with the lifetime of its parts"?
> 
> In C++ when the object of derived class is constructed, its base class constructor is called first and at that time the object is considered to have the Base dynamic type, which makes sense, as the derived parts have not yet been initialized (they will be initialized in the Derived constructor, which will happen later). Only after the base constructor finishes, the dynamic type of the object is "promoted" to Derived. This means that virtual calls within the Base constructor will never dispatch to Derived variants, which is safer, as it prevents accidental access to not-yet-initialized parts of the object from virtual functions. We say that from within constructors (and destructors, where the same process goes in the reverse direction) the static type is equal to the dynamic type of the object.
> Ada does not have this feature and diaptching calls can access uninitialized components from derived parts by means of dispatching to the not-yet-born parts of the object.
> 
> In this sense and this particular context, C++ offers better and stronger (!) type safety than Ada.
> 
> -- 
> Maciej Sobczak * http://www.inspirel.com

Ah, I see.

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

* Re: Ada Annoyances
  2017-06-24 13:06                 ` pythoner6
@ 2017-06-24 15:40                   ` Dmitry A. Kazakov
  0 siblings, 0 replies; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-06-24 15:40 UTC (permalink / raw)


On 2017-06-24 15:06, pythoner6@gmail.com wrote:

> As I understand it, the penalty in Ada is going to some extra space 
> for the tag (how big is this? I haven't found much info on the size
> of a tag, which I'm assuming is because this may be implementation
> dependent?),
Do this:

    type Empty is tagged null record;

Empty'Size is the size in bits.

> and the smart pointer will get passed around by reference, as
> opposed to by value which would make more sense. While for most part
> I'm not too  concerned about the extra space required for the tag (in other cases),
> for a smart pointer that's probably about doubling the size which is
> unfortunate.

That depends. Pointers to reference-counted objects are much better to 
passed by reference. Because by-copy passing will require incrementing 
and decrementing the reference count, which in concurrent environment 
requires expensive locking.

The sorts of pointers usually passed by copy are normally superfluous in 
Ada.

> Method calls won't be dynamically dispatched unless you're dealing
> with a Smart_Pointer'Class and calling methods that take a Smart_Pointer
> (which I don't see much reason to do if you want a low overhead smart
> pointer), right?

Wrong. In Ada a pointer need not to be tagged in order to dispatch on 
the target.

    type T is tagged ...
    procedure Foo (X : in out T);
    type S is new T with ...
    type Pointer is access T'Class;

    X : Pointer := new S;

    X.Foo -- This dispatches

>> In C++ when the object of derived class is constructed, its base
>> class constructor is called first and at that time the object is
>> considered to have the Base dynamic type
[...]
>> In this sense and this particular context, C++ offers better and
>> stronger (!) type safety than Ada.
> Ah, I see.

An object may not change its type. When not constructed it simply does 
not exist.

C++ construction model is safer where it supports user-defined hooks for 
specific types.

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

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

* Re: Ada Annoyances
  2017-06-23 19:21       ` Niklas Holsti
  2017-06-24  4:02         ` Shark8
@ 2017-06-24 19:55         ` Simon Wright
  2017-06-24 20:56           ` Niklas Holsti
  2017-06-25 23:43         ` Randy Brukardt
  2017-06-29 21:12         ` Robert A Duff
  3 siblings, 1 reply; 116+ messages in thread
From: Simon Wright @ 2017-06-24 19:55 UTC (permalink / raw)


Niklas Holsti <niklas.holsti@tidorum.invalid> writes:

> For some time, I have had in mind a possible Ada extension to solve
> point (b): an attribute/aspect that would let the programmer set a
> static upper bound on the size of any object in T'Class. If we call
> this aspect Maximum_Size (or perhaps Maximum_Size'Class), the
> programmer could use it like this:
>
>    type Root is tagged record ... end record
>    with Maximum_Size => 128;
>
>    type Child is new Root with record ... end record;
>    -- The compiler checks that Child'Size is at most 128 bits, and
>    -- rejects the program otherwise.
>
> It would now be legal to create statically sized data structures using
> Root'Class, without dynamic memory allocation, by allocating 128 bits
> for each value of type Root'Class:

GNAT is happy with

   type Parent is tagged null record
   with Dynamic_Predicate => Size (Parent) < 128;

   function Size (P : Parent'Class) return Integer is (P'Size);

   type Large is array (1 .. 10) of Integer;
   type Child is new Parent with record
      L : Large;
   end record;

Declaring an object of type Child raises Assert_Failure.

Of course you'd much rather have a static compile-time check!


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

* Re: Ada Annoyances
  2017-06-24  9:07                   ` Dmitry A. Kazakov
@ 2017-06-24 20:50                     ` Maciej Sobczak
  2017-06-24 21:06                       ` Dmitry A. Kazakov
  0 siblings, 1 reply; 116+ messages in thread
From: Maciej Sobczak @ 2017-06-24 20:50 UTC (permalink / raw)



> > I see no practical benefit from this. Can you provide some motivating example?
> 
> Dispatch upon object construction.
[...]

I have asked for a motivating example - that is, something practical, not some incomplete Foo/Bar stub. I still see no benefit.

> In C++ you can have T and S parts, plus a language hack that kills 
> dispatching while there.

Wrong.
C++ does not kill any dispatching anywhere. Calls to virtual functions from constructors/destructors are dispatching. The language only makes sure that the dynamic type (that is, the potential range of dispatching calls) follows the already constructed part of the object and is never ahead of it (because that would be unsafe). This is type safety applied in the place where the effective type of the object changes (!) at run-time. This is not a hack, this is exactly how it should be done.

Your example does not show anything that could not be achieved in C++ - in which case I'm not convinced.

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

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

* Re: Ada Annoyances
  2017-06-24 19:55         ` Simon Wright
@ 2017-06-24 20:56           ` Niklas Holsti
  0 siblings, 0 replies; 116+ messages in thread
From: Niklas Holsti @ 2017-06-24 20:56 UTC (permalink / raw)


On 17-06-24 22:55 , Simon Wright wrote:
> Niklas Holsti <niklas.holsti@tidorum.invalid> writes:
>
>> For some time, I have had in mind a possible Ada extension to solve
>> point (b): an attribute/aspect that would let the programmer set a
>> static upper bound on the size of any object in T'Class. If we call
>> this aspect Maximum_Size (or perhaps Maximum_Size'Class), the
>> programmer could use it like this:
>>
>>    type Root is tagged record ... end record
>>    with Maximum_Size => 128;
>>
>>    type Child is new Root with record ... end record;
>>    -- The compiler checks that Child'Size is at most 128 bits, and
>>    -- rejects the program otherwise.
>>
>> It would now be legal to create statically sized data structures using
>> Root'Class, without dynamic memory allocation, by allocating 128 bits
>> for each value of type Root'Class:
>
> GNAT is happy with
>
>    type Parent is tagged null record
>    with Dynamic_Predicate => Size (Parent) < 128;
>
>    function Size (P : Parent'Class) return Integer is (P'Size);
>
>    type Large is array (1 .. 10) of Integer;
>    type Child is new Parent with record
>       L : Large;
>    end record;
>
> Declaring an object of type Child raises Assert_Failure.

As one would expect, based on standard Ada, yes?

> Of course you'd much rather have a static compile-time check!

Indeed I would.

But the check is not the main point in the suggested Maximum_Size 
aspect: the main point is that it would let the compiler consider the 
type Root'Class as a definite subtype, and would therefore allow its 
direct use as a component of arrays or records, instead of forcing an 
access-classwide to be used as an intermediate.

I don't suppose GNAT lets you use Parent'Class as the component type of 
an array, even with this Dynamic_Predicate?

There may however be some other semantic implications of the definite vs 
indefinite subtype divide, not related to the size of the values, that 
would make it hard to let the suggested Maximum_Size aspect change the 
classwide type from indefinite to definite.

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

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

* Re: Ada Annoyances
  2017-06-24 20:50                     ` Maciej Sobczak
@ 2017-06-24 21:06                       ` Dmitry A. Kazakov
  2017-06-25 11:33                         ` Maciej Sobczak
  0 siblings, 1 reply; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-06-24 21:06 UTC (permalink / raw)


On 2017-06-24 22:50, Maciej Sobczak wrote:
> 
>>> I see no practical benefit from this. Can you provide some motivating example?
>>
>> Dispatch upon object construction.
> [...]
> 
> I have asked for a motivating example - that is, something
> practical,  not some incomplete Foo/Bar stub. I still see no benefit.

For T substitute Abstract_TCP_Server. For Bar substitute 
Get_IP_Address_To_Listen.

>> In C++ you can have T and S parts, plus a language hack that kills
>> dispatching while there.
> 
> Wrong.
> C++ does not kill any dispatching anywhere. Calls to virtual functions from constructors/destructors are dispatching.

That is just same plus heating of the environment.

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


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

* Re: Ada Annoyances
  2017-06-24 21:06                       ` Dmitry A. Kazakov
@ 2017-06-25 11:33                         ` Maciej Sobczak
  2017-06-25 14:32                           ` Dmitry A. Kazakov
  0 siblings, 1 reply; 116+ messages in thread
From: Maciej Sobczak @ 2017-06-25 11:33 UTC (permalink / raw)



> For T substitute Abstract_TCP_Server. For Bar substitute 
> Get_IP_Address_To_Listen.

And I still don't see any benefit. Can you explain what functionality is available in this scheme (and that is not available currently in Ada or C++)?

> > Wrong.
> > C++ does not kill any dispatching anywhere. Calls to virtual functions from constructors/destructors are dispatching.
> 
> That is just same plus heating of the environment.

You are running out of arguments.
Calls to virtual functions while the object is during construction need to work like usual, because they need not be done from the constructor:

void useObject(Base & obj)
{
    obj.foo(); // dispatching call to foo()
}

Base::Base()
{
    // some initialization ...

    useObject(*this);
}

Derived::Derived()
{
    // some initialization ...

    useObject(*this);
}


The useObject function does not know what it gets as an argument and we want it to dispatch to the most specific part, but surely we do not want it to dispatch to the parts that do not yet exist. Most importantly, useObject does not know that it gets called from constructors, because it might be called from any other context as well. It might be even in a different translation unit.

This shows that dispatching is *not* "killed" and whatever environment heating takes place, it is needed, like in any other place where dispatching is considered useful. We can discuss the useless environment heating imposed by Controlled in Ada, instead.

I understand that it is beyond the threshold of humiliation for a die-hard Ada programmer, but I personally don't find it difficult to admit that this is the part that C++ got right.

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

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

* Re: Ada Annoyances
  2017-06-25 11:33                         ` Maciej Sobczak
@ 2017-06-25 14:32                           ` Dmitry A. Kazakov
  2017-06-25 20:50                             ` Maciej Sobczak
  0 siblings, 1 reply; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-06-25 14:32 UTC (permalink / raw)


On 2017-06-25 13:33, Maciej Sobczak wrote:
> 
>> For T substitute Abstract_TCP_Server. For Bar substitute
>> Get_IP_Address_To_Listen.
> 
> And I still don't see any benefit.

It is frequently used design pattern to leave some parts of construction 
used by the parent type to the children.

> Can you explain what
> functionality is available in this scheme (and that is not available
> currently in Ada  or C++)?

In Ada one uses a class-wide operation dispatching to the construction 
call (Get_IP_Address_To_Listen) and a comment that Initialize must call 
it or else the parent's Initialize (which calls it too) if overridden. 
Since Ada's Initialize is called late it is OK to dispatch from there. 
C++ which calls its initializers early. The point is that construction 
requires both early (type-specific) and late (class-wide) initializers.

[...]
> Most importantly, useObject does not know that it gets called from
> constructors, because it might be called from any other context as well.
> It might be even in a different translation unit.
> 
> This shows that dispatching is *not* "killed" and whatever
> environment  heating takes place,

I don't see how it shows that, or anything.

> I understand that it is beyond the threshold of humiliation for a
> die-hard Ada programmer, but I personally don't find it difficult to
> admit that this is the part that C++ got right.

The only right thing are type-specific constructors. Everything else in 
the C++ construction model is wrong. And it is not in Ada's favor. Ada's 
user-construction model is wrong too.

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

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

* Re: Ada Annoyances
  2017-06-25 14:32                           ` Dmitry A. Kazakov
@ 2017-06-25 20:50                             ` Maciej Sobczak
  2017-06-26  7:58                               ` Dmitry A. Kazakov
  0 siblings, 1 reply; 116+ messages in thread
From: Maciej Sobczak @ 2017-06-25 20:50 UTC (permalink / raw)


> It is frequently used design pattern to leave some parts of construction 
> used by the parent type to the children.

I have never heard the name of this "design pattern", but if I understand the description correctly, I can do that in C++. So there is no need for anything more evolved.

> The point is that construction 
> requires both early (type-specific) and late (class-wide) initializers.

The example I have shown demonstrates this.

> [...]
> > Most importantly, useObject does not know that it gets called from
> > constructors, because it might be called from any other context as well.
> > It might be even in a different translation unit.
> > 
> > This shows that dispatching is *not* "killed" and whatever
> > environment  heating takes place,
> 
> I don't see how it shows that, or anything.

The useObject function performs a dispatching call and it does so even if the function itself is called in the middle of some object construction. So, the dispatching is not "killed" while the object is being constructed. It still works properly, with the type-safe range of dispatch.

> The only right thing [...]

For me the only right thing is type safety. If it is compromised, like in Ada, then the language got it wrong.

> Everything else in 
> the C++ construction model is wrong.

C++ has stronger type safety than Ada in this particular context. I'm fine with it. If it's wrong for you, let's agree to disagree.

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

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

* Re: Ada Annoyances
  2017-06-23 19:21       ` Niklas Holsti
  2017-06-24  4:02         ` Shark8
  2017-06-24 19:55         ` Simon Wright
@ 2017-06-25 23:43         ` Randy Brukardt
  2017-06-26 20:20           ` Niklas Holsti
  2017-06-29 21:12         ` Robert A Duff
  3 siblings, 1 reply; 116+ messages in thread
From: Randy Brukardt @ 2017-06-25 23:43 UTC (permalink / raw)


"Niklas Holsti" <niklas.holsti@tidorum.invalid> wrote in message 
news:4921bd4e-3827-a7ac-7f2d-d60edbc514a3@tidorum.invalid...
> On 17-06-23 20:49 , Randy Brukardt wrote:
>> <raph.amiard@gmail.com> wrote in message
>> news:be1619b4-2220-4287-8e67-1af32377d3f7@googlegroups.com...
>> ...
>>> Ada forcing tagged types on you to use certain features *is* a
>>> problem, if only because certain Ada users are forbidden to
>>> use tagged types altogether and thus are prevented to use a
>>> lot of useful features.
>>
>> Stupid language usage rules are not the problem of the language design,
>> they're a management problem.
>
> Sometimes usage rules are imposed by environment constraints, in 
> particular limited resources in smallish embedded systems, combined with 
> reliability requirements which mean that running out of resources at run 
> time must be avoided.
>
>> I can understand banning T'Class (thus banning
>> dynamic dispatching) and banning controlled types (thus banning hidden 
>> calls
>> that can be harder to analyze), but not banning tagged types themselves.
...

> b) the non-static size of class-wide objects (of type T'Class), which 
> means that the compiler and/or the programmer must use dynamic allocation 
> (usually heap or secondary stack) for such objects.
...
> Point (b) is more difficult and I know of no work-around that can be 
> applied at analysis time.

Simply banning the use of T'Class has that effect. It's rather drastic, but 
it eliminates all of the dynamic features. Note that this was considered 
important enough that the standard (in Annex H) restriction No_Dispatch has 
this effect.

You still get the other advantages of tagged types (extension, proper 
inheritance for private, equality, prefixed notation, etc.), and there is 
almost no runtime penalty (or analysis problem).

                         Randy.

    . 


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

* Re: Ada Annoyances
  2017-06-24  8:34               ` Maciej Sobczak
  2017-06-24 13:06                 ` pythoner6
@ 2017-06-26  0:06                 ` Randy Brukardt
  2017-06-26 20:35                   ` Maciej Sobczak
  1 sibling, 1 reply; 116+ messages in thread
From: Randy Brukardt @ 2017-06-26  0:06 UTC (permalink / raw)


"Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message 
news:bb2dce33-54bd-426c-9029-f965fa007e3b@googlegroups.com...
...
> In C++ when the object of derived class is constructed, its base class
> constructor is called first and at that time the object is considered to 
> have
> the Base dynamic type, which makes sense, as the derived parts have not
> yet been initialized (they will be initialized in the Derived constructor, 
> which
> will happen later). Only after the base constructor finishes, the dynamic 
> type
> of the object is "promoted" to Derived. This means that virtual calls 
> within
> the Base constructor will never dispatch to Derived variants, which is 
> safer,
> as it prevents accidental access to not-yet-initialized parts of the 
> object from
> virtual functions. We say that from within constructors (and destructors,
> where the same process goes in the reverse direction) the static type is
> equal to the dynamic type of the object.

> Ada does not have this feature and diaptching calls can access 
> uninitialized
> components from derived parts by means of dispatching to the not-yet-born
> parts of the object.

C++ needs this model since it has no way to eliminate dispatching from 
routines. In Ada, where redispatching requires explicit work, the vast 
majority of constructors will never make a dispatching call so there is very 
little risk. The problem in Ada is that there isn't any way to determine 
which routines are used as constructors (they're just ordinary routines), so 
it isn't possible to enforce special rules on them. And banning all 
redispatching seems too draconian.

In any case, this problem is irrelevant. Since it is, in general, impossible 
for the language to determine a safe order of initialization for the 
components of an arbitrary record type (3.3.1 has a complicated set of rules 
attempting to do that, but it is known not to work in all cases, and it's 
unlikely that they're consistently implemented, either), there are much 
worse problems that can be caused by a clueless type constructor (which 
would apply to almost all of us).

Ada at least tries to define the order of initialization (that is, 
elaboration). Most other languages don't even try.

The net takeaway is that a truly type-safe language maybe could be 
constructed, but it would have to be an incredibly simple language with very 
little practical application. So that sort of thing is irrelevant.

                                         Randy.



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

* Re: Ada Annoyances
  2017-06-25 20:50                             ` Maciej Sobczak
@ 2017-06-26  7:58                               ` Dmitry A. Kazakov
  2017-06-26 13:24                                 ` Maciej Sobczak
  0 siblings, 1 reply; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-06-26  7:58 UTC (permalink / raw)


On 25/06/2017 22:50, Maciej Sobczak wrote:
>> It is frequently used design pattern to leave some parts of construction
>> used by the parent type to the children.
> 
> I have never heard the name of this "design pattern", but if I
> understand the description correctly, I can do that in C++. So there is
> no need for anything more evolved.

The example must demonstrate dispatch to the operation of the object's 
type (the ultimate type) from a body defined for the parent type T class.

> C++ has stronger type safety than Ada in this particular context.

It is apples and oranges. As I explained C++ has type-specific 
constructors while Ada's Initialization is a class-wide constructor. You 
cannot compare them.

Obviously for daily use type-specific constructors are much more useful 
than class-wide ones, IMO.

I am far from being satisfied with the Initialize/Finalize/Adjust hack.

> I'm  fine with it. If it's wrong for you, let's agree to disagree.

It is always unsafe to use one method instead of another.

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


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

* Re: Ada Annoyances
  2017-06-21 12:29   ` Pascal Obry
  2017-06-21 14:52     ` pythoner6
@ 2017-06-26 11:01     ` Vincent
  2017-06-26 11:15       ` Alejandro R. Mosteo
  2017-06-26 16:35       ` Pascal Obry
  1 sibling, 2 replies; 116+ messages in thread
From: Vincent @ 2017-06-26 11:01 UTC (permalink / raw)


Hello Pascal,

Nice to meet you on this forum !

> So do check for performance when the application actually run.
How can I do this ? Is there a package that allows an easy instrumentation of the code, providing traces in real time ?

Kind regards,

Vincent

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

* Re: Ada Annoyances
  2017-06-26 11:01     ` Vincent
@ 2017-06-26 11:15       ` Alejandro R. Mosteo
  2017-06-26 16:35       ` Pascal Obry
  1 sibling, 0 replies; 116+ messages in thread
From: Alejandro R. Mosteo @ 2017-06-26 11:15 UTC (permalink / raw)


On 26/06/17 13:01, Vincent wrote:
> Hello Pascal,
> 
> Nice to meet you on this forum !
> 
>> So do check for performance when the application actually run.
> How can I do this ? Is there a package that allows an easy instrumentation of the code, providing traces in real time ?

Not in real time, but for post-mortem you can use regular profilers. I 
only have recent experience with valgrind.

For real-time profiling I heard aeons ago about oprofile. No experience 
with it...

I too have to fight the premature optimization urge. But now that I've 
limited time or patience for code trickery it is easier to just focus on 
correct, maintainable code, and leave optimizations for whenever they 
make themselves clearly necessary ;)

Alex.

> 
> Kind regards,
> 
> Vincent
> 


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

* Re: Ada Annoyances
  2017-06-26  7:58                               ` Dmitry A. Kazakov
@ 2017-06-26 13:24                                 ` Maciej Sobczak
  2017-06-26 16:38                                   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 116+ messages in thread
From: Maciej Sobczak @ 2017-06-26 13:24 UTC (permalink / raw)


> The example must demonstrate dispatch to the operation of the object's 
> type (the ultimate type) from a body defined for the parent type T class.

More complete demonstration:

#include <cstdio>

class Base
{
public:
    Base();
    
    virtual void vfoo();
};

class Derived : public Base
{
public:
    Derived();
    
    virtual void vfoo();
};

void useObject(Base & b)
{
    b.vfoo();
}

Base::Base()
{
    std::puts("   calling useObject from Base constructor:");
    
    useObject(*this);
}

void Base::vfoo()
{
    std::puts("      Hello from Base object!");
}

Derived::Derived()
{
    std::puts("   calling useObject from Derived constructor:");
    
    useObject(*this);
}

void Derived::vfoo()
{
    std::puts("      Hello from Derived object!");
}

int main()
{
    std::puts("test with Base object:");
    Base b;
    
    std::puts("");
    
    std::puts("test with Derived object:");
    Derived d;
}

$ g++ test.cpp
$ ./a.exe
test with Base object:
   calling useObject from Base constructor:
      Hello from Base object!

test with Derived object:
   calling useObject from Base constructor:
      Hello from Base object!
   calling useObject from Derived constructor:
      Hello from Derived object!

Since the Derived object is constructed in a two-step process, the useObject function is called twice, once from the Base part and once from the Derived part. The dispatch from the first call does not reach the not-yet-created parts of the object, which is a safe behavior.

> > C++ has stronger type safety than Ada in this particular context.
> 
> It is apples and oranges.

If you choose so. In this particular context, apples taste better.

> As I explained C++ has type-specific 
> constructors while Ada's Initialization is a class-wide constructor. You 
> cannot compare them.

I can and I should, since both are used to achieve the same design-level intent, which is construction of a newly created object.

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


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

* Re: Ada Annoyances
  2017-06-26 11:01     ` Vincent
  2017-06-26 11:15       ` Alejandro R. Mosteo
@ 2017-06-26 16:35       ` Pascal Obry
  1 sibling, 0 replies; 116+ messages in thread
From: Pascal Obry @ 2017-06-26 16:35 UTC (permalink / raw)



Hello Vincent,

> Nice to meet you on this forum !

Yeah! Hope you're doing well.

> > So do check for performance when the application actually run.
> 
> How can I do this ? Is there a package that allows an easy
> instrumentation of the code, providing traces in real time ?

Depending on the application. The first step is just to ensure that the
application "meet" the time constraints. If not hard real time I
usually do:

$ time myapplication

If the application is fast enough then that's all.

If the application seems sluggish then you need to instrument it and
profile it. And the fact is that I have rarely the need for this. Long
time ago I did use gprof with GNAT.

Regards,


-- 
  Pascal Obry /  Magny Les Hameaux (78)

  The best way to travel is by means of imagination

  http://www.obry.net

  gpg --keyserver keys.gnupg.net --recv-key F949BD3B

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

* Re: Ada Annoyances
  2017-06-26 13:24                                 ` Maciej Sobczak
@ 2017-06-26 16:38                                   ` Dmitry A. Kazakov
  2017-06-26 20:42                                     ` Maciej Sobczak
  0 siblings, 1 reply; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-06-26 16:38 UTC (permalink / raw)


On 2017-06-26 15:24, Maciej Sobczak wrote:
>> The example must demonstrate dispatch to the operation of the object's
>> type (the ultimate type) from a body defined for the parent type T class.
> 
> Since the Derived object is constructed in a two-step process, the
> useObject function is called twice, once from the Base part and once
> from the Derived part.

Exactly my point. Dispatch is "killed" or misrouted if you want.

>> It is apples and oranges.
> 
> If you choose so. In this particular context, apples taste better.

Yes, if type-specific constructors is what is needed. Ada's concept of T 
and T'Class does not prevent having them, if ARG once decides to fix the 
mess. C++ model cannot be fixed ever.

>> As I explained C++ has type-specific
>> constructors while Ada's Initialization is a class-wide constructor. You
>> cannot compare them.
> 
> I can and I should, since both are used to achieve the same
> design-level intent, which is construction of a newly created object.

No. Application is very different. A class-wide constructor is called 
when construction of all instances is complete. E.g. for T'Class it 
would mean that the specific constructors from T to S are all through.

As I explained the sequence is this:

    T
    S
    S'Class
           / Here the run-time activates a task component of T with
           \ a discriminant of T'Class
    T'Class <- Here you call a task entry to pass parameters

And for destructor:

    T'Class < Here you call an entry to ask task to quit
            < Here the run-time awaits task termination
    S'Class
    S
    T

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


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

* Re: Ada Annoyances
  2017-06-25 23:43         ` Randy Brukardt
@ 2017-06-26 20:20           ` Niklas Holsti
  2017-06-26 21:47             ` Randy Brukardt
  0 siblings, 1 reply; 116+ messages in thread
From: Niklas Holsti @ 2017-06-26 20:20 UTC (permalink / raw)


On 17-06-26 02:43 , Randy Brukardt wrote:
> "Niklas Holsti" <niklas.holsti@tidorum.invalid> wrote in message
> news:4921bd4e-3827-a7ac-7f2d-d60edbc514a3@tidorum.invalid...
>> On 17-06-23 20:49 , Randy Brukardt wrote:
>>> <raph.amiard@gmail.com> wrote in message
>>> news:be1619b4-2220-4287-8e67-1af32377d3f7@googlegroups.com...
>>> ...
>>>> Ada forcing tagged types on you to use certain features *is* a
>>>> problem, if only because certain Ada users are forbidden to
>>>> use tagged types altogether and thus are prevented to use a
>>>> lot of useful features.
>>>
>>> Stupid language usage rules are not the problem of the language design,
>>> they're a management problem.
>>
>> Sometimes usage rules are imposed by environment constraints, in
>> particular limited resources in smallish embedded systems, combined with
>> reliability requirements which mean that running out of resources at run
>> time must be avoided.
>>
>>> I can understand banning T'Class (thus banning
>>> dynamic dispatching) and banning controlled types (thus banning hidden
>>> calls
>>> that can be harder to analyze), but not banning tagged types themselves.
> ...
>
>> b) the non-static size of class-wide objects (of type T'Class), which
>> means that the compiler and/or the programmer must use dynamic allocation
>> (usually heap or secondary stack) for such objects.
> ...
>> Point (b) is more difficult and I know of no work-around that can be
>> applied at analysis time.
>
> Simply banning the use of T'Class has that effect.

At design and compilation time, yes, with consequent restrictions on the 
design. But it is not a work-around that allows static analysis of 
programs which do use T'Class.

> It's rather drastic, but
> it eliminates all of the dynamic features. Note that this was considered
> important enough that the standard (in Annex H) restriction No_Dispatch has
> this effect.
>
> You still get the other advantages of tagged types (extension, proper
> inheritance for private, equality, prefixed notation, etc.), and there is
> almost no runtime penalty (or analysis problem).

For the application I most have in mind (a SW component currently using 
discriminated records to simulate tagged types) there would be no point 
in using tagged types with the No_Dispatch restriction. The loss of 
class-wide programming and class-wide data structures would remove 
almost all benefits.

My hope is that a Maximum_Size aspect would let one manipulate 
class-wide objects in the same "definite" way as is possible for variant 
records with a default discriminant value. However, it would require 
that the tag of an object could be changed by assignment; this is 
perhaps too radical a change in the tagged object semantics.

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

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

* Re: Ada Annoyances
  2017-06-26  0:06                 ` Randy Brukardt
@ 2017-06-26 20:35                   ` Maciej Sobczak
  2017-06-26 21:40                     ` Randy Brukardt
  2017-06-27 15:19                     ` AdaMagica
  0 siblings, 2 replies; 116+ messages in thread
From: Maciej Sobczak @ 2017-06-26 20:35 UTC (permalink / raw)


> C++ needs this model

In other words, what it offers is complete. Sounds fair.

> In Ada, where redispatching requires explicit work, the vast 
> majority of constructors will never make a dispatching call so there is very 
> little risk.

The vast majority? Where does this statistics come from?
I expect programmers to delegate initialization of the base parts to the initialization procedure that was already written for the base part, like here:

      procedure Initialize (Obj : in out Derived) is
      begin
         -- initialize Base part:
         Initialize (Base (Obj));
         
         -- initialize Derived part:
         -- ...
      end Initialize;

I'm not sure whether this is majority or minority, but the idiom seems to be intuitive. The problem is - even though the view conversion is explicit here, the dispatching call in the Base version of Initialize is not and it is there, where the potentially unsafe action can occur. These two places can be in separate files, written by different programmers. If you decouple explicit from unsafe, this is no longer in the Ada spirit.

The complete example (analogous to the C++ example I have written in the other post) is:

with Ada.Text_IO;
with Ada.Finalization;

procedure Test is
   
   package P is
      type Base is new Ada.Finalization.Limited_Controlled with null record;
      
      procedure Initialize (Obj : in out Base);
      procedure VFoo (Obj : in Base);
      
      type Derived is new Base with null record;
      
      procedure Initialize (Obj : in out Derived);
      procedure VFoo (Obj : in Derived);
      
      procedure Use_Object (Obj : in Base'Class);
   end P;
   
   package body P is
      procedure Initialize (Obj : in out Base) is
      begin
         Ada.Text_IO.Put_Line ("   call from Base's Initialize");
         Use_Object (Obj);
      end Initialize;
      
      procedure VFoo (Obj : in Base) is
      begin
         Ada.Text_IO.Put_Line ("      Hello from Base");
      end VFoo;
      
      procedure Initialize (Obj : in out Derived) is
      begin
         -- initialize Base part:
         Initialize (Base (Obj));
         
         Ada.Text_IO.Put_Line ("   call from Derived's Initialize");
         Use_Object (Obj);
      end Initialize;
      
      procedure VFoo (Obj : in Derived) is
      begin
         Ada.Text_IO.Put_Line ("      Hello from Derived");
      end VFoo;
      
      procedure Use_Object (Obj : in Base'Class)  is
      begin
         VFoo (Obj);
      end Use_Object;
   end P;
   
begin
   Ada.Text_IO.Put_Line ("test with Base");
   declare
      B : P.Base;
   begin
      null;
   end;
   
   Ada.Text_IO.Put_Line ("test with Derived");
   declare
      D : P.Derived;
   begin
      null;
   end;
end Test;

When executed, we get:

test with Base
   call from Base's Initialize
      Hello from Base
test with Derived
   call from Base's Initialize
      Hello from Derived   <<<<<<< here are dragons!
   call from Derived's Initialize
      Hello from Derived


> In any case, this problem is irrelevant.

So guess how did I learn about it...

> The net takeaway is that a truly type-safe language maybe could be 
> constructed,

Yes. C++ got that part right.

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

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

* Re: Ada Annoyances
  2017-06-26 16:38                                   ` Dmitry A. Kazakov
@ 2017-06-26 20:42                                     ` Maciej Sobczak
  0 siblings, 0 replies; 116+ messages in thread
From: Maciej Sobczak @ 2017-06-26 20:42 UTC (permalink / raw)


> > Since the Derived object is constructed in a two-step process, the
> > useObject function is called twice, once from the Base part and once
> > from the Derived part.
> 
> Exactly my point. Dispatch is "killed" or misrouted if you want.

The result is better type safety. You can call it "killed", "misrouted", "untyped", "broken", "impossible to repair", "apples vs. oranges", or whatever. I really don't mind.

And since all arguments have been written and we seem to fall in a loop, I propose to finish at that point.

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

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

* Re: Ada Annoyances
  2017-06-26 20:35                   ` Maciej Sobczak
@ 2017-06-26 21:40                     ` Randy Brukardt
  2017-06-27  7:23                       ` Maciej Sobczak
  2017-06-27  7:26                       ` Dmitry A. Kazakov
  2017-06-27 15:19                     ` AdaMagica
  1 sibling, 2 replies; 116+ messages in thread
From: Randy Brukardt @ 2017-06-26 21:40 UTC (permalink / raw)


"Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message 
news:71c4fdcd-4213-4b84-b852-c8674cfaf717@googlegroups.com...
...
>> In Ada, where redispatching requires explicit work, the vast
>> majority of constructors will never make a dispatching call so there is 
>> very
>> little risk.

>The vast majority? Where does this statistics come from?

Common sense. Constructors shouldn't be doing anything complicated in the 
first place, so there's not much reason for delegation. Even if you do use 
it, dispatching calls are rare in good Ada code. Most of them come from 
factories or global data structures, which are irrelevant here (you're not 
using those things on the constructed object itself within a constructor).

In any case, interfaces and other forms of OOP dispatching are greatly 
overrated; the cases where they can be profitably employed in real-world 
programs are quite rare. (There's much more value from type extension and 
implementation inheritance.)

As I tried to say yesterday, Ada does have a flaw in that allows dispatching 
calls within contructors (and more generally, inside of any primitive 
operations). That requires work of some sort, but it is possible, and it 
shouldn't be. It's too late to fix that in terms of the language, but it's 
easy enough to check with tools like AdaControl.

>I expect programmers to delegate initialization of the base parts to the 
>initialization
> procedure that was already written for the base part, like here:

Surely.

>I'm not sure whether this is majority or minority, but the idiom seems to 
>be intuitive.
>The problem is - even though the view conversion is explicit here, the 
>dispatching
>call in the Base version of Initialize is not and it is there, where the 
>potentially
>unsafe action can occur.

A dispatching call in *any* version of Initialize is a problem, is 
unnecessary, and should have been banned by the language. Don't do it, and 
you'll have no problem to worry about. (And that it true for every 
primitive - "method" in C++ terms.)

...
> These two places can be in separate files, written by different 
> programmers.
> If you decouple explicit from unsafe, this is no longer in the Ada spirit.

Yes, of course if you call broken code, your code will end up broken too. 
Hard to see what could be done about that - it's always possible that the 
base class is written by an incompetent programmer. (Another reason that I 
personally don't think too much of OOP - I want control of everything I 
write -- if I'm going to make a fatal mistake, I at least want it to be 
something that I can improve next time.)

>The complete example (analogous to the C++ example I have written in the 
>other post) is:

I don't buy the usefulness (in real code) of a class-wide Use_Object. My 
experience has been such routines almost always end up needing to be 
primitive (and definitely true in this case).

In any case, we both agree that you shouldn't be able to call Use_Object in 
this case, I suspect our reasons differ but the effect is the same.

>> In any case, this problem is irrelevant.
>
>So guess how did I learn about it...

You wrote some ill-advised Initialize routines? Re-dispatching is almost 
always evil, do it only after VERY careful consideration. (Note that we had 
to fix Pre'Class/Post'Class so they didn't unintentionally cause 
redispatching, as the effect was that a body might not have had the 
precondition it was expecting to have been evaluated).

>> The net takeaway is that a truly type-safe language maybe could be
>> constructed,
>
>Yes. C++ got that part right.

You completely ignored my point about order of initialization, which 
destroys any type-safety up-front. I don't think C++ (or any other 
mainstream language) even tries to get that right...

                               Randy.


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

* Re: Ada Annoyances
  2017-06-26 20:20           ` Niklas Holsti
@ 2017-06-26 21:47             ` Randy Brukardt
  2017-06-26 22:23               ` Dmitry A. Kazakov
  2017-06-29 19:00               ` Niklas Holsti
  0 siblings, 2 replies; 116+ messages in thread
From: Randy Brukardt @ 2017-06-26 21:47 UTC (permalink / raw)


"Niklas Holsti" <niklas.holsti@tidorum.invalid> wrote in message 
news:erd8jiFhsroU1@mid.individual.net...
> On 17-06-26 02:43 , Randy Brukardt wrote:
...
>>> Point (b) is more difficult and I know of no work-around that can be
>>> applied at analysis time.
>>
>> Simply banning the use of T'Class has that effect.
>
> At design and compilation time, yes, with consequent restrictions on the 
> design. But it is not a work-around that allows static analysis of 
> programs which do use T'Class.

There's no free lunch! T'Class is by definition "indefinite", since existing 
code already compiled has to be able to handle newly defined types 
(including those that don't yet exist). That's never going to allow 
conventional static analysis.

>> It's rather drastic, but
>> it eliminates all of the dynamic features. Note that this was considered
>> important enough that the standard (in Annex H) restriction No_Dispatch 
>> has
>> this effect.
>>
>> You still get the other advantages of tagged types (extension, proper
>> inheritance for private, equality, prefixed notation, etc.), and there is
>> almost no runtime penalty (or analysis problem).
>
> For the application I most have in mind (a SW component currently using 
> discriminated records to simulate tagged types) there would be no point in 
> using tagged types with the No_Dispatch restriction. The loss of 
> class-wide programming and class-wide data structures would remove almost 
> all benefits.
>
> My hope is that a Maximum_Size aspect would let one manipulate class-wide 
> objects in the same "definite" way as is possible for variant records with 
> a default discriminant value. However, it would require that the tag of an 
> object could be changed by assignment; this is perhaps too radical a 
> change in the tagged object semantics.

That seems way too drastic a change. I could imagine an aspect like the one 
you proposed to get rid of the indirection, but changing the semantics in a 
major way seems to be more than aspects are supposed to do. And changing the 
tag via assignment means having to be prepared to change finalization of 
objects after the fact as well. Ugh.

                                        Randy.



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

* Re: Ada Annoyances
  2017-06-26 21:47             ` Randy Brukardt
@ 2017-06-26 22:23               ` Dmitry A. Kazakov
  2017-06-29 19:00               ` Niklas Holsti
  1 sibling, 0 replies; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-06-26 22:23 UTC (permalink / raw)


On 2017-06-26 23:47, Randy Brukardt wrote:

> There's no free lunch! T'Class is by definition "indefinite", since existing
> code already compiled has to be able to handle newly defined types
> (including those that don't yet exist). That's never going to allow
> conventional static analysis.

Indefinite unless you constrain these types is some way. Which is the 
essence of the proposal. There is nothing wrong in putting a static 
contract on T'Class upfront for all descendants to obey. After all 
abstract primitive operations is no different.

Another approach could be allowing constrained subtypes of T'Class. E.g.

    subtype S_as_T is T'Class (S);    -- Only S is allowed
    subtype T_to_S is T'Class (T..S); -- Only types between T and S

Of course to have it ane useful one need some syntax for siblings 
(breadth rather than depth).

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

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

* Re: Ada Annoyances
  2017-06-26 21:40                     ` Randy Brukardt
@ 2017-06-27  7:23                       ` Maciej Sobczak
  2017-06-27 20:38                         ` Randy Brukardt
  2017-06-27  7:26                       ` Dmitry A. Kazakov
  1 sibling, 1 reply; 116+ messages in thread
From: Maciej Sobczak @ 2017-06-27  7:23 UTC (permalink / raw)


> >So guess how did I learn about it...
> 
> You wrote some ill-advised Initialize routines?

You cannot say it was ill-advised without knowing the context and purpose. More likely, you prefer to refer to some unspoken "principle" to defend the language - it is convenient, because it avoids discussion. But this is not a design principle, it is a language constraint, simply "don't do that in Ada". I understand this. But if I can do it in other languages, then it might as well be a proper design, it just needs a proper language support, which Ada does not provide.

> Re-dispatching is almost 
> always evil, do it only after VERY careful consideration.

Let's say I did consider it VERY carefuly. Now all your references to unspoken "principles" and qualifiers like "almost" and "majority" and criticism of the code that you have never seen, fell apart.

The objective fact is this: the language allows something and it does not offer the complete support for that something. Whether that something is a good design in any particular context is another story. The language has a hole in its type system. It is that simple. I can accept any solution (even the draconian ones that you have mentioned), but not a lack of solution.

> >Yes. C++ got that part right.
> 
> You completely ignored my point about order of initialization,

Because I did not understand how package elaboration relate to constructing objects in the class hierarchy. I have understood that you wanted to show that Ada is cool in some other, unrelated areas.

> I don't think C++ (or any other 
> mainstream language) even tries to get that right...

The order of initialization of objects is very well defined in C++.
Or at least nobody has demonstrated any problem with it in this discussion.
I have, however, demonstrated a problem with the order of initialization in Ada.

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

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

* Re: Ada Annoyances
  2017-06-26 21:40                     ` Randy Brukardt
  2017-06-27  7:23                       ` Maciej Sobczak
@ 2017-06-27  7:26                       ` Dmitry A. Kazakov
  2017-06-27 20:41                         ` Randy Brukardt
  1 sibling, 1 reply; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-06-27  7:26 UTC (permalink / raw)


On 26/06/2017 23:40, Randy Brukardt wrote:
> "Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message
> news:71c4fdcd-4213-4b84-b852-c8674cfaf717@googlegroups.com...
> ...
>>> In Ada, where redispatching requires explicit work, the vast
>>> majority of constructors will never make a dispatching call so there is
>>> very little risk.
> 
>> The vast majority? Where does this statistics come from?
> 
> Common sense. Constructors shouldn't be doing anything complicated in the
> first place, so there's not much reason for delegation.

This is an argument for type-specific constructors actually. You cannot 
have it both ways.

And constructor could be quite complicated if you don't want to push 
initialization to the type's end user. In essence making an object fully 
functional is either a complication for the original designer of the 
type  once declared or a complication for a user unfamiliar with the 
implementation details asked to bring half-baked object in order. I 
really hate APIs that require a dozen of calls to make plus some On_Init 
callbacks to handle before I could do anything with an object.

[...]

> As I tried to say yesterday, Ada does have a flaw in that allows dispatching
> calls within contructors (and more generally, inside of any primitive
> operations). That requires work of some sort, but it is possible, and it
> shouldn't be.

Hmm, but what are you going to do about Rosen's trick? All use-cases 
where it is used (to work around language problems, constructors 
included) must be eliminated first. Only then re-dispatch could (and 
must) be outlawed.

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

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

* Re: Ada Annoyances
  2017-06-26 20:35                   ` Maciej Sobczak
  2017-06-26 21:40                     ` Randy Brukardt
@ 2017-06-27 15:19                     ` AdaMagica
  2017-06-27 16:32                       ` Dmitry A. Kazakov
  2017-06-28 13:15                       ` Maciej Sobczak
  1 sibling, 2 replies; 116+ messages in thread
From: AdaMagica @ 2017-06-27 15:19 UTC (permalink / raw)


Am Montag, 26. Juni 2017 22:35:34 UTC+2 schrieb Maciej Sobczak:
> The complete example (analogous to the C++ example I have written in the other post) is:
> 
> with Ada.Text_IO;
> with Ada.Finalization;
> 
> procedure Test is
>    
>    package P is
>       type Base is new Ada.Finalization.Limited_Controlled with null record;
>       
>       procedure Initialize (Obj : in out Base);
>       procedure VFoo (Obj : in Base);
>       
>       type Derived is new Base with null record;
>       
>       procedure Initialize (Obj : in out Derived);
>       procedure VFoo (Obj : in Derived);
>       
>       procedure Use_Object (Obj : in Base'Class);
>    end P;
>    ...
> 
> When executed, we get:
> 
> test with Base
>    call from Base's Initialize
>       Hello from Base
> test with Derived
>    call from Base's Initialize
>       Hello from Derived   <<<<<<< here are dragons!
>    call from Derived's Initialize
>       Hello from Derived

Yes, this *is* a problem. The reason are the initialize *procedures* and the view conversion.
The following uses *functions* instead (which behave more like C++'s constructors). This program works correctly just like the C++ version.

(It seems that there is a bug in Gnat here. See comments in the code.)

package Maciej is

  type Base is tagged record
    I: Integer;  -- Gnat bug? Need this lest call of Base'(Create) will be optimized away
  end record;
  function Create return Base;
  procedure Foo (X: Base);

  type Derived is new Base with null record;
  function Create return Derived;
  procedure Foo (X: Derived);

  procedure Use_Object (X: Base'Class);

end Maciej;
-----------
with Ada.Text_IO;

package body Maciej is

  -- Ada hasn't constructors comparable with those of C++.

  function Create return Base is
    B: Base := (I => 19);  -- Here, the C++ constructor would be called.
  begin
    Ada.Text_IO.Put_Line ("  Calling Use_Object from Base constructor:");
    Use_Object (B);
    return B;
  end Create;

  procedure Foo (X: Base) is
  begin
    Ada.Text_IO.Put_Line ("    Hello from Base object!");
  end Foo;

  function Create return Derived is
    D: Derived := (Base'(Create) with null record);
  begin
    Ada.Text_IO.Put_Line ("  Calling Use_Object from Derived constructor:");
    Use_Object (D);
    return D;
  end Create;

  procedure Foo (X: Derived) is
  begin
    Ada.Text_IO.Put_Line ("    Hello from Derived object!");
  end Foo;

  procedure Use_Object (X: Base'Class) is
  begin
    X.Foo;
  end Use_Object;

end Maciej;
-----------
with Ada.Text_IO;
with Maciej;

procedure Maciej_Main is
begin
  Ada.Text_IO.Put_Line ("Test with Base object:");
  declare
    B: Maciej.Base := Maciej.Create;
  begin
    null;
  end;
  Ada.Text_IO.New_Line;
  Ada.Text_IO.Put_Line ("Test with Derived object:");
  declare
    D: Maciej.Derived := Maciej.Create;
  begin
    null;
  end;
  Ada.Text_IO.New_Line;
  Ada.Text_IO.Put_Line ("Same again with procedures:");
  declare
    B: Maciej.Base;
  begin
    B.Create;
  end;
  declare
    D: Maciej.Derived;
  begin
    D.Create;
  end;

end Maciej_Main;

Test with Base object:
  Calling Use_Object from Base constructor:
    Hello from Base object!

Test with Derived object:
  Calling Use_Object from Base constructor:
    Hello from Base object!
  Calling Use_Object from Derived constructor:
    Hello from Derived object!

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

* Re: Ada Annoyances
  2017-06-27 15:19                     ` AdaMagica
@ 2017-06-27 16:32                       ` Dmitry A. Kazakov
  2017-06-28 13:15                       ` Maciej Sobczak
  1 sibling, 0 replies; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-06-27 16:32 UTC (permalink / raw)


On 2017-06-27 17:19, AdaMagica wrote:
> Am Montag, 26. Juni 2017 22:35:34 UTC+2 schrieb Maciej Sobczak:

>> When executed, we get:
>>
>> test with Base
>>     call from Base's Initialize
>>        Hello from Base
>> test with Derived
>>     call from Base's Initialize
>>        Hello from Derived   <<<<<<< here are dragons!
>>     call from Derived's Initialize
>>        Hello from Derived
> 
> Yes, this *is* a problem.

No, it is misunderstanding of what Initialize procedure is. It is a 
class-wide constructor and not a type-specific constructor like in C++. 
This is per language design, willingly or not. Therefore it is OK to 
dispatch from Initialize because:

1. All components are initialized
2. Initialize is overrides

If the intent is to use Initialize as a poor-mans substitute for a 
type-specific constructor, then you call parent's Initialize *and* you 
don't dispatch.

If you use it as a class-wide constructor you can dispatch but you don't 
call parent's part. Usually parents class-wide subroutines can be used 
to factor out common initialization code.

You can mix both approaches, but with utter care, because this is how 
mess starts.

> The following uses *functions* instead (which behave more like C++'s constructors).

Yes, if they return a specific type.

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


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

* Re: Ada Annoyances
  2017-06-27  7:23                       ` Maciej Sobczak
@ 2017-06-27 20:38                         ` Randy Brukardt
  2017-06-28  8:21                           ` Dmitry A. Kazakov
  2017-06-28 13:07                           ` Maciej Sobczak
  0 siblings, 2 replies; 116+ messages in thread
From: Randy Brukardt @ 2017-06-27 20:38 UTC (permalink / raw)


"Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message 
news:98197f40-9833-4bb8-87ca-1593d2da7c81@googlegroups.com...
>> >So guess how did I learn about it...
>>
>> You wrote some ill-advised Initialize routines?
>
>You cannot say it was ill-advised without knowing the context and purpose.

Of course I can. The purpose of the Initialize routine is to "fix-up" an 
existing initialized object (some sort of registration is the most likely), 
with the language-defined default initialization and/or a constructor 
function providing the actual initialization. It's not unlikely that someone 
might try to abuse that purpose, but that doesn't suddenly make such a usage 
less ill-advised. Again, the flaw in Ada here is that the purpose behind 
these routines (Initialize/Adjust/Finalize) isn't as obvious as it could be, 
and people coming from other languages do try to make them do things for 
which they are not intended. Not surprisingly, that causes problems.

...
>> Re-dispatching is almost
>> always evil, do it only after VERY careful consideration.

>Let's say I did consider it VERY carefuly.

Then you've also considered the negative side-effects and deem them to be 
acceptable.

>Now all your references to unspoken "principles" and qualifiers like 
>"almost" and
>"majority" and criticism of the code that you have never seen, fell apart.

I say "almost" because I don't believe in making absolutest statements. But 
if one uses Ada as it was intended, and don't try to fit designs from other 
languages into it, there aren't any problems here. If one goes too far 
outside the box, you can introduce problems, and that possibility is 
definitely a language flaw.

But all I see here is you trying to prove that C++ is better than Ada. If 
so, why are you wasting our time here? Go back to the evil empire and leave 
those of us that are trying to fix the universe alone. I'm done here.

                             Randy.




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

* Re: Ada Annoyances
  2017-06-27  7:26                       ` Dmitry A. Kazakov
@ 2017-06-27 20:41                         ` Randy Brukardt
  2017-06-28  7:57                           ` Dmitry A. Kazakov
  0 siblings, 1 reply; 116+ messages in thread
From: Randy Brukardt @ 2017-06-27 20:41 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:oit1at$2vo$1@gioia.aioe.org...
> On 26/06/2017 23:40, Randy Brukardt wrote:
...
>> As I tried to say yesterday, Ada does have a flaw in that allows 
>> dispatching
>> calls within contructors (and more generally, inside of any primitive
>> operations). That requires work of some sort, but it is possible, and it
>> shouldn't be.
>
> Hmm, but what are you going to do about Rosen's trick? All use-cases where 
> it is used (to work around language problems, constructors included) must 
> be eliminated first. Only then re-dispatch could (and must) be outlawed.

Avoid it? I've never used it in actual code, because it never seemed to save 
anything (and it forces using limited types, which I avoid as much as 
possible). I've always used an allocated "real-data-part" in the cases where 
the Rosen trick might have helped. So I can't really say anything 
intelligent here.

                                         Randy.



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

* Re: Ada Annoyances
  2017-06-27 20:41                         ` Randy Brukardt
@ 2017-06-28  7:57                           ` Dmitry A. Kazakov
  0 siblings, 0 replies; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-06-28  7:57 UTC (permalink / raw)


On 27/06/2017 22:41, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:oit1at$2vo$1@gioia.aioe.org...
>> On 26/06/2017 23:40, Randy Brukardt wrote:
> ...
>>> As I tried to say yesterday, Ada does have a flaw in that allows
>>> dispatching
>>> calls within contructors (and more generally, inside of any primitive
>>> operations). That requires work of some sort, but it is possible, and it
>>> shouldn't be.
>>
>> Hmm, but what are you going to do about Rosen's trick? All use-cases where
>> it is used (to work around language problems, constructors included) must
>> be eliminated first. Only then re-dispatch could (and must) be outlawed.
> 
> Avoid it? I've never used it in actual code, because it never seemed to save
> anything (and it forces using limited types, which I avoid as much as
> possible). I've always used an allocated "real-data-part" in the cases where
> the Rosen trick might have helped.

There are cases where I need it (or a class-wide discriminant similar to 
it):

1. Multiple inheritance emulated by mix-in. There is nothing wrong in 
proper mix-in, but in this case both objects are in fact the same one 
initialized at the same point with all problems following from that.

2. Components of [pointers to] task or protected type, since I cannot 
meaningfully use them via inheritance.

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


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

* Re: Ada Annoyances
  2017-06-27 20:38                         ` Randy Brukardt
@ 2017-06-28  8:21                           ` Dmitry A. Kazakov
  2017-06-28 20:50                             ` Randy Brukardt
  2017-06-28 13:07                           ` Maciej Sobczak
  1 sibling, 1 reply; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-06-28  8:21 UTC (permalink / raw)


On 27/06/2017 22:38, Randy Brukardt wrote:

> I say "almost" because I don't believe in making absolutest statements. But
> if one uses Ada as it was intended, and don't try to fit designs from other
> languages into it, there aren't any problems here.

I disagree. There are very serious problems with object 
initialization/finalization in Ada whatever pattern you use. Neither 
controlled nor constructing functions fulfill even reasonably minimal 
requirements on safety and usability. The problem is aggravated by the 
fact that you cannot foresee the consequences of any choice. It may hit 
you months later on the road in some descendant type. I had cases when I 
had to start over from scratch several times. The situation is 
absolutely unacceptable for Ada as a language for software engineering.

> But all I see here is you trying to prove that C++ is better than Ada.

That is a bit unfair.

He only said that C++'s initialization model is perfect. Well that is 
wrong. However true is that the language must support user-defined 
type-specific constructors, non-overridable and with parameters. This is 
not enough to make initialization working but it is a required part of it.

You say that Ada's initialization model is tolerable because there 
cannot be anything better. This is inconsistent with very notion of 
strong typing. If type safety cannot be supported we must say goodbye to 
strong types.

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


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

* Re: Ada Annoyances
  2017-06-27 20:38                         ` Randy Brukardt
  2017-06-28  8:21                           ` Dmitry A. Kazakov
@ 2017-06-28 13:07                           ` Maciej Sobczak
  1 sibling, 0 replies; 116+ messages in thread
From: Maciej Sobczak @ 2017-06-28 13:07 UTC (permalink / raw)


> >You cannot say it was ill-advised without knowing the context and purpose.
> 
> Of course I can. The purpose of the Initialize routine is to "fix-up" an 
> existing initialized object

I can understand that, but the name of this procedure does not convey this meaning. Even your own sentence above sounds illogical.

> Again, the flaw in Ada here is that the purpose behind 
> these routines (Initialize/Adjust/Finalize) isn't as obvious

There seems to be an agreement here.

> >Let's say I did consider it VERY carefuly.
> 
> Then you've also considered the negative side-effects

Which I was not aware of until I was hit by them.
(Interestingly, you could defend every single con of C++ the same way and ultimately prove that there are no problems with it. Beware, such arguments are double-edged swords.)

> But all I see here is you trying to prove that C++ is better than Ada. If 
> so, why are you wasting our time here?

On the contrary. Actually, I'm an official Ada advocate at my workplace. The problem is - you need to be *very* precise when discussing advantages of one language over another and there is absolutely no chance you will ever convince anybody to use Ada if you try to praise it by contrasting it with misunderstood flaws of C++ (or Java or whatever).

In this very discussion I have seen multiple statements that C++ is broken beyond all repair and the statement that particularly called my attention was about C++ being "untyped", while in fact the construction process there is relatively well thought-out and designed to preserve the type safety, which I tried to demonstrate. Another statement was about inability of C++ to suppress dispatching calls. This is when I have decided to play the devil's advocate and demonstrate that without proper arguments - and in particular without being fair and giving justice where it is due, you have no chance of convincing anybody. Ada is an interesting language for large-scale development, but it has its own share of language design flaws. It is unavoidable with such a long history, but at least be fair.

> Go back to the evil empire

To which one? :-)

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


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

* Re: Ada Annoyances
  2017-06-27 15:19                     ` AdaMagica
  2017-06-27 16:32                       ` Dmitry A. Kazakov
@ 2017-06-28 13:15                       ` Maciej Sobczak
  2017-06-28 14:05                         ` AdaMagica
  2017-06-28 20:53                         ` Randy Brukardt
  1 sibling, 2 replies; 116+ messages in thread
From: Maciej Sobczak @ 2017-06-28 13:15 UTC (permalink / raw)


> The following uses *functions* instead (which behave more like C++'s constructors).

No, C++ constructors have nothing to do with functions. They do not return anything and in particular within the class hierarchy, where the construction process has multiple stages and constructors operate on partial views on the target object, it is clear that they have little analogies with regular functions.

Still:

> This program works correctly just like the C++ version.
[...]

I like your example. It demonstrates that factory functions are better suited to implement the design intent that we have discussed.

> (It seems that there is a bug in Gnat here.

No language is perfect. :-)

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

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

* Re: Ada Annoyances
  2017-06-28 13:15                       ` Maciej Sobczak
@ 2017-06-28 14:05                         ` AdaMagica
  2017-06-29 21:17                           ` Robert A Duff
  2017-06-28 20:53                         ` Randy Brukardt
  1 sibling, 1 reply; 116+ messages in thread
From: AdaMagica @ 2017-06-28 14:05 UTC (permalink / raw)


Am Mittwoch, 28. Juni 2017 15:16:00 UTC+2 schrieb Maciej Sobczak:
> > The following uses *functions* instead (which behave more like C++'s constructors).
> 
> No, C++ constructors have nothing to do with functions. They do not return anything and in particular within the class hierarchy, where the construction process has multiple stages and constructors operate on partial views on the target object, it is clear that they have little analogies with regular functions.

That's all correct. My point was that your Initialize procedures were in no way comparable to C++ constructors, so your translation of C++ to Ada was questionable. The Ada functions' distance to constructors is far less. As I said in the comments of my example, there are no true constructors in Ada.

> Still:
>
> > This program works correctly just like the C++ version.
> [...]
>
> I like your example. It demonstrates that factory functions are better suited to implement the design intent that we have discussed.

That was my intent. With package Ada.Finalization, one has to be very careful to avoid such re-dispatching as in your example. When I created my example, I first used procedures like you did - and fell into the same trap.


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

* Re: Ada Annoyances
  2017-06-28  8:21                           ` Dmitry A. Kazakov
@ 2017-06-28 20:50                             ` Randy Brukardt
  2017-06-28 23:18                               ` Nasser M. Abbasi
  2017-06-29  7:15                               ` Dmitry A. Kazakov
  0 siblings, 2 replies; 116+ messages in thread
From: Randy Brukardt @ 2017-06-28 20:50 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:oivou5$cfh$1@gioia.aioe.org...
> On 27/06/2017 22:38, Randy Brukardt wrote:
...
> You say that Ada's initialization model is tolerable because there cannot 
> be anything better. This is inconsistent with very notion of strong 
> typing. If type safety cannot be supported we must say goodbye to strong 
> types.

OOP seems to me to be incompatible with strong typing. I'd rather say 
goodbye to OOP than to strong typing, but YMMV.

                                  Randy.



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

* Re: Ada Annoyances
  2017-06-28 13:15                       ` Maciej Sobczak
  2017-06-28 14:05                         ` AdaMagica
@ 2017-06-28 20:53                         ` Randy Brukardt
  1 sibling, 0 replies; 116+ messages in thread
From: Randy Brukardt @ 2017-06-28 20:53 UTC (permalink / raw)


"Maciej Sobczak" <see.my.homepage@gmail.com> wrote in message 
news:32bd3d2d-16d2-46f4-902f-3b6944f30226@googlegroups.com...
>...
>> (It seems that there is a bug in Gnat here.
>
>No language is perfect. :-)

Language /= implementation. Ada /= Gnat.

                      Randy.



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

* Re: Ada Annoyances
  2017-06-28 20:50                             ` Randy Brukardt
@ 2017-06-28 23:18                               ` Nasser M. Abbasi
  2017-06-29  7:27                                 ` Dmitry A. Kazakov
                                                   ` (2 more replies)
  2017-06-29  7:15                               ` Dmitry A. Kazakov
  1 sibling, 3 replies; 116+ messages in thread
From: Nasser M. Abbasi @ 2017-06-28 23:18 UTC (permalink / raw)


On 6/28/2017 3:50 PM, Randy Brukardt wrote:

> OOP seems to me to be incompatible with strong typing. I'd rather say
> goodbye to OOP than to strong typing, but YMMV.
> 
>                                    Randy.
> 

May be this is vindication that Niklaus Wirth was right
after all with his Language Pascal?  Strong typing, and
without OOP. Pascal Was perfect language for learning and
teaching also.

       Algorithms + Data Structures = Programs

Is all what was needed, and I still think that is true today.

Ada initially was almost like this when it came out and it
had no OOP, but Ada became much more complicated and complex with
time, adding more stuff to it including OOP.

One now needs almost a PhD in computer science and compiler theory
to fully understand and learn big languages like Ada and C++.

--Nasser
  


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

* Re: Ada Annoyances
  2017-06-28 20:50                             ` Randy Brukardt
  2017-06-28 23:18                               ` Nasser M. Abbasi
@ 2017-06-29  7:15                               ` Dmitry A. Kazakov
  2017-06-30  0:42                                 ` Randy Brukardt
  1 sibling, 1 reply; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-06-29  7:15 UTC (permalink / raw)


On 28/06/2017 22:50, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:oivou5$cfh$1@gioia.aioe.org...
>> On 27/06/2017 22:38, Randy Brukardt wrote:
> ...
>> You say that Ada's initialization model is tolerable because there cannot
>> be anything better. This is inconsistent with very notion of strong
>> typing. If type safety cannot be supported we must say goodbye to strong
>> types.
> 
> OOP seems to me to be incompatible with strong typing.

That depends on what you call OO. There is nothing new in OO except for 
types representing classes of related types. Why should that be 
incompatible with strong typing?

Then objects require initialization regardless presence of class types. 
Even if you remove inheritance there still be aggregation. How do I 
initialize an aggregate object?

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


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

* Re: Ada Annoyances
  2017-06-28 23:18                               ` Nasser M. Abbasi
@ 2017-06-29  7:27                                 ` Dmitry A. Kazakov
  2017-06-29 16:24                                 ` Jeffrey R. Carter
  2017-06-29 21:46                                 ` darkestkhan
  2 siblings, 0 replies; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-06-29  7:27 UTC (permalink / raw)


On 29/06/2017 01:18, Nasser M. Abbasi wrote:

>        Algorithms + Data Structures = Programs
> 
> Is all what was needed, and I still think that is true today.

That might be true if taken literally. But today we don't write programs 
on a napkin in short periods between torturing students. Alas, we must 
design software /= programs.

> Ada initially was almost like this when it came out and it
> had no OOP,

Ada 83 was called an "object-based" language.

> but Ada became much more complicated and complex with
> time, adding more stuff to it including OOP.
> 
> One now needs almost a PhD in computer science and compiler theory
> to fully understand and learn big languages like Ada and C++.

There are many reasons for complexity modern languages and processes 
have. Lack of sound theory is one of them. But the most important reason 
is that it no hobby anymore.

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

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

* Re: Ada Annoyances
  2017-06-28 23:18                               ` Nasser M. Abbasi
  2017-06-29  7:27                                 ` Dmitry A. Kazakov
@ 2017-06-29 16:24                                 ` Jeffrey R. Carter
  2017-06-29 16:51                                   ` Nasser M. Abbasi
  2017-07-04 23:40                                   ` Luke A. Guest
  2017-06-29 21:46                                 ` darkestkhan
  2 siblings, 2 replies; 116+ messages in thread
From: Jeffrey R. Carter @ 2017-06-29 16:24 UTC (permalink / raw)


On 06/29/2017 01:18 AM, Nasser M. Abbasi wrote:
> Pascal Was perfect language for learning and
> teaching also.

The US Military Academy did a controlled experiment that showed that Ada (83) 
was a better teaching language than Pascal, which they were using at the time. 
Pascal has many well known gotchas for beginners that Ada got right. The "Pascal 
subset" of Ada with packages seems like an excellent first language, though.

-- 
Jeff Carter
"I blow my nose on you."
Monty Python & the Holy Grail
03

---
This email has been checked for viruses by AVG.
http://www.avg.com


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

* Re: Ada Annoyances
  2017-06-29 16:24                                 ` Jeffrey R. Carter
@ 2017-06-29 16:51                                   ` Nasser M. Abbasi
  2017-07-04 23:40                                   ` Luke A. Guest
  1 sibling, 0 replies; 116+ messages in thread
From: Nasser M. Abbasi @ 2017-06-29 16:51 UTC (permalink / raw)


On 6/29/2017 11:24 AM, Jeffrey R. Carter wrote:
> On 06/29/2017 01:18 AM, Nasser M. Abbasi wrote:
>> Pascal Was perfect language for learning and
>> teaching also.
> 
> The US Military Academy did a controlled experiment that showed that Ada (83)
> was a better teaching language than Pascal, which they were using at the time.
> Pascal has many well known gotchas for beginners that Ada got right. The "Pascal
> subset" of Ada with packages seems like an excellent first language, though.
> 

Sure, I can believe that. As I said, for me, Ada 83 was
a "better" Pascal.

It was at the right level for providing structured programming
with strong typing.

But Ada has got a lot bigger and more complex with time. All
languages seem to be inflicted by this disease. Look at Fortran
today for example, with all the OOP and other features they
added to it. Fortran which used to be one of the simplest
languages now has become as complicated of a language as Ada
and C++ !

--Nasser

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

* Re: Ada Annoyances
  2017-06-26 21:47             ` Randy Brukardt
  2017-06-26 22:23               ` Dmitry A. Kazakov
@ 2017-06-29 19:00               ` Niklas Holsti
  2017-06-29 21:29                 ` Robert A Duff
  2017-06-30  0:47                 ` Randy Brukardt
  1 sibling, 2 replies; 116+ messages in thread
From: Niklas Holsti @ 2017-06-29 19:00 UTC (permalink / raw)


On 17-06-27 00:47 , Randy Brukardt wrote:
> "Niklas Holsti" <niklas.holsti@tidorum.invalid> wrote in message
> news:erd8jiFhsroU1@mid.individual.net...
>> On 17-06-26 02:43 , Randy Brukardt wrote:
> ...
>>>> Point (b) is more difficult and I know of no work-around that can be
>>>> applied at analysis time.
>>>
>>> Simply banning the use of T'Class has that effect.
>>
>> At design and compilation time, yes, with consequent restrictions on the
>> design. But it is not a work-around that allows static analysis of
>> programs which do use T'Class.
>
> There's no free lunch! T'Class is by definition "indefinite", since existing
> code already compiled has to be able to handle newly defined types
> (including those that don't yet exist). That's never going to allow
> conventional static analysis.

As already appeared in other posts, the aim of the proposed Maximum_Size 
aspect is to make this T'Class type behave as a definite type. The rules 
for Maximum_Size would have to be defined in such a way that a change of 
the Maximum_Size value would force recompilation of any code depending 
on the value.

>> My hope is that a Maximum_Size aspect would let one manipulate class-wide
>> objects in the same "definite" way as is possible for variant records with
>> a default discriminant value. However, it would require that the tag of an
>> object could be changed by assignment; this is perhaps too radical a
>> change in the tagged object semantics.
>
> That seems way too drastic a change.

There is a parallel with the ability or inability to change the 
discriminants of a record-type object, which depends on the presence of 
default values for the discriminant, that is, on whether the object is 
unconstrained or constrained.

> I could imagine an aspect like the one
> you proposed to get rid of the indirection, but changing the semantics in a
> major way seems to be more than aspects are supposed to do.

I understand. However, I think I will write up the suggestion for 
ada-comment, to get it on the record.

> And changing the tag via assignment means having to be prepared to
> change finalization of  objects after the fact as well. Ugh.

Isn't finalization of local objects usually implemented by creating a 
list of these objects, and then traversing that list on scope exit? It 
seems to me that changing the tag of an object on the list should not be 
a problem; the new tag would just lead to a different Finalize, through 
normal dispatching.

But perhaps there are other implementations where the particular 
Finalize operation for a local object is determined when the 
local-object declaration is elaborated, and therefore corresponds to the 
initial tag value?

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


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

* Re: Ada Annoyances
  2017-06-23 19:21       ` Niklas Holsti
                           ` (2 preceding siblings ...)
  2017-06-25 23:43         ` Randy Brukardt
@ 2017-06-29 21:12         ` Robert A Duff
  2017-07-04 19:30           ` Niklas Holsti
  3 siblings, 1 reply; 116+ messages in thread
From: Robert A Duff @ 2017-06-29 21:12 UTC (permalink / raw)


Niklas Holsti <niklas.holsti@tidorum.invalid> writes:

> There are two reasons why tagged types hamper such analysis:

As Randy pointed out, it is more correct to say that class-wide types do
that.  Tagged types by themselves do not cause these problems.
Tagged types without class-wide types are not super useful,
but they are somewhat useful.

> a) dispatching calls (as you said), where the actual callee is
> determined by run-time values (tags) which are hard to predict by static
> analysis
>
> b) the non-static size of class-wide objects (of type T'Class), which
> means that the compiler and/or the programmer must use dynamic
> allocation (usually heap or secondary stack) for such objects.
...
> For some time, I have had in mind a possible Ada extension to solve
> point (b): an attribute/aspect that would let the programmer set a
> static upper bound on the size of any object in T'Class. If we call this
> aspect Maximum_Size (or perhaps Maximum_Size'Class), the programmer
> could use it like this:
>
>    type Root is tagged record ... end record
>    with Maximum_Size => 128;

Something like that was considered and rejected for Ada 9X.
Part of the problem is that it seems so low level to be talking
about sizes.  It's not even portable.  And not maintainable -- if you
delete a big type, or make it smaller, you're now wasting space.

It would be better to have the compiler compute the maximum
size needed.  That  would require the compiler to do a fairly
global analysis, which is something Ada compilers are not
set up to do.

>    type Object_List is array (List_Index) of Root'Class;
>
>    type Object_Pair is record
>       A, B : Root'Class;
>    end record;

Would you allow:

    X : Object_List (1..10);
    Y : Object_Pair;

?  If so, what is the 'Tag of the various components?
"Undefined" is not a very satisfying answer.

These things are analogous to records with defaulted discriminants.
The language makes some (unsuccessful!) attempt to prevent
uninitialized discriminants.

- Bob

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

* Re: Ada Annoyances
  2017-06-28 14:05                         ` AdaMagica
@ 2017-06-29 21:17                           ` Robert A Duff
  2017-06-30  7:44                             ` Dmitry A. Kazakov
  0 siblings, 1 reply; 116+ messages in thread
From: Robert A Duff @ 2017-06-29 21:17 UTC (permalink / raw)


AdaMagica <christ-usch.grein@t-online.de> writes:

>... there are no true constructors in Ada.

I've asked this before, without getting a clear answer: What constitutes
a "true constructor"?  I understand the problem with dispatching to
things whose parts haven't been initialized yet.  But what I'm looking
for is a definition of what a "true constructor" is.

Which programming languages have true constructors?
C++ constructors have some (different) problems.

- Bob

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

* Re: Ada Annoyances
  2017-06-29 19:00               ` Niklas Holsti
@ 2017-06-29 21:29                 ` Robert A Duff
  2017-06-30  0:50                   ` Randy Brukardt
  2017-07-04 19:32                   ` Niklas Holsti
  2017-06-30  0:47                 ` Randy Brukardt
  1 sibling, 2 replies; 116+ messages in thread
From: Robert A Duff @ 2017-06-29 21:29 UTC (permalink / raw)


Niklas Holsti <niklas.holsti@tidorum.invalid> writes:

> Isn't finalization of local objects usually implemented by creating a
> list of these objects, and then traversing that list on scope exit?

No.  That method was used originally by GNAT, but it was changed to
a simpler and much more efficient method.

Consider a record with defaulted discriminants.  The set of components
of that record that have finalization can change when the discriminant
changes.  That's complicated if you're keeping lists of those
components.

If you want to see how GNAT does it now, use the -gnatDGL switch
to compile some examples.  Look for procedures ending in "DI" ("deep
initialize") and "DF" ("deep finalize").

Lists are used only for heap objects that need finalization,
and not for their subcomponents.

>...It
> seems to me that changing the tag of an object on the list should not be
> a problem; the new tag would just lead to a different Finalize, through
> normal dispatching.

I agree, I don't see a problem here.  When Finalize is called, it
dispatches via the currrent Tag.  Tags can't change in Ada, but if they
could it would still dispatch via the Tag value present when Finalize is
called.

> But perhaps there are other implementations where the particular
> Finalize operation for a local object is determined when the
> local-object declaration is elaborated, and therefore corresponds to the
> initial tag value?

I don't know of any such.

- Bob

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

* Re: Ada Annoyances
  2017-06-28 23:18                               ` Nasser M. Abbasi
  2017-06-29  7:27                                 ` Dmitry A. Kazakov
  2017-06-29 16:24                                 ` Jeffrey R. Carter
@ 2017-06-29 21:46                                 ` darkestkhan
  2 siblings, 0 replies; 116+ messages in thread
From: darkestkhan @ 2017-06-29 21:46 UTC (permalink / raw)


On Wednesday, June 28, 2017 at 11:18:26 PM UTC, Nasser M. Abbasi wrote:
> On 6/28/2017 3:50 PM, Randy Brukardt wrote:
> 
> > OOP seems to me to be incompatible with strong typing. I'd rather say
> > goodbye to OOP than to strong typing, but YMMV.
> > 
> >                                    Randy.
> > 
> 
> May be this is vindication that Niklaus Wirth was right
> after all with his Language Pascal?  Strong typing, and
> without OOP. Pascal Was perfect language for learning and
> teaching also.
> 
>        Algorithms + Data Structures = Programs
> 
> Is all what was needed, and I still think that is true today.
> 
> Ada initially was almost like this when it came out and it
> had no OOP, but Ada became much more complicated and complex with
> time, adding more stuff to it including OOP.
> 
> One now needs almost a PhD in computer science and compiler theory
> to fully understand and learn big languages like Ada and C++.
> 
> --Nasser

I don't think that Ada is that complicated - at least not from user's perspective. Modern languages tend to be bigger than old ones due to the size and scope of problems solved today. Back in the days 20M lines of code was unimagineable, nowadays there are more and more projects that cross this line. Beside it is not like Ada forces you to use tagged types or OOP.

darkestkhan

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

* Re: Ada Annoyances
  2017-06-29  7:15                               ` Dmitry A. Kazakov
@ 2017-06-30  0:42                                 ` Randy Brukardt
  2017-06-30  7:36                                   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 116+ messages in thread
From: Randy Brukardt @ 2017-06-30  0:42 UTC (permalink / raw)


>Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
>news:oj29fa$m41$1@gioia.aioe.org...
> On 28/06/2017 22:50, Randy Brukardt wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>> news:oivou5$cfh$1@gioia.aioe.org...
>>> On 27/06/2017 22:38, Randy Brukardt wrote:
>> ...
>>> You say that Ada's initialization model is tolerable because there 
>>> cannot
>>> be anything better. This is inconsistent with very notion of strong
>>> typing. If type safety cannot be supported we must say goodbye to strong
>>> types.
>>
>> OOP seems to me to be incompatible with strong typing.
>
> That depends on what you call OO. There is nothing new in OO except for 
> types representing classes of related types. Why should that be 
> incompatible with strong typing?

???  Both type extension and dynamic dispatching are unique to OOP. (You 
could emulate them with composition, but that doesn't do the same violence 
to strong typing.)

                              Randy.


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

* Re: Ada Annoyances
  2017-06-29 19:00               ` Niklas Holsti
  2017-06-29 21:29                 ` Robert A Duff
@ 2017-06-30  0:47                 ` Randy Brukardt
  2017-06-30 18:45                   ` Niklas Holsti
  1 sibling, 1 reply; 116+ messages in thread
From: Randy Brukardt @ 2017-06-30  0:47 UTC (permalink / raw)


"Niklas Holsti" <niklas.holsti@tidorum.invalid> wrote in message 
news:erl137Fp39dU1@mid.individual.net...
> On 17-06-27 00:47 , Randy Brukardt wrote:
...
>> And changing the tag via assignment means having to be prepared to
>> change finalization of  objects after the fact as well. Ugh.
>
> Isn't finalization of local objects usually implemented by creating a list 
> of these objects, and then traversing that list on scope exit? It seems to 
> me that changing the tag of an object on the list should not be a problem; 
> the new tag would just lead to a different Finalize, through normal 
> dispatching.

That's not a problem. The case I was thinking about was one where the change 
in tag caused an object which was not previously controlled to become 
controlled. Then the object would have to be added to the finalization list, 
but not to the head, but rather to the exact point where the original object 
was declared. That would be very difficult.

I just spent most of the winter fixing a bug related to that for variant 
records in Janus/Ada, and this case would be worse (because there's no 
enclosing object in which to put helper components).

                                      Randy.
       . 



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

* Re: Ada Annoyances
  2017-06-29 21:29                 ` Robert A Duff
@ 2017-06-30  0:50                   ` Randy Brukardt
  2017-07-03 20:39                     ` Robert A Duff
  2017-07-04 19:32                   ` Niklas Holsti
  1 sibling, 1 reply; 116+ messages in thread
From: Randy Brukardt @ 2017-06-30  0:50 UTC (permalink / raw)


"Robert A Duff" <bobduff@TheWorld.com> wrote in message 
news:wcca84q5vq1.fsf@TheWorld.com...
> Niklas Holsti <niklas.holsti@tidorum.invalid> writes:
...
> I agree, I don't see a problem here.  When Finalize is called, it
> dispatches via the currrent Tag.  Tags can't change in Ada, but if they
> could it would still dispatch via the Tag value present when Finalize is
> called.

That's not the problem. The problem is knowing whether to call Finalize at 
all. The only solution I could see for the GNAT approach is to treat all 
tagged objects as controlled (using a null Finalize in cause the object 
isn't controlled). That's expensive.

For a list-based approach (like the one Janus/Ada uses), I don't see any 
solution at all. Putting every tagged object on the finalization lists would 
be prohibitively expensive.

                         Randy.



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

* Re: Ada Annoyances
  2017-06-30  0:42                                 ` Randy Brukardt
@ 2017-06-30  7:36                                   ` Dmitry A. Kazakov
  0 siblings, 0 replies; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-06-30  7:36 UTC (permalink / raw)


On 30/06/2017 02:42, Randy Brukardt wrote:
>> Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>> news:oj29fa$m41$1@gioia.aioe.org...
>> On 28/06/2017 22:50, Randy Brukardt wrote:
>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>>> news:oivou5$cfh$1@gioia.aioe.org...
>>>> On 27/06/2017 22:38, Randy Brukardt wrote:
>>> ...
>>>> You say that Ada's initialization model is tolerable because there
>>>> cannot
>>>> be anything better. This is inconsistent with very notion of strong
>>>> typing. If type safety cannot be supported we must say goodbye to strong
>>>> types.
>>>
>>> OOP seems to me to be incompatible with strong typing.
>>
>> That depends on what you call OO. There is nothing new in OO except for
>> types representing classes of related types. Why should that be
>> incompatible with strong typing?
> 
> ???  Both type extension and dynamic dispatching are unique to OOP. (You
> could emulate them with composition, but that doesn't do the same violence
> to strong typing.)

I meant the second. The first is rather an implementation detail. The 
derived type need not to inherit the parent's representation.

I don't see why either should have any effect on strong typing. Ada 95 
perfectly resolved the problem.

(It is like saying that numeric types are bad for strong typing because 
in FORTRAN you could pass INTEGER*4 for REAL*8.)

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

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

* Re: Ada Annoyances
  2017-06-29 21:17                           ` Robert A Duff
@ 2017-06-30  7:44                             ` Dmitry A. Kazakov
  2017-06-30  7:49                               ` J-P. Rosen
  0 siblings, 1 reply; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-06-30  7:44 UTC (permalink / raw)


On 29/06/2017 23:17, Robert A Duff wrote:
> AdaMagica <christ-usch.grein@t-online.de> writes:
> 
>> ... there are no true constructors in Ada.
> 
> I've asked this before, without getting a clear answer: What constitutes
> a "true constructor"?

A true constructor is a piece of user-defined code (not a subprogram or 
operation!) implicitly called before the first use of the object.

> Which programming languages have true constructors?
> C++ constructors have some (different) problems.

Regardless of their problems C++ constructors are true constructors.

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


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

* Re: Ada Annoyances
  2017-06-30  7:44                             ` Dmitry A. Kazakov
@ 2017-06-30  7:49                               ` J-P. Rosen
  2017-06-30  8:28                                 ` Dmitry A. Kazakov
  0 siblings, 1 reply; 116+ messages in thread
From: J-P. Rosen @ 2017-06-30  7:49 UTC (permalink / raw)


Le 30/06/2017 à 09:44, Dmitry A. Kazakov a écrit :
> A true constructor is a piece of user-defined code (not a subprogram or
> operation!) implicitly called before the first use of the object.
So, the only problem you have with Ada constructors is that they don't
require a special syntax? Strange!

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

* Re: Ada Annoyances
  2017-06-30  7:49                               ` J-P. Rosen
@ 2017-06-30  8:28                                 ` Dmitry A. Kazakov
  2017-06-30 10:14                                   ` J-P. Rosen
  0 siblings, 1 reply; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-06-30  8:28 UTC (permalink / raw)


On 30/06/2017 09:49, J-P. Rosen wrote:
> Le 30/06/2017 à 09:44, Dmitry A. Kazakov a écrit :
>> A true constructor is a piece of user-defined code (not a subprogram or
>> operation!) implicitly called before the first use of the object.
> So, the only problem you have with Ada constructors is that they don't
> require a special syntax? Strange!

That is not syntax. There is just no such thing in Ada:

1. For any type T I declare, I must be able to define a constructor. 
This includes T'Class.

2. For controlled types Initialize is not a constructor because it is 
not always called and because it can be called explicitly out of place.

And I must be able to provide parameters to constructors.

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


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

* Re: Ada Annoyances
  2017-06-30  8:28                                 ` Dmitry A. Kazakov
@ 2017-06-30 10:14                                   ` J-P. Rosen
  2017-06-30 10:30                                     ` Dmitry A. Kazakov
  0 siblings, 1 reply; 116+ messages in thread
From: J-P. Rosen @ 2017-06-30 10:14 UTC (permalink / raw)


Le 30/06/2017 à 10:28, Dmitry A. Kazakov a écrit :
> That is not syntax. There is just no such thing in Ada:
> 
> 1. For any type T I declare, I must be able to define a constructor.
> This includes T'Class.
> 
> 2. For controlled types Initialize is not a constructor because it is
> not always called and because it can be called explicitly out of place.
> 
> And I must be able to provide parameters to constructors.
And this is all doable with regular functions.

Therefore, it continue to think that the only problem you have with Ada
constructors is that they don't require a special syntax...
-- 
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] 116+ messages in thread

* Re: Ada Annoyances
  2017-06-30 10:14                                   ` J-P. Rosen
@ 2017-06-30 10:30                                     ` Dmitry A. Kazakov
  0 siblings, 0 replies; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-06-30 10:30 UTC (permalink / raw)


On 30/06/2017 12:14, J-P. Rosen wrote:
> Le 30/06/2017 à 10:28, Dmitry A. Kazakov a écrit :
>> That is not syntax. There is just no such thing in Ada:
>>
>> 1. For any type T I declare, I must be able to define a constructor.
>> This includes T'Class.
>>
>> 2. For controlled types Initialize is not a constructor because it is
>> not always called and because it can be called explicitly out of place.
>>
>> And I must be able to provide parameters to constructors.
> And this is all doable with regular functions.

Not even close. Constructing functions do not work for anything beyond 
simple examples. Even if they worked, they are unsafe, e.g. in private 
bodies.

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


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

* Re: Ada Annoyances
  2017-06-23 17:49     ` Randy Brukardt
  2017-06-23 19:21       ` Niklas Holsti
  2017-06-23 19:22       ` Niklas Holsti
@ 2017-06-30 15:02       ` Norman Worth
  2017-06-30 23:49         ` pythoner6
  2 siblings, 1 reply; 116+ messages in thread
From: Norman Worth @ 2017-06-30 15:02 UTC (permalink / raw)


Randy Brukardt wrote:
> <raph.amiard@gmail.com> wrote in message
> news:be1619b4-2220-4287-8e67-1af32377d3f7@googlegroups.com...
> ...
>> Ada forcing tagged types on you to use certain features *is* a problem, if
>> only
>> because certain Ada users are forbidden to use tagged types altogether and
>> thus
>> are prevented to use a lot of useful features.
>
> Stupid language usage rules are not the problem of the language design,
> they're a management problem. I can understand banning T'Class (thus banning
> dynamic dispatching) and banning controlled types (thus banning hidden calls
> that can be harder to analyze), but not banning tagged types themselves.
> Indeed, (almost) all new types should be tagged - as Tucker said often
> during the Ada 9x development, "Tagged types work right"; for the most part,
> regular record types don't "work right" for various things and that can't be
> fixed because compatibility concerns. (Although Ada 2012 did bite the bullet
> about equality; that may be a significant reason why there is only one Ada
> 2012 compiler to date.)
>
>                                                Randy.
>
>
Programmers should stop trying to write C++ in Ada.  For the most part, 
it doesn't work.  Where it is forced, it is ugly and unreliable.

You should not use tagged types where they are not needed.  It messes up 
the code.  In general, if you are not going to have derived types, the 
base type should not be tagged.  It's easy enough to change if you 
change your mind, but that means you didn't think things out fully.

Tagged types really do work, for the most part.  And Ada compilers are 
very smart about when they can use static calls and when dispatching is 
really needed.

Using a tagged type for Ada.Controlled was a natural way of implementing it.


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

* Re: Ada Annoyances
  2017-06-30  0:47                 ` Randy Brukardt
@ 2017-06-30 18:45                   ` Niklas Holsti
  2017-06-30 20:06                     ` Robert A Duff
  0 siblings, 1 reply; 116+ messages in thread
From: Niklas Holsti @ 2017-06-30 18:45 UTC (permalink / raw)


On 17-06-30 03:47 , Randy Brukardt wrote:
> "Niklas Holsti" <niklas.holsti@tidorum.invalid> wrote in message
> news:erl137Fp39dU1@mid.individual.net...
>> On 17-06-27 00:47 , Randy Brukardt wrote:
> ...
>>> And changing the tag via assignment means having to be prepared to
>>> change finalization of  objects after the fact as well. Ugh.
>>
>> Isn't finalization of local objects usually implemented by creating a list
>> of these objects, and then traversing that list on scope exit? It seems to
>> me that changing the tag of an object on the list should not be a problem;
>> the new tag would just lead to a different Finalize, through normal
>> dispatching.
>
> That's not a problem. The case I was thinking about was one where the change
> in tag caused an object which was not previously controlled to become
> controlled.

I don't see how that could happen. In the changes I am suggesting (for 
the Maximum_Size aspect), the old and new tags would be in the same 
T'Class (the one to which the Maximum_Size aspect applies), and the type 
T would then either be derived from a Controlled parent, or not. So it 
seems to me that the object's controlled/uncontrolled status could not 
be changed by such a change of tag.

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

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

* Re: Ada Annoyances
  2017-06-30 18:45                   ` Niklas Holsti
@ 2017-06-30 20:06                     ` Robert A Duff
  0 siblings, 0 replies; 116+ messages in thread
From: Robert A Duff @ 2017-06-30 20:06 UTC (permalink / raw)


Niklas Holsti <niklas.holsti@tidorum.invalid> writes:

> I don't see how that could happen. In the changes I am suggesting (for
> the Maximum_Size aspect), the old and new tags would be in the same
> T'Class (the one to which the Maximum_Size aspect applies), and the type
> T would then either be derived from a Controlled parent, or not. So it
> seems to me that the object's controlled/uncontrolled status could not
> be changed by such a change of tag.

True, but you can add a component that is controlled.
So the outer object is not controlled, but it needs nontrivial
finalization.

- Bob

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

* Re: Ada Annoyances
  2017-06-30 15:02       ` Norman Worth
@ 2017-06-30 23:49         ` pythoner6
  2017-07-03  0:04           ` Randy Brukardt
  0 siblings, 1 reply; 116+ messages in thread
From: pythoner6 @ 2017-06-30 23:49 UTC (permalink / raw)


On Friday, June 30, 2017 at 11:02:48 AM UTC-4, Norman Worth wrote:
> You should not use tagged types where they are not needed.  It messes up 
> the code.  In general, if you are not going to have derived types, the 
> base type should not be tagged.  

In some cases you do not have a choice; this is why I started this thread in the first place. If you want to define custom indexing, custom iteration or use the object.method() syntax, you must use tagged types, regardless of whether or not you really need tagged types. It seems odd to me that you must pay an unnecessary cost to use these features just because the language says so (perhaps there is a reason behind the decision, but I can't see why), even if that cost is small.

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

* Re: Ada Annoyances
  2017-06-30 23:49         ` pythoner6
@ 2017-07-03  0:04           ` Randy Brukardt
  2017-07-03 17:47             ` Jere
  0 siblings, 1 reply; 116+ messages in thread
From: Randy Brukardt @ 2017-07-03  0:04 UTC (permalink / raw)


(1) Untagged primitive operations can be overridden "late", that causes 
problems for anything that calls them indirectly. Perhaps it could have been 
made to work, but it was more work for a feature that some people thought 
was marginal; probably it would have been dropped rather than getting more 
complicated.

(2) Iteration is defined in terms of an interface, so by definition it only 
works with tagged types. Perhaps we should have not tried to build on other 
language features and just made iteration magic all the way (it certainly 
would have been easier to use that way), but taggedness is a consequence of 
that.

(3) Since prefixed notation does automatic dereferencing and referencing 
(that is, .all and 'Access), allowing it on all types caused levels of 
ambiguity (and potentially infinite regress). It was easier to just define 
it on tagged types, which didn't have those issues. Perhaps it could have 
been made to work, but it was more work for a feature that already had 
significant opposition; probably it would have been dropped rather than 
getting more complicated. (Sound like a broken record??)

Note that for versions of Ada prior to Ada 2012, you have to use tagged 
types if you expect "=" to work right. Untagged record "=" does not compose 
in original Ada. We eventually decided to fix that, but the fix means that 
substantial existing code won't compile with Ada 2012 (most of it didn't do 
what the author intended anyway, so whether that is a bad thing is hard to 
say).

And of course if you need controlled types, you have to use tagged types. If 
you want any type extension (regardless of whether any dispatching or 
inheritance is involved), you have to use tagged types.

So you have to use tagged types in most circumstances in Ada 2012. And given 
that the extra cost is a word or two per object, the overhead is 
insignificant in most cases. (The cases where it matters, tiny non-private 
objects that are used in large quantities, are those for which the missing 
features aren't usable anyway.)

The real problem here is keeping compatibility with the messed-up 
definitions of untagged types in Ada; the most sensible thing to do would be 
to make all types effectively tagged (Dmitry likes to tell everyone how it 
ought to work), but that would be incompatible in many overriding cases. It 
would make more sense for Ada'Succ.

                               Randy.

<pythoner6@gmail.com> wrote in message 
news:3df6404a-588d-4e2d-a189-1d1e32ce9f5d@googlegroups.com...
On Friday, June 30, 2017 at 11:02:48 AM UTC-4, Norman Worth wrote:
> You should not use tagged types where they are not needed.  It messes up
> the code.  In general, if you are not going to have derived types, the
> base type should not be tagged.

In some cases you do not have a choice; this is why I started this thread in 
the first place. If you want to define custom indexing, custom iteration or 
use the object.method() syntax, you must use tagged types, regardless of 
whether or not you really need tagged types. It seems odd to me that you 
must pay an unnecessary cost to use these features just because the language 
says so (perhaps there is a reason behind the decision, but I can't see 
why), even if that cost is small. 


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

* Re: Ada Annoyances
  2017-07-03  0:04           ` Randy Brukardt
@ 2017-07-03 17:47             ` Jere
  2017-07-03 19:43               ` Dmitry A. Kazakov
  2017-07-04  2:18               ` Randy Brukardt
  0 siblings, 2 replies; 116+ messages in thread
From: Jere @ 2017-07-03 17:47 UTC (permalink / raw)


On Sunday, July 2, 2017 at 8:04:56 PM UTC-4, Randy Brukardt wrote:
> (3) Since prefixed notation does automatic dereferencing and referencing 
> (that is, .all and 'Access), allowing it on all types caused levels of 
> ambiguity (and potentially infinite regress). It was easier to just define 
> it on tagged types, which didn't have those issues. Perhaps it could have 
> been made to work, but it was more work for a feature that already had 
> significant opposition; probably it would have been dropped rather than 
> getting more complicated. (Sound like a broken record??)

Was there any consideration to having prefixed notation to 
apply to all record types and add a way to denote that a private 
type is a record type (there should be many ways to do that)? 
We don't really need it on all types, just record types.

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

* Re: Ada Annoyances
  2017-07-03 17:47             ` Jere
@ 2017-07-03 19:43               ` Dmitry A. Kazakov
  2017-07-04  2:18               ` Randy Brukardt
  1 sibling, 0 replies; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-07-03 19:43 UTC (permalink / raw)


On 2017-07-03 19:47, Jere wrote:
> On Sunday, July 2, 2017 at 8:04:56 PM UTC-4, Randy Brukardt wrote:
>> (3) Since prefixed notation does automatic dereferencing and referencing
>> (that is, .all and 'Access), allowing it on all types caused levels of
>> ambiguity (and potentially infinite regress). It was easier to just define
>> it on tagged types, which didn't have those issues. Perhaps it could have
>> been made to work, but it was more work for a feature that already had
>> significant opposition; probably it would have been dropped rather than
>> getting more complicated. (Sound like a broken record??)
> 
> Was there any consideration to having prefixed notation to
> apply to all record types and add a way to denote that a private
> type is a record type (there should be many ways to do that)?
> We don't really need it on all types, just record types.

This falls under the category "abstract record interface". You declare 
that a type implements the interface. Members ".XXX" are interface's 
abstract operations to be implemented as procedures/functions/components.

You know already the answer: not to happen.

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


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

* Re: Ada Annoyances
  2017-06-30  0:50                   ` Randy Brukardt
@ 2017-07-03 20:39                     ` Robert A Duff
  2017-07-04 19:52                       ` Niklas Holsti
  0 siblings, 1 reply; 116+ messages in thread
From: Robert A Duff @ 2017-07-03 20:39 UTC (permalink / raw)


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

> "Robert A Duff" <bobduff@TheWorld.com> wrote in message 
> news:wcca84q5vq1.fsf@TheWorld.com...
>> Niklas Holsti <niklas.holsti@tidorum.invalid> writes:
> ...
>> I agree, I don't see a problem here.  When Finalize is called, it
>> dispatches via the currrent Tag.  Tags can't change in Ada, but if they
>> could it would still dispatch via the Tag value present when Finalize is
>> called.
>
> That's not the problem. The problem is knowing whether to call Finalize at 
> all. The only solution I could see for the GNAT approach is to treat all 
> tagged objects as controlled (using a null Finalize in cause the object 
> isn't controlled). That's expensive.

In this fictional/future version of Ada, I presume the Tag of an object
could only change if it's a class-wide object.  So you don't have to
finalize all tagged objects -- just class-wide ones, and that's
essentially what GNAT is doing anyway.  E.g. if you say:

    X : T'Class := F(...);

the compiler doesn't know whether X contains controlled subcomponents,
so it does a dispatching call to a compiler-generated primitive of T,
which finalizes components, or does nothing.

GNAT can optimize that away if you use the No_Finalization restriction.
Maybe also the Disable_Controlled aspect on a type -- not sure about
that.

> For a list-based approach (like the one Janus/Ada uses), I don't see any 
> solution at all. Putting every tagged object on the finalization lists would 
> be prohibitively expensive.

Again, not every tagged object, just every class-wide object.

Actually, not even that.  Just every class-wide object that
uses this new feature.  It would be known at the root of
the type hierarchy whether Tags can change.  So there's no
distributed overhead.

- Bob


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

* Re: Ada Annoyances
  2017-07-03 17:47             ` Jere
  2017-07-03 19:43               ` Dmitry A. Kazakov
@ 2017-07-04  2:18               ` Randy Brukardt
  2017-12-17 13:47                 ` Prefixed notation for non tagged types Jere
  1 sibling, 1 reply; 116+ messages in thread
From: Randy Brukardt @ 2017-07-04  2:18 UTC (permalink / raw)


"Jere" <jhb.chat@gmail.com> wrote in message 
news:73b4a9bd-1f3b-42b9-9ef7-5303b0a88794@googlegroups.com...
> On Sunday, July 2, 2017 at 8:04:56 PM UTC-4, Randy Brukardt wrote:
>> (3) Since prefixed notation does automatic dereferencing and referencing
>> (that is, .all and 'Access), allowing it on all types caused levels of
>> ambiguity (and potentially infinite regress). It was easier to just 
>> define
>> it on tagged types, which didn't have those issues. Perhaps it could have
>> been made to work, but it was more work for a feature that already had
>> significant opposition; probably it would have been dropped rather than
>> getting more complicated. (Sound like a broken record??)
>
> Was there any consideration to having prefixed notation to
> apply to all record types and add a way to denote that a private
> type is a record type (there should be many ways to do that)?
> We don't really need it on all types, just record types.

Not that I recall, but requiring an indication that a private type is 
completed by a record seems like noise (99% of private types are completed 
by some sort of record as it is). It would be better the other way around 
(indicate when it is *not* completed by a record), but of course that would 
be incompatible. Still seems best for Ada'Succ.

                                          Randy.


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

* Re: Ada Annoyances
  2017-06-29 21:12         ` Robert A Duff
@ 2017-07-04 19:30           ` Niklas Holsti
  2017-07-05 20:03             ` Robert A Duff
  0 siblings, 1 reply; 116+ messages in thread
From: Niklas Holsti @ 2017-07-04 19:30 UTC (permalink / raw)


(Apologies for a delayed reply.)

On 17-06-30 00:12 , Robert A Duff wrote:
> Niklas Holsti <niklas.holsti@tidorum.invalid> writes:
>
>> There are two reasons why tagged types hamper such analysis:
>
> As Randy pointed out, it is more correct to say that class-wide types do
> that.  Tagged types by themselves do not cause these problems.
> Tagged types without class-wide types are not super useful,
> but they are somewhat useful.
>
>> a) dispatching calls (as you said), where the actual callee is
>> determined by run-time values (tags) which are hard to predict by static
>> analysis
>>
>> b) the non-static size of class-wide objects (of type T'Class), which
>> means that the compiler and/or the programmer must use dynamic
>> allocation (usually heap or secondary stack) for such objects.
> ...
>> For some time, I have had in mind a possible Ada extension to solve
>> point (b): an attribute/aspect that would let the programmer set a
>> static upper bound on the size of any object in T'Class. If we call this
>> aspect Maximum_Size (or perhaps Maximum_Size'Class), the programmer
>> could use it like this:
>>
>>    type Root is tagged record ... end record
>>    with Maximum_Size => 128;
>
> Something like that was considered and rejected for Ada 9X.
> Part of the problem is that it seems so low level to be talking
> about sizes.  It's not even portable.

You are right, but this feature would be used only or mainly in embedded 
programs, which usually already contain unportable, low-level stuff: 
task stack sizes, record representation clauses, etc.

> And not maintainable -- if you
> delete a big type, or make it smaller, you're now wasting space.

If the feature would be adopted, I imagine a friendly compiler would (at 
least optionally) tell me that I am wasting space, or that the given 
Maximum_Size is too small, and what would be the minimum valid value (as 
GNAT does now for 'Size clauses that give a too-small size) even if it 
requires some bind-time or link-time global check. That is a 
quality-of-implementation issue.

> It would be better to have the compiler compute the maximum
> size needed.  That  would require the compiler to do a fairly
> global analysis, which is something Ada compilers are not
> set up to do.

Well, the "binder" part of the compilation system does some global 
stuff. And I would not be surprised if link-time "relocation"-type 
computations could be (mis-)used to compute the maximum size of any type 
in a class.

Some compilers already support stack-size analysis, which is a similar 
global analysis.

>>    type Object_List is array (List_Index) of Root'Class;
>>
>>    type Object_Pair is record
>>       A, B : Root'Class;
>>    end record;
>
> Would you allow:
>
>     X : Object_List (1..10);
>     Y : Object_Pair;
>
> ?

I would like to allow that (default initialized components of type 
Root'Class), but I would not much mind having to initialize such 
components explicitly.

> If so, what is the 'Tag of the various components?
> "Undefined" is not a very satisfying answer.

I agree that "undefined" would not be good. The natural answer seems to 
be that the default initial tag is that of the Root type, but then we 
must assume that it is not an abstract type.

> These things are analogous to records with defaulted discriminants.

Yes, that has been my mental model (and it is the implementation used in 
the main SW component that I would like to switch over to class-wide types).

> The language makes some (unsuccessful!) attempt to prevent
> uninitialized discriminants.

Interesting -- I did not know that the attempt is not fully successful. 
Is it easy to explain when the attemp fails?

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

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

* Re: Ada Annoyances
  2017-06-29 21:29                 ` Robert A Duff
  2017-06-30  0:50                   ` Randy Brukardt
@ 2017-07-04 19:32                   ` Niklas Holsti
  1 sibling, 0 replies; 116+ messages in thread
From: Niklas Holsti @ 2017-07-04 19:32 UTC (permalink / raw)


On 17-06-30 00:29 , Robert A Duff wrote:
> Niklas Holsti <niklas.holsti@tidorum.invalid> writes:
>
>> Isn't finalization of local objects usually implemented by creating a
>> list of these objects, and then traversing that list on scope exit?
>
> No.  That method was used originally by GNAT, but it was changed to
> a simpler and much more efficient method.

Ok, understood and good to know, thanks.

>> ...It
>> seems to me that changing the tag of an object on the list should not be
>> a problem; the new tag would just lead to a different Finalize, through
>> normal dispatching.
>
> I agree, I don't see a problem here.  When Finalize is called, it
> dispatches via the currrent Tag.  Tags can't change in Ada, but if they
> could it would still dispatch via the Tag value present when Finalize is
> called.

We agree on that, good.

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

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

* Re: Ada Annoyances
  2017-07-03 20:39                     ` Robert A Duff
@ 2017-07-04 19:52                       ` Niklas Holsti
  0 siblings, 0 replies; 116+ messages in thread
From: Niklas Holsti @ 2017-07-04 19:52 UTC (permalink / raw)


On 17-07-03 23:39 , Robert A Duff wrote:
> "Randy Brukardt" <randy@rrsoftware.com> writes:
>
>> "Robert A Duff" <bobduff@TheWorld.com> wrote in message
>> news:wcca84q5vq1.fsf@TheWorld.com...
>>> Niklas Holsti <niklas.holsti@tidorum.invalid> writes:
>> ...
>>> I agree, I don't see a problem here.  When Finalize is called, it
>>> dispatches via the currrent Tag.  Tags can't change in Ada, but if they
>>> could it would still dispatch via the Tag value present when Finalize is
>>> called.
>>
>> That's not the problem. The problem is knowing whether to call Finalize at
>> all. The only solution I could see for the GNAT approach is to treat all
>> tagged objects as controlled (using a null Finalize in cause the object
>> isn't controlled). That's expensive.
>
> In this fictional/future version of Ada, I presume the Tag of an object
> could only change if it's a class-wide object.

That was my intention, yes, apologies for not saying so, explicitly.

> So you don't have to
> finalize all tagged objects -- just class-wide ones,

    [snip]

> Actually, not even that.  Just every class-wide object that
> uses this new feature.  It would be known at the root of
> the type hierarchy whether Tags can change.  So there's no
> distributed overhead.

Good to hear. I will try to write up a 'Maximum_Size suggestion for 
ada-comment. May take a while, though.

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

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

* Re: Ada Annoyances
  2017-06-29 16:24                                 ` Jeffrey R. Carter
  2017-06-29 16:51                                   ` Nasser M. Abbasi
@ 2017-07-04 23:40                                   ` Luke A. Guest
  2017-07-05  5:29                                     ` J-P. Rosen
  2017-07-05 17:49                                     ` Jeffrey R. Carter
  1 sibling, 2 replies; 116+ messages in thread
From: Luke A. Guest @ 2017-07-04 23:40 UTC (permalink / raw)


Jeffrey R. Carter <spam.jrcarter.not@spam.not.acm.org> wrote:
> On 06/29/2017 01:18 AM, Nasser M. Abbasi wrote:
>> Pascal Was perfect language for learning and
>> teaching also.
> 
> The US Military Academy did a controlled experiment that showed that Ada (83) 
> was a better teaching language than Pascal, which they were using at the time. 
> Pascal has many well known gotchas for 

What gotchas, apart from dangling else?

beginners that Ada got right. The "Pascal 
> subset" of Ada with packages seems like an excellent first language, though.
> 

I still think Ada is a better teaching language than Pascal. 


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

* Re: Ada Annoyances
  2017-07-04 23:40                                   ` Luke A. Guest
@ 2017-07-05  5:29                                     ` J-P. Rosen
  2017-07-05 13:49                                       ` Dennis Lee Bieber
  2017-07-05 17:49                                     ` Jeffrey R. Carter
  1 sibling, 1 reply; 116+ messages in thread
From: J-P. Rosen @ 2017-07-05  5:29 UTC (permalink / raw)


Le 05/07/2017 à 01:40, Luke A. Guest a écrit :
> Jeffrey R. Carter <spam.jrcarter.not@spam.not.acm.org> wrote:
>> The US Military Academy did a controlled experiment that showed that Ada (83) 
>> was a better teaching language than Pascal, which they were using at the time. 
>> Pascal has many well known gotchas for 
> 
> What gotchas, apart from dangling else?
> 
Arrays of fixed, static size come to mind.

Also, parameter passing needing to be marked as "by value" or "by
reference" is not an easy concept for beginners.


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

* Re: Ada Annoyances
  2017-07-05  5:29                                     ` J-P. Rosen
@ 2017-07-05 13:49                                       ` Dennis Lee Bieber
  0 siblings, 0 replies; 116+ messages in thread
From: Dennis Lee Bieber @ 2017-07-05 13:49 UTC (permalink / raw)


On Wed, 5 Jul 2017 07:29:44 +0200, "J-P. Rosen" <rosen@adalog.fr> declaimed
the following:

>Le 05/07/2017 à 01:40, Luke A. Guest a écrit :
>> Jeffrey R. Carter <spam.jrcarter.not@spam.not.acm.org> wrote:
>>> The US Military Academy did a controlled experiment that showed that Ada (83) 
>>> was a better teaching language than Pascal, which they were using at the time. 
>>> Pascal has many well known gotchas for 
>> 
>> What gotchas, apart from dangling else?
>> 
>Arrays of fixed, static size come to mind.
>
>Also, parameter passing needing to be marked as "by value" or "by
>reference" is not an easy concept for beginners.

	And (if it is following Jensen&Wirth 2nd) that weird one record
pre-read I/O scheme.
-- 
	Wulfraed                 Dennis Lee Bieber         AF6VN
    wlfraed@ix.netcom.com    HTTP://wlfraed.home.netcom.com/


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

* Re: Ada Annoyances
  2017-07-04 23:40                                   ` Luke A. Guest
  2017-07-05  5:29                                     ` J-P. Rosen
@ 2017-07-05 17:49                                     ` Jeffrey R. Carter
  1 sibling, 0 replies; 116+ messages in thread
From: Jeffrey R. Carter @ 2017-07-05 17:49 UTC (permalink / raw)


On 07/05/2017 01:40 AM, Luke A. Guest wrote:
> Jeffrey R. Carter <spam.jrcarter.not@spam.not.acm.org> wrote:
>> On 06/29/2017 01:18 AM, Nasser M. Abbasi wrote:
>>> Pascal Was perfect language for learning and
>>> teaching also.
>>
>> The US Military Academy did a controlled experiment that showed that Ada (83)
>> was a better teaching language than Pascal, which they were using at the time.
>> Pascal has many well known gotchas for
> 
> What gotchas, apart from dangling else?

Semicolon statement separators rather than terminators, need for block 
statements for most compound statements, lack of exit.

-- 
Jeff Carter
"I blow my nose on you."
Monty Python & the Holy Grail
03

---
This email has been checked for viruses by AVG.
http://www.avg.com

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

* Re: Ada Annoyances
  2017-07-04 19:30           ` Niklas Holsti
@ 2017-07-05 20:03             ` Robert A Duff
  0 siblings, 0 replies; 116+ messages in thread
From: Robert A Duff @ 2017-07-05 20:03 UTC (permalink / raw)


Niklas Holsti <niklas.holsti@tidorum.invalid> writes:

> (Apologies for a delayed reply.)

No need to apologize.  I certainly only pay attention to
comp.lang.ada occasionally.

> You are right, but this feature would be used only or mainly in embedded
> programs, which usually already contain unportable, low-level stuff:
> task stack sizes, record representation clauses, etc.

I would use it even in nonembedded systems.

I don't buy the idea that just because some of one's embedded code
needs to be nonportable/low-level, it's OK to force other stuff
to be, when it's not logically necessary.

If you're not interfacing with external hardware or similar,
the compiler should compute record layouts/sizes.

>> And not maintainable -- if you
>> delete a big type, or make it smaller, you're now wasting space.
>
> If the feature would be adopted, I imagine a friendly compiler would (at
> least optionally) tell me that I am wasting space, or that the given
> Maximum_Size is too small, and what would be the minimum valid value (as
> GNAT does now for 'Size clauses that give a too-small size) even if it
> requires some bind-time or link-time global check. That is a
> quality-of-implementation issue.

If it can warn about too-large max size, then it can compute the
max size for you.  Yes, it has to be a global analysis.

Too-small max size is easy -- that can be done at compile
time for each type.

> Well, the "binder" part of the compilation system does some global
> stuff. And I would not be surprised if link-time "relocation"-type
> computations could be (mis-)used to compute the maximum size of any type
> in a class.

Well, if you implemented this feature in GNAT, you'd be proven right.
I don't think AdaCore is going to spend time on it any time soon.

> Some compilers already support stack-size analysis, which is a similar
> global analysis.

Yes.  ARG has always shied away from requiring such things.

> I would like to allow that (default initialized components of type
> Root'Class), but I would not much mind having to initialize such
> components explicitly.

OK.

>> If so, what is the 'Tag of the various components?
>> "Undefined" is not a very satisfying answer.
>
> I agree that "undefined" would not be good. The natural answer seems to
> be that the default initial tag is that of the Root type, but then we
> must assume that it is not an abstract type.

But root types are usually abstract.

>> These things are analogous to records with defaulted discriminants.
>
> Yes, that has been my mental model (and it is the implementation used in
> the main SW component that I would like to switch over to class-wide
> types).
>
>> The language makes some (unsuccessful!) attempt to prevent
>> uninitialized discriminants.
>
> Interesting -- I did not know that the attempt is not fully
> successful. Is it easy to explain when the attemp fails?

Quite easy:

    Uninit : Integer;
    X : Some_Record (Discrim => Uninit);

In a simple case like that, compilers likely warn.
But it's not hard to hide the uninitialized variable
from the compiler.  E.g. a component of a heap-allocated
record -- compilers can't warn about that, because it
would cause too many false positives.

- Bob


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

* Prefixed notation for non tagged types
  2017-07-04  2:18               ` Randy Brukardt
@ 2017-12-17 13:47                 ` Jere
  2017-12-17 15:06                   ` Simon Wright
  0 siblings, 1 reply; 116+ messages in thread
From: Jere @ 2017-12-17 13:47 UTC (permalink / raw)


On Monday, July 3, 2017 at 10:18:33 PM UTC-4, Randy Brukardt wrote:
> "Jere" wrote in message 
> > On Sunday, July 2, 2017 at 8:04:56 PM UTC-4, Randy Brukardt wrote:
> >> (3) Since prefixed notation does automatic dereferencing and referencing
> >> (that is, .all and 'Access), allowing it on all types caused levels of
> >> ambiguity (and potentially infinite regress). It was easier to just 
> >> define
> >> it on tagged types, which didn't have those issues. Perhaps it could have
> >> been made to work, but it was more work for a feature that already had
> >> significant opposition; probably it would have been dropped rather than
> >> getting more complicated. (Sound like a broken record??)
> >
> > Was there any consideration to having prefixed notation to
> > apply to all record types and add a way to denote that a private
> > type is a record type (there should be many ways to do that)?
> > We don't really need it on all types, just record types.
> 
> Not that I recall, but requiring an indication that a private type is 
> completed by a record seems like noise (99% of private types are completed 
> by some sort of record as it is). It would be better the other way around 
> (indicate when it is *not* completed by a record), but of course that would 
> be incompatible. Still seems best for Ada'Succ.
> 
>                                           Randy.

I know this is an old email chain, but I've been thinking about this
more recently.  For background, I asked if there could be a way to
denote that a private type was a record type, so that Prefixed notation
could be used on non tagged types.  Randy noted that since most private 
types were record types, it would just be noise.  I wanted to revisit
this thought.  Forgive me if there is a good way to split the chain.
I don't know how to do that.  

So with that in mind:
My inclination is that the noise is already there.  I generally like
prefixed notation (it is easier for me to discern what is going on
when I read it), so even though I don't really like providing extension
for a type, I find myself making types tagged just to get the
prefixed notation.  In essence, I am already adding noise.  I think
my suggestion is that the noise could be replaced.  Instead of
having to mark any type where I want that notation (I don't do
it to all types) as tagged, have some other method that allows for
the ada compiler to confirm the full view is a record but also allow
for the prefixed notation in partial public view.

I like to keep extension out of many types that I wante prefixed
notation on.  I don't want the baggage that tagged types come with
unless I am actually utilizing those features.  I'm sure there are
a ton of ways to do this:

1.  use the not keyword in conjunction with tagged:
type My_Type is not tagged limited private;

I don't like this at all but just saying it is an option.  I think
it conveys a confusing meaning to the type.

2.  new keyword
type My_Type is <new keyword> limited private;

I don't really like adding new keywords either...though the option is
there I guess.  Something like the "final" keyword that says it was
tagged but can no longer be extended or some keyword completely
unrelated to tagged-ness.

3.  change up record declarations to use "record" in the partial view:
type My_Type is limited private record;

My guess is this would be difficult for compiler writers though as 
record is used for starting a declaration block.

4.  maybe an aspect
type My_Type is limited private
with
   Prefixed_Notation => True;  -- or some other aspect name

Here I am unsure if this is a good fit or not.  I don't have a good
feel for the boundaries of what aspects should be used for.

5.  maybe an attribute
type My_Type is limited private;
for My_Type'Prefixed_Notation use True;  -- or some other name

Same thoughts as #4 but I feel even more strongly that this would
be odd.

Maybe some other options.  My key point is that there already exists
noise out there for this and it comes with features that the designer
may not want to expose in the process.  Maybe there is a better way
to handle it.  I realize that if the feature existed others that didn't
mark types tagged for prefix notation would possibly use it, but I think
that is more of an indication of why it should be explored further.

Anyone have any thoughts?


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

* Re: Prefixed notation for non tagged types
  2017-12-17 13:47                 ` Prefixed notation for non tagged types Jere
@ 2017-12-17 15:06                   ` Simon Wright
  2017-12-17 15:33                     ` Dmitry A. Kazakov
                                       ` (2 more replies)
  0 siblings, 3 replies; 116+ messages in thread
From: Simon Wright @ 2017-12-17 15:06 UTC (permalink / raw)


Jere <jhb.chat@gmail.com> writes:

> On Monday, July 3, 2017 at 10:18:33 PM UTC-4, Randy Brukardt wrote:
>> "Jere" wrote in message 
>> > On Sunday, July 2, 2017 at 8:04:56 PM UTC-4, Randy Brukardt wrote:
>> >> (3) Since prefixed notation does automatic dereferencing and referencing
>> >> (that is, .all and 'Access), allowing it on all types caused levels of
>> >> ambiguity (and potentially infinite regress). It was easier to just 
>> >> define
>> >> it on tagged types, which didn't have those issues. Perhaps it could have
>> >> been made to work, but it was more work for a feature that already had
>> >> significant opposition; probably it would have been dropped rather than
>> >> getting more complicated. (Sound like a broken record??)
>> >
>> > Was there any consideration to having prefixed notation to
>> > apply to all record types and add a way to denote that a private
>> > type is a record type (there should be many ways to do that)?
>> > We don't really need it on all types, just record types.
>> 
>> Not that I recall, but requiring an indication that a private type is 
>> completed by a record seems like noise (99% of private types are completed 
>> by some sort of record as it is). It would be better the other way around 
>> (indicate when it is *not* completed by a record), but of course that would 
>> be incompatible. Still seems best for Ada'Succ.
>> 
>>                                           Randy.
>
> I know this is an old email chain, but I've been thinking about this
> more recently.  For background, I asked if there could be a way to
> denote that a private type was a record type, so that Prefixed notation
> could be used on non tagged types.  Randy noted that since most private 
> types were record types, it would just be noise.  I wanted to revisit
> this thought.  Forgive me if there is a good way to split the chain.
> I don't know how to do that.  

I don't understand why prefixed notation should be limited to private
types that are completed by records?

Naturally, I wasn't involved in any ARG discussions about this (not
being a member!), but I'd have thought the ideal would be for any
derived type (which includes private types, I think?) to be a candidate.


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

* Re: Prefixed notation for non tagged types
  2017-12-17 15:06                   ` Simon Wright
@ 2017-12-17 15:33                     ` Dmitry A. Kazakov
  2017-12-18 22:31                     ` Randy Brukardt
  2017-12-19  0:40                     ` Jere
  2 siblings, 0 replies; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-12-17 15:33 UTC (permalink / raw)


On 2017-12-17 16:06, Simon Wright wrote:

> I don't understand why prefixed notation should be limited to private
> types that are completed by records?

Yes, it looks like a simple syntax sugar that the programmer should be 
able to enable for any subprogram and any argument of.

> Naturally, I wasn't involved in any ARG discussions about this (not
> being a member!), but I'd have thought the ideal would be for any
> derived type (which includes private types, I think?) to be a candidate.

Certainly not the way of ARG's thought, but in classic OO prefix 
notation comes from the [wrong] idea that a method is an object's 
member. Thus the notation can be seen as an implementation of a record 
interface X.F where F is naturally dispatching. This in Ada leads to 
tagged types and their primitive operations.

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

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

* Re: Ada Annoyances
  2017-06-23 18:56           ` Maciej Sobczak
  2017-06-23 22:18             ` pythoner6
@ 2017-12-17 16:24             ` Mehdi Saada
  2017-12-17 17:27               ` Dmitry A. Kazakov
  1 sibling, 1 reply; 116+ messages in thread
From: Mehdi Saada @ 2017-12-17 16:24 UTC (permalink / raw)


So, some of you think the stupidity is on the side of certain customers, to ban tagged types as a whole, as objetively there is no added cost when we don't use 'Class types ? Rather than on the language designers', for tagging controlled type and cursor etc by default ?
Can someone answer simply, if there is or not, really no difference (save for some more bits for the tag) between regular records types and tagged types, when not using class types ?

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

* Re: Ada Annoyances
  2017-12-17 16:24             ` Mehdi Saada
@ 2017-12-17 17:27               ` Dmitry A. Kazakov
  2017-12-18 23:09                 ` Randy Brukardt
  0 siblings, 1 reply; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-12-17 17:27 UTC (permalink / raw)


On 2017-12-17 17:24, Mehdi Saada wrote:
> So, some of you think the stupidity is on the side of certain
> customers, to ban tagged types as a whole, as objetively there is no
> added cost when we don't use 'Class types ? Rather than on the language
> designers', for tagging controlled type and cursor etc by default ?
> Can someone answer simply, if there is or not, really no difference
> (save for some more bits for the tag) between regular records types and
> tagged types, when not using class types ?

There is a huge difference even without class-wide objects. Some things 
from the top:

1. You can derive a new type from a tagged type, which you cannot do 
from a non-tagged type

2. You can clone a non-tagged type, which you cannot do with a tagged type.

3. The meaning of abstract operations like

    procedure Foo (X : T) is abstract;

for tagged and non-tagged types is totally different

4. Type polymorphism is still available for tagged types without 
class-wide objects as you can have generic formal parameters:

    generic
       type X is new Y with private;

5. You can inherit operations of tagged types.

6. You cannot declare certain operation signatures with tagged types due 
to multiple-dispatch issues.

7. Declaration of tagged types are subject of freezing rules.

8. Visibility of primitive operations is radically different. You can 
reach primitive operation even if they are not visible.

9. Certain signatures behave differently if arguments are tagged, e.g. 
when several arguments are controlled the tags must be same.

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


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

* Re: Prefixed notation for non tagged types
  2017-12-17 15:06                   ` Simon Wright
  2017-12-17 15:33                     ` Dmitry A. Kazakov
@ 2017-12-18 22:31                     ` Randy Brukardt
  2017-12-19  0:40                     ` Jere
  2 siblings, 0 replies; 116+ messages in thread
From: Randy Brukardt @ 2017-12-18 22:31 UTC (permalink / raw)


"Simon Wright" <simon@pushface.org> wrote in message 
news:lyzi6hfl6r.fsf@pushface.org...
...
> Naturally, I wasn't involved in any ARG discussions about this (not
> being a member!), but I'd have thought the ideal would be for any
> derived type (which includes private types, I think?) to be a candidate.

My recollection was that the original idea was to allow it for any type, but 
that ran into problems with access types. Then we considered allowing it for 
any composite type, but that ran into problems with private types (which can 
be completed with an elementary type, specifically an access type). 
Requiring "tagged" side-stepped the problems, and it seemed like a better 
solution than adopting something that has known problems (which, once 
adopted, we're stuck with forever).

I think we would have been better off getting rid of the implicit 'Access in 
the prefixed notation (no other Ada feature does that); in that case, there 
wouldn't have been a problem with any type. That suggestion went nowhere, 
though.

                                 Randy.


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

* Re: Ada Annoyances
  2017-12-17 17:27               ` Dmitry A. Kazakov
@ 2017-12-18 23:09                 ` Randy Brukardt
  2017-12-19  9:25                   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 116+ messages in thread
From: Randy Brukardt @ 2017-12-18 23:09 UTC (permalink / raw)



"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:p169d9$6ka$1@gioia.aioe.org...
> On 2017-12-17 17:24, Mehdi Saada wrote:
>> So, some of you think the stupidity is on the side of certain
>> customers, to ban tagged types as a whole, as objetively there is no
>> added cost when we don't use 'Class types ? Rather than on the language
>> designers', for tagging controlled type and cursor etc by default ?
>> Can someone answer simply, if there is or not, really no difference
>> (save for some more bits for the tag) between regular records types and
>> tagged types, when not using class types ?
>
> There is a huge difference even without class-wide objects. Some things 
> from the top:
>
> 1. You can derive a new type from a tagged type, which you cannot do from 
> a non-tagged type

I think you are using a non-Ada meaning of "derive" here, since an Ada 
derived type works for all types.

> 2. You can clone a non-tagged type, which you cannot do with a tagged 
> type.

No idea what this means. You certainly can use a null extension on a tagged 
type, and that operates pretty much the same as a non-tagged type.

> 3. The meaning of abstract operations like
>
>    procedure Foo (X : T) is abstract;
>
> for tagged and non-tagged types is totally different

Right.

> 4. Type polymorphism is still available for tagged types without 
> class-wide objects as you can have generic formal parameters:
>
>    generic
>       type X is new Y with private;

You can do this for untagged types as well (without the "with private" 
part), it's just not very useful.

> 5. You can inherit operations of tagged types.

All derived types inherit operations. That's why the Ada 95 design used 
derivation rather than a new type construct to implement OOP.

> 6. You cannot declare certain operation signatures with tagged types due 
> to multiple-dispatch issues.

Right. But this is a subset of 9.

> 7. Declaration of tagged types are subject of freezing rules.

All types are subject to freezing rules; perhaps you meant that the 
*operations* of a tagged type are also subject to freezing rules.

> 8. Visibility of primitive operations is radically different. You can 
> reach primitive operation even if they are not visible.

You mean that prefix notation is allowed (and it has different visibility 
rules). Otherwise, the visibilty rules are the same for all types, annoying 
as that can be.

I think this one follows from the OPs original comment.

> 9. Certain signatures behave differently if arguments are tagged, e.g. 
> when several arguments are controlled the tags must be same.

Right, 6 is a subset of this one, in that there can be only one tag, and a 
number of rules are used to enforce that.


======================

I read the original question as to whether the *representation* of a tagged 
type is essentially the same as an untagged record type. And the answer to 
that is that, yes, in most cases, a tagged type is just a record type with 
an extra "tag" component. Unless there are going to be a very large number 
of objects of a type, the extra cost of a tagged type is insignificant.

The Ada 95 designers considered tagged types to be "records done right", and 
thus the different rules for them. Most of the differences are improvements 
(and at least one has been applied to all records in more recent Ada 
versions -- the equality rules). I wouldn't worry about declaring a type 
tagged unless there were likely to be thousands of objects of it being 
created.

Controlled types might be more expensive, depending upon how they are 
implemented. If a chaining implementation is used, then there are extra 
components which have to be managed. That might happen even for a mostly 
static implementation (there still are cases like allocated objects that 
have to be managed dynamically). So I'd be a bit more cautious with those, 
but again it only would matter if there are a lot of objects getting created 
and destroyed.

                                 Randy.



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

* Re: Prefixed notation for non tagged types
  2017-12-17 15:06                   ` Simon Wright
  2017-12-17 15:33                     ` Dmitry A. Kazakov
  2017-12-18 22:31                     ` Randy Brukardt
@ 2017-12-19  0:40                     ` Jere
  2017-12-19 23:04                       ` Randy Brukardt
  2 siblings, 1 reply; 116+ messages in thread
From: Jere @ 2017-12-19  0:40 UTC (permalink / raw)


On Sunday, December 17, 2017 at 10:06:38 AM UTC-5, Simon Wright wrote:
> Jere writes:
> 
> > On Monday, July 3, 2017 at 10:18:33 PM UTC-4, Randy Brukardt wrote:
> >> "Jere" wrote in message 
> >> > On Sunday, July 2, 2017 at 8:04:56 PM UTC-4, Randy Brukardt wrote:
> >> >> (3) Since prefixed notation does automatic dereferencing and referencing
> >> >> (that is, .all and 'Access), allowing it on all types caused levels of
> >> >> ambiguity (and potentially infinite regress). It was easier to just 
> >> >> define
> >> >> it on tagged types, which didn't have those issues. Perhaps it could have
> >> >> been made to work, but it was more work for a feature that already had
> >> >> significant opposition; probably it would have been dropped rather than
> >> >> getting more complicated. (Sound like a broken record??)
> >> >
> >> > Was there any consideration to having prefixed notation to
> >> > apply to all record types and add a way to denote that a private
> >> > type is a record type (there should be many ways to do that)?
> >> > We don't really need it on all types, just record types.
> >> 
> >> Not that I recall, but requiring an indication that a private type is 
> >> completed by a record seems like noise (99% of private types are completed 
> >> by some sort of record as it is). It would be better the other way around 
> >> (indicate when it is *not* completed by a record), but of course that would 
> >> be incompatible. Still seems best for Ada'Succ.
> >> 
> >>                                           Randy.
> >
> > I know this is an old email chain, but I've been thinking about this
> > more recently.  For background, I asked if there could be a way to
> > denote that a private type was a record type, so that Prefixed notation
> > could be used on non tagged types.  Randy noted that since most private 
> > types were record types, it would just be noise.  I wanted to revisit
> > this thought.  Forgive me if there is a good way to split the chain.
> > I don't know how to do that.  
> 
> I don't understand why prefixed notation should be limited to private
> types that are completed by records?
> 
> Naturally, I wasn't involved in any ARG discussions about this (not
> being a member!), but I'd have thought the ideal would be for any
> derived type (which includes private types, I think?) to be a candidate.

I wasn't intending that it be limited to record types.  When I had asked
way back in this chain's history I was told it wasn't possible, so I was
trying baby steps.  All record types would be the next logical step 
after tagged types. I would definitely be happy with a wider array of
options for it.


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

* Re: Ada Annoyances
  2017-12-18 23:09                 ` Randy Brukardt
@ 2017-12-19  9:25                   ` Dmitry A. Kazakov
  0 siblings, 0 replies; 116+ messages in thread
From: Dmitry A. Kazakov @ 2017-12-19  9:25 UTC (permalink / raw)


On 2017-12-19 00:09, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:p169d9$6ka$1@gioia.aioe.org...

>> 1. You can derive a new type from a tagged type, which you cannot do from
>> a non-tagged type
> 
> I think you are using a non-Ada meaning of "derive" here, since an Ada
> derived type works for all types.

Yes, a common-sense "derive" (:-))

>> 2. You can clone a non-tagged type, which you cannot do with a tagged
>> type.
> 
> No idea what this means. You certainly can use a null extension on a tagged
> type, and that operates pretty much the same as a non-tagged type.

I mean:

    type X is new Integer;

which is very different from

    type X is new Integer with null record;

if the latter ever existed.

Cloning for tagged types is only possible when the type is wrapped into 
a generic:

    generic
    package Clone_Factory is
       type Y is tagged ...;
    end Clone_Factory;

    package Clone_1 is new Clone_Factory;
    package Clone_2 is new Clone_Factory;
    ...

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


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

* Re: Prefixed notation for non tagged types
  2017-12-19  0:40                     ` Jere
@ 2017-12-19 23:04                       ` Randy Brukardt
  2017-12-20 12:33                         ` Robert Eachus
  0 siblings, 1 reply; 116+ messages in thread
From: Randy Brukardt @ 2017-12-19 23:04 UTC (permalink / raw)


"Jere" <jhb.chat@gmail.com> wrote in message 
news:4b355dd2-b7c2-495a-8377-306b500fcb78@googlegroups.com...
...
> I wasn't intending that it be limited to record types.  When I had asked
> way back in this chain's history I was told it wasn't possible, so I was
> trying baby steps.  All record types would be the next logical step
> after tagged types. I would definitely be happy with a wider array of
> options for it.

Assuming that you want it to work for private types, the only choices are 
"all types" or "tagged types", because any type can complete a normal 
private type, and having something available for a private type that is not 
available for the full type leads directly to madness.

                                   Randy.



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

* Re: Prefixed notation for non tagged types
  2017-12-19 23:04                       ` Randy Brukardt
@ 2017-12-20 12:33                         ` Robert Eachus
  0 siblings, 0 replies; 116+ messages in thread
From: Robert Eachus @ 2017-12-20 12:33 UTC (permalink / raw)


On Tuesday, December 19, 2017 at 6:05:01 PM UTC-5, Randy Brukardt wrote:

> Assuming that you want it to work for private types, the only choices are 
> "all types" or "tagged types", because any type can complete a normal 
> private type, and having something available for a private type that is not 
> available for the full type leads directly to madness.

Go directly to madness.  Do not pass Go.  Do not collect $200.  ;-)

Seriously, the visibility rules were hard fought way back in the early eighties.  There were lots of 'nice' features thrown out because the corners either resulted in the "wrong" function being called, or two definitions hiding each other.  The only one I know of that we missed was:

   function Foo return Integer is begin return 3;  end;
   function Foo (X: in Integer := 4) return Integer is begin return X; end;
   ...
   Y: Integer := Foo; -- ambiguous

There is no way to call the first Foo, or for that matter call the second Foo with a default argument!  Of course, the real "fix" is just don't do that. (The case where one Foo is directly visible and the other is use-visible has a rule that favors the directly visible declaration. Again madness avoidance, adding a use clause will not change the meaning of the code within the scope of the program.  If it means that there are now two use-visible homographs, the use clause can make the code illegal, but the fix is obvious.)

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

end of thread, other threads:[~2017-12-20 12:33 UTC | newest]

Thread overview: 116+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-21  1:12 Ada Annoyances pythoner6
2017-06-21 10:13 ` Lucretia
2017-06-23 15:27   ` raph.amiard
2017-06-23 17:49     ` Randy Brukardt
2017-06-23 19:21       ` Niklas Holsti
2017-06-24  4:02         ` Shark8
2017-06-24 19:55         ` Simon Wright
2017-06-24 20:56           ` Niklas Holsti
2017-06-25 23:43         ` Randy Brukardt
2017-06-26 20:20           ` Niklas Holsti
2017-06-26 21:47             ` Randy Brukardt
2017-06-26 22:23               ` Dmitry A. Kazakov
2017-06-29 19:00               ` Niklas Holsti
2017-06-29 21:29                 ` Robert A Duff
2017-06-30  0:50                   ` Randy Brukardt
2017-07-03 20:39                     ` Robert A Duff
2017-07-04 19:52                       ` Niklas Holsti
2017-07-04 19:32                   ` Niklas Holsti
2017-06-30  0:47                 ` Randy Brukardt
2017-06-30 18:45                   ` Niklas Holsti
2017-06-30 20:06                     ` Robert A Duff
2017-06-29 21:12         ` Robert A Duff
2017-07-04 19:30           ` Niklas Holsti
2017-07-05 20:03             ` Robert A Duff
2017-06-23 19:22       ` Niklas Holsti
2017-06-30 15:02       ` Norman Worth
2017-06-30 23:49         ` pythoner6
2017-07-03  0:04           ` Randy Brukardt
2017-07-03 17:47             ` Jere
2017-07-03 19:43               ` Dmitry A. Kazakov
2017-07-04  2:18               ` Randy Brukardt
2017-12-17 13:47                 ` Prefixed notation for non tagged types Jere
2017-12-17 15:06                   ` Simon Wright
2017-12-17 15:33                     ` Dmitry A. Kazakov
2017-12-18 22:31                     ` Randy Brukardt
2017-12-19  0:40                     ` Jere
2017-12-19 23:04                       ` Randy Brukardt
2017-12-20 12:33                         ` Robert Eachus
2017-06-21 11:58 ` Ada Annoyances joakimds
2017-06-21 12:29   ` Pascal Obry
2017-06-21 14:52     ` pythoner6
2017-06-21 16:11       ` J-P. Rosen
2017-06-21 16:12       ` Dmitry A. Kazakov
2017-06-21 22:45         ` pythoner6
2017-06-22  7:29           ` Dmitry A. Kazakov
2017-06-22 10:29             ` pythoner6
2017-06-22 11:04               ` Egil H H
2017-06-22 13:30               ` Dmitry A. Kazakov
2017-06-22 19:22                 ` Niklas Holsti
2017-06-22 21:52                   ` Dmitry A. Kazakov
2017-06-23  9:33                     ` AdaMagica
2017-06-23 10:25                       ` Simon Wright
2017-06-23  1:00                 ` pythoner6
2017-06-23 15:23         ` raph.amiard
2017-06-23 16:10           ` Dmitry A. Kazakov
2017-06-23 17:41           ` Randy Brukardt
2017-06-23 18:56           ` Maciej Sobczak
2017-06-23 22:18             ` pythoner6
2017-06-24  8:05               ` Dmitry A. Kazakov
2017-06-24  8:35                 ` Maciej Sobczak
2017-06-24  9:07                   ` Dmitry A. Kazakov
2017-06-24 20:50                     ` Maciej Sobczak
2017-06-24 21:06                       ` Dmitry A. Kazakov
2017-06-25 11:33                         ` Maciej Sobczak
2017-06-25 14:32                           ` Dmitry A. Kazakov
2017-06-25 20:50                             ` Maciej Sobczak
2017-06-26  7:58                               ` Dmitry A. Kazakov
2017-06-26 13:24                                 ` Maciej Sobczak
2017-06-26 16:38                                   ` Dmitry A. Kazakov
2017-06-26 20:42                                     ` Maciej Sobczak
2017-06-24  8:34               ` Maciej Sobczak
2017-06-24 13:06                 ` pythoner6
2017-06-24 15:40                   ` Dmitry A. Kazakov
2017-06-26  0:06                 ` Randy Brukardt
2017-06-26 20:35                   ` Maciej Sobczak
2017-06-26 21:40                     ` Randy Brukardt
2017-06-27  7:23                       ` Maciej Sobczak
2017-06-27 20:38                         ` Randy Brukardt
2017-06-28  8:21                           ` Dmitry A. Kazakov
2017-06-28 20:50                             ` Randy Brukardt
2017-06-28 23:18                               ` Nasser M. Abbasi
2017-06-29  7:27                                 ` Dmitry A. Kazakov
2017-06-29 16:24                                 ` Jeffrey R. Carter
2017-06-29 16:51                                   ` Nasser M. Abbasi
2017-07-04 23:40                                   ` Luke A. Guest
2017-07-05  5:29                                     ` J-P. Rosen
2017-07-05 13:49                                       ` Dennis Lee Bieber
2017-07-05 17:49                                     ` Jeffrey R. Carter
2017-06-29 21:46                                 ` darkestkhan
2017-06-29  7:15                               ` Dmitry A. Kazakov
2017-06-30  0:42                                 ` Randy Brukardt
2017-06-30  7:36                                   ` Dmitry A. Kazakov
2017-06-28 13:07                           ` Maciej Sobczak
2017-06-27  7:26                       ` Dmitry A. Kazakov
2017-06-27 20:41                         ` Randy Brukardt
2017-06-28  7:57                           ` Dmitry A. Kazakov
2017-06-27 15:19                     ` AdaMagica
2017-06-27 16:32                       ` Dmitry A. Kazakov
2017-06-28 13:15                       ` Maciej Sobczak
2017-06-28 14:05                         ` AdaMagica
2017-06-29 21:17                           ` Robert A Duff
2017-06-30  7:44                             ` Dmitry A. Kazakov
2017-06-30  7:49                               ` J-P. Rosen
2017-06-30  8:28                                 ` Dmitry A. Kazakov
2017-06-30 10:14                                   ` J-P. Rosen
2017-06-30 10:30                                     ` Dmitry A. Kazakov
2017-06-28 20:53                         ` Randy Brukardt
2017-12-17 16:24             ` Mehdi Saada
2017-12-17 17:27               ` Dmitry A. Kazakov
2017-12-18 23:09                 ` Randy Brukardt
2017-12-19  9:25                   ` Dmitry A. Kazakov
2017-06-21 20:40       ` G.B.
2017-06-21 22:25         ` pythoner6
2017-06-26 11:01     ` Vincent
2017-06-26 11:15       ` Alejandro R. Mosteo
2017-06-26 16:35       ` Pascal Obry

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