* Best use cases for OOP
@ 2025-08-28 14:40 Kevin Chadwick
2025-08-28 14:45 ` Best use cases for OOP (resent quoted sorry) Kevin Chadwick
0 siblings, 1 reply; 8+ messages in thread
From: Kevin Chadwick @ 2025-08-28 14:40 UTC (permalink / raw)
On 28/08/2025 10:02, Dmitry A. Kazakov wrote:
On 2025-08-28 10:50, Kevin Chadwick wrote:
I can explain how it works. When a DLL is loaded its library level
gets elaborated. So if you have:
package P is
type T is tagged ...
end P;
in the main program or DLL and
with P;
package Q is
type S is new T with ...
function F return T'Class;
end Q;
in the DLL being loaded, then in the process of elaboration S will be
created which in particular means extending of the dispatching table.
You can return a class-wide object from there and dispatch on the
newly created type's operation.
Clear?
Interesting, better than the shape examples but I guess you have to get
that in the first instance.
Dynamic polymorphism is an extremely powerful mechanism, but it kind of
bends out of traditional typing.
It is like the relativity theory. Everything is relative, position,
velocity, but up to the point. Acceleration is not anymore. Same is with
typing: value->type, so far so good, but one more step up:
value->type->class and something happens. Primitive operations become
reachable even if you do not see them, you cannot hide them. Multiple
inheritance, OK, but what about conflicts, is it additive or idempotent?
Multiple dispatch is a total dark hole.
I have struggled to find compelling reasons to use tagged types considering
they affect the size of records and potentially elaboration issues that
cannot exist without tagged types.
I know some use tagged types just for dot notation but that doesn't really
move the needle in my mind. I would certainly appreciate it if people could
share their favourite use cases for tagged types though. Things that are
perhaps a pain without them or were with Ada 83.
--
Regards, Kc
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Best use cases for OOP (resent quoted sorry)
2025-08-28 14:40 Best use cases for OOP Kevin Chadwick
@ 2025-08-28 14:45 ` Kevin Chadwick
2025-08-28 15:12 ` Dmitry A. Kazakov
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Kevin Chadwick @ 2025-08-28 14:45 UTC (permalink / raw)
On 28/08/2025 15:40, Kevin Chadwick wrote:
>On 28/08/2025 10:02, Dmitry A. Kazakov wrote:
>
>On 2025-08-28 10:50, Kevin Chadwick wrote:
>
>I can explain how it works. When a DLL is loaded its library level
>
>gets elaborated. So if you have:
>
>package P is
>
> type T is tagged ...
>
>end P;
>
>in the main program or DLL and
>
>with P;
>
>package Q is
>
> type S is new T with ...
>
> function F return T'Class;
>
>end Q;
>
>in the DLL being loaded, then in the process of elaboration S will be
>
>created which in particular means extending of the dispatching table.
>
>You can return a class-wide object from there and dispatch on the
>
>newly created type's operation.
>
>Clear?
>
>Interesting, better than the shape examples but I guess you have to get
>
>that in the first instance.
>
>Dynamic polymorphism is an extremely powerful mechanism, but it kind of
>
>bends out of traditional typing.
>
>It is like the relativity theory. Everything is relative, position,
>
>velocity, but up to the point. Acceleration is not anymore. Same is with
>
>typing: value->type, so far so good, but one more step up:
>
>value->type->class and something happens. Primitive operations become
>
>reachable even if you do not see them, you cannot hide them. Multiple
>
>inheritance, OK, but what about conflicts, is it additive or idempotent?
>
>Multiple dispatch is a total dark hole.
>
>
I have struggled to find compelling reasons to use tagged types considering
they affect the size of records and potentially elaboration issues that
cannot exist without tagged types.
I know some use tagged types just for dot notation but that doesn't really
move the needle in my mind. I would certainly appreciate it if people could
share their favourite use cases for tagged types though. Things that are
perhaps a pain without them or were with Ada 83.
--
Regards, Kc
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Best use cases for OOP (resent quoted sorry)
2025-08-28 14:45 ` Best use cases for OOP (resent quoted sorry) Kevin Chadwick
@ 2025-08-28 15:12 ` Dmitry A. Kazakov
2025-08-28 18:28 ` Niklas Holsti
2025-08-28 20:23 ` Alex // nytpu
2 siblings, 0 replies; 8+ messages in thread
From: Dmitry A. Kazakov @ 2025-08-28 15:12 UTC (permalink / raw)
On 2025-08-28 16:45, Kevin Chadwick wrote:
> I have struggled to find compelling reasons to use tagged types considering
> they affect the size of records and potentially elaboration issues that
> cannot exist without tagged types.
Nothing forces you to use variant sizes or construction hooks. The
advantage is the you can, if you need it.
> I know some use tagged types just for dot notation but that doesn't really
> move the needle in my mind. I would certainly appreciate it if people could
> share their favourite use cases for tagged types though. Things that are
> perhaps a pain without them or were with Ada 83.
1. The easiest example is network protocols. If you take a look at the
Simple Components implementation, then the server and client know
nothing about the actual protocol. They simply read and write chunk of
data. Upon connection a factory is called which returns an instance of a
connection object. This type implements HTTP, MQTT, ModBus, LDAP
whatever. The server/client simply passes data to the object for
processing. That are dispatching calls.
2. Syntax tree. The nodes of the tree are tagged types. You can nicely
reuse parts of implementation, e.g. numeric literals etc. You can
inspect an implementation of Ada expression parser. The parser itself
knows nothing about Ada. It is the same parser that is used for JSON or XPM.
3. GUI widgets it are practically impossible to have without OO, as you
need a hierarchy of and an ability to create new widgets using the old
ones. In AICWL layers of a gauge, oscilloscope, meter are tagged types.
The instrument is drawn by drawing each layer via a dispatching call.
4. Practically all container types are tagged in order to extend
functionality but also for generic programming. Consider an ability to
iterate a container. All iteratable containers form a class. With tagged
types you can formally define such a class as an interface and inherit
it in vector, map, set. You can do that with generics too, but that
would force everything generic.
--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Best use cases for OOP (resent quoted sorry)
2025-08-28 14:45 ` Best use cases for OOP (resent quoted sorry) Kevin Chadwick
2025-08-28 15:12 ` Dmitry A. Kazakov
@ 2025-08-28 18:28 ` Niklas Holsti
2025-08-28 20:23 ` Alex // nytpu
2 siblings, 0 replies; 8+ messages in thread
From: Niklas Holsti @ 2025-08-28 18:28 UTC (permalink / raw)
On 2025-08-28 17:45, Kevin Chadwick wrote:
[ snip ]
> I have struggled to find compelling reasons to use tagged types considering
> they affect the size of records and potentially elaboration issues that
> cannot exist without tagged types.
>
> I know some use tagged types just for dot notation but that doesn't really
> move the needle in my mind.
An Ada amendment (AI22-0091-1) that extends dot notation to almost all
untagged types has been approved for the next Ada standard:
http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ai22s/ai22-0091-1.html?rev=Top1.8
> I would certainly appreciate it if people could share their favourite
> use cases for tagged types though. Things that are perhaps a pain
> without them or were with Ada 83.
Rather than a use-case, here is a general argument (well known already):
in principle a tagged type T could be replaced by an Ada 83 record type
with an enumerated discriminant (corresponding to the tag of T) and
corresponding variants (corresponding to the types in T'Class).
Dynamically dispatched operation calls would be replaced by "case"
statements indexed by the discriminant.
However, that would make it much harder to structure and maintain the
program, because:
1. The declaration of the discriminant enumeration must contain all
values that will be used anywhere in the program. This central
declaration must be visible to all uses of the discriminant.
2. Every "case" statement must contain a "when" branch for every value
of the discriminant. Thus every "case" statement has to handle all
variants and have visibility on the modules that implement the logic for
each variant. This leads to a lot of inter-module dependencies across
variants that may be quite unrelated.
3. Consequently, adding or removing a variant (corresponding to adding
or removing a type in T'Class) implies changes to many source files and
requires a lot of recompilation and perhaps much retesting.
In contrast, when a tagged type is used, instead of a record with variants:
A. There is no central declaration of all derived types (all types in
T'Class). Each such type can be declared and be visible only in the
modules where it is relevant. Only the root type T must be widely visible.
B. The implementation of each operation on the class is not a "case"
statement with a "when" branch for each derived type. Instead, thru
dynamic dispatch, the implementations of the operations for a derived
type can be placed in the modules relevant to that type, as if the
"case" statements had been cut up to collect the "when" branches for
each variant into a module for that variant.
C. Consequently, adding or removing a derived type in T'Class is usually
a very local change to a closely related set of source files. Adding or
removing primitive operations of T can still require changes to many
source files (the files implementing each derived type), but that can be
mitigated by creating subclasses of T'Class so that operations
applicable to a subclass (a subset of the types in T'Class) are defined
only in that subclass and not all T'Class.
In summary, tagged types provide a new and IMO powerful and useful way
to modularize a program, separate concerns, and reduce unnecessary
inter-module dependencies.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Best use cases for OOP (resent quoted sorry)
2025-08-28 14:45 ` Best use cases for OOP (resent quoted sorry) Kevin Chadwick
2025-08-28 15:12 ` Dmitry A. Kazakov
2025-08-28 18:28 ` Niklas Holsti
@ 2025-08-28 20:23 ` Alex // nytpu
2025-08-29 8:28 ` Dmitry A. Kazakov
2 siblings, 1 reply; 8+ messages in thread
From: Alex // nytpu @ 2025-08-28 20:23 UTC (permalink / raw)
On 8/28/25 8:45 AM, Kevin Chadwick wrote:
> <...>
>
> I have struggled to find compelling reasons to use tagged types considering
> they affect the size of records and potentially elaboration issues that
> cannot exist without tagged types.
>
> I know some use tagged types just for dot notation but that doesn't really
> move the needle in my mind. I would certainly appreciate it if people could
> share their favourite use cases for tagged types though. Things that are
> perhaps a pain without them or were with Ada 83.
In general, things like variant records are sorta "perpendicular" in use
to OOP/tagged types. Tagged types make it easy to add a new class while
not having to modify most of the routines you can use on the class, but
it's tedious to add new routines; while variant records make it easy to
add new routines to use on the type but it's tedious to add a new record
variant. Linking to a random section of a random book but this section
is a great explanation:
<https://craftinginterpreters.com/representing-code.html#the-expression-problem>
In Ada in particular, my main preferred use-case is defining interfaces
so my routines can take a `My_Interface'Class` type and then anything
needing to use them can just implement the interface in whatever record
the want to use my code with. This seems to be one of the primary
things the Ada standard library uses it for too, e.g. streams, storage
pools, and controlled types. Note that I'm saying "interface" as a
concept distinct from Ada's interfaces, for instance the standard
library makes controlled types and storage pools be full tagged types
you subclass (for various complex reasons) but conceptually they're
still just empty types defining a common interface for the routines
those APIs need.
Although admittedly it is extremely rare I use (non-derived) tagged
types at all though, and when I do it is almost exclusively to get dot
notation lol (and tagged types were supposed to no longer be needed for
dot calls in Ada 2022 but it was delayed until Ada 202y). I do use
types derived from the standard library types a lot though; namely
controlled types for bindings and for custom stream types.
I wouldn't really worry about the "overhead" of tagged types not
significant on any modern system and no more than a language like C++
(let alone high-level dynamic languages) add to literally every data
structure with no option to omit the metadata like Ada has. The only
real issue is that IIRC tagged types are always at least twenty bytes on
GNAT (on ARMv4T/ARMv5T at least, since developing for them is the only
time I've gotten warnings about this limitation) which precludes things
like having a record be small enough to be passed in a register instead
of the stack, but not much of an issue on modern systems. It'd also
preclude things like a record containing a single field being optimized
to acting like a variable directly holding that field type since there's
the tag overhead. Very premature micro-optimization-y concern still
though IMO, just use tagged types when it makes sense.
~nytpu
--
Alex // nytpu
https://nytpu.com/ - gemini://nytpu.com/ - gopher://nytpu.com/
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Best use cases for OOP (resent quoted sorry)
2025-08-28 20:23 ` Alex // nytpu
@ 2025-08-29 8:28 ` Dmitry A. Kazakov
2025-08-29 9:14 ` Kevin Chadwick
0 siblings, 1 reply; 8+ messages in thread
From: Dmitry A. Kazakov @ 2025-08-29 8:28 UTC (permalink / raw)
On 2025-08-28 22:23, Alex // nytpu wrote:
> The only
> real issue is that IIRC tagged types are always at least twenty bytes on
> GNAT (on ARMv4T/ARMv5T at least, since developing for them is the only
> time I've gotten warnings about this limitation) which precludes things
> like having a record be small enough to be passed in a register instead
> of the stack, but not much of an issue on modern systems.
The reason is that tagged types are by-reference types. And that is
because one wanted to have T'Class <-> T conversions a mere view
conversions.
One language extension I always wanted were an ability to have classes
of types without having a tag embedded in the representation. So that
one could have Boolean'Class. In this model T'Class <-> T would be a
full conversion producing a new object. The types must be by-value then.
Furthermore for such types re-dispatch would be impossible:
procedure Foo (X : in out T) is
begin
T'Class (X).Bar; -- Error, T'Class (X) is a new object
--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Best use cases for OOP (resent quoted sorry)
2025-08-29 8:28 ` Dmitry A. Kazakov
@ 2025-08-29 9:14 ` Kevin Chadwick
2025-08-29 10:37 ` Dmitry A. Kazakov
0 siblings, 1 reply; 8+ messages in thread
From: Kevin Chadwick @ 2025-08-29 9:14 UTC (permalink / raw)
>One language extension I always wanted were an ability to have classes
>of types without having a tag embedded in the representation.
I understand the usability problems tags can cause but not sure I understand
the benefit. Would it allow memory mapped registers such as Timer_1 and
Timer_2 with some differences but whose shared components could be handled
by a procedure accepting 'Class even though those shared components were
memory mapped to different locations. If so I would love that. Even if it
would not enable that. Have you considered making a suggestion here?
"https://github.com/Ada-Rapporteur-Group/User-Community-Input/issues"
--
Regards, Kc
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Best use cases for OOP (resent quoted sorry)
2025-08-29 9:14 ` Kevin Chadwick
@ 2025-08-29 10:37 ` Dmitry A. Kazakov
0 siblings, 0 replies; 8+ messages in thread
From: Dmitry A. Kazakov @ 2025-08-29 10:37 UTC (permalink / raw)
On 2025-08-29 11:14, Kevin Chadwick wrote:
>
>> One language extension I always wanted were an ability to have classes
>> of types without having a tag embedded in the representation.
>
> I understand the usability problems tags can cause but not sure I
> understand
> the benefit. Would it allow memory mapped registers such as Timer_1 and
> Timer_2 with some differences but whose shared components could be handled
> by a procedure accepting 'Class even though those shared components were
> memory mapped to different locations.
Your Timer_1 and Timer_2 are limited types, so you cannot have a class
of them without burying a tag into. Since you cannot copy such things
you cannot convert Timer_1 to Timer'Class per view. Unless you allow
copy-in copy-out semantics.
> If so I would love that. Even if it
> would not enable that. Have you considered making a suggestion here?
>
> "https://github.com/Ada-Rapporteur-Group/User-Community-Input/issues"
<rant on>
No, because such changes are never accepted. One thing is to introduce
square brackets and break separation of interface and implementation
(all these bodies of functions in declarations,
if-/case-/for-expressions etc) and another thing is a serious overhaul
of the type system such as it was done in Ada 95.
Note that it is more than just handling external tags. It is a general
principle of a type constraint. Tag is a constraint of T'Class. So are
array bounds. So is dimension in the AdaCore hack of dimensioned types.
All these should have been discriminants. And all discriminants should
have been handled like array bounds are handled. That is when you
declare a constrained array String (1..80), the bounds are not there.
When you make it unconstrained (convert to String) the bounds are added
(e.g. passed around). Now compare that with a record discriminant, with
a type tag in T <-> T'Class etc.
Though it would be quite possible to make this backward compatible, any
proposal will be dismissed on the ground of "breaking" the language.
People think they hate OO, consider yourself. But it reality they hate
any type system which is an inch more powerful than C. A miniscule
minority could gritting the teeth accept Ada 83. But this is where the
train stops.
<rant off>
--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2025-08-29 10:37 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-28 14:40 Best use cases for OOP Kevin Chadwick
2025-08-28 14:45 ` Best use cases for OOP (resent quoted sorry) Kevin Chadwick
2025-08-28 15:12 ` Dmitry A. Kazakov
2025-08-28 18:28 ` Niklas Holsti
2025-08-28 20:23 ` Alex // nytpu
2025-08-29 8:28 ` Dmitry A. Kazakov
2025-08-29 9:14 ` Kevin Chadwick
2025-08-29 10:37 ` Dmitry A. Kazakov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox