Yes.
package A is
type B is private;
private
type B is new Some_Tagged_Type with null record; -- Your extension here and ends here.
end A;
Yes.
package A is
type B is private;
private
type B is new Some_Tagged_Type with null record; -- Your extension here and ends here.
end A;
Except for child packages:
package A.Expose_B is
type B is tagged private; -- Same as A.B, but with tag exposed
private
type B is new A.B with null record;
end A.Expose_B;
To really prevent extension of a tagged type, it has to be declared in a body. Achieving that for a private type requires additional complexity. See the section of “Avoiding Access Types” called “Making Private Types Private” (there’s a paper based on the presentation in the Ada User Journal, 2024-09, and I have a PDF of it, but currently I don’t seem to be able to upload any files to Github; contact me directly for a copy.)
There’s a way that doesn’t require tagged-type, arguably better:
Package Example is
Type Public_Thing is private;
Private
Type Private_Thing;
Type Public_Thing is not null access Private_Thing;
End Example;
Package Body Example is
Type Private_Thing is ( One, Two, Three, Four );
End Example;
Is this what in C++ is called “pimpl” or “pointer to implementation”?
Yes, exactly.
The nice thing about this is that there’s three distinct view-levels/interfaces:
private
part, which is seen by child private-parts.body
— I forget if the body
of the child-package can see this, I’d have to review to be certain, but I don’t think so.Except that now you have to implement memory management, which is notoriously error prone. Access types should be your last choice, not your first.
This seems to be due to Github now using some library that my Firefox extensions block; I am able to upload using Chromium. The link I intended to include is Avoiding Access Types.
True; though if we (ARG) had done a little better with access-types in the last revision, we could have had non-pointer access-types… rather than merely automatic-dereference of access-discriminants. — With my proposal for a metalanguage abstracting types-on-properties and types-on-usage we could have self-finalizing types. (Actually, all types have a conceptual finalize, it’s just in most cases it’s the null-procedure and, on the conceptual-level, this is optimized-away as a premature optimization.)
Aside from the type-centric part, though, the metalanguage needs to be able to describe attributes & parameters: modes, possible implementation, passing-method (even things like call-by-name, for with Import, Convention => X
), etc… this, in turn, would allow for simplification of the language, such as the motivating example: the excessive verbosity (and generation of otherwise non-functional auxiliary-types) of doing user-defined indexing. (Add in a Finalize
[null procedure attribute] to the base-metatype for the type-hierarchy and Bam! now every type has a Finalize
and we could set it with For Some_Type'Finalize use Clean_Up;
or Type X is not null access Whatever with Finalize => Unchecked_Deallocate_X( X );
)
IMO, this is why an Ada metalanguage is so important: given the state of proving and model-checking now, if we can [re-]define Ada in terms of this metalanguage we can:
End Construct_Name;
allowing the compiler to error-check your structure to a degree).pop
), likewise cleans up the language [Ada.Containers.*
in particular].Finalize
example);I don’t think Ada has been evinced because of a performance penalty…
Back in the 1980, Ada compilers cost a lot… then many programmers choosed something more available. It could be Turbo Pascal, Turbo C (or other C compilers on Unix).
Now, with Gnat, Ada is free, but the most important thing is the ecosystem (even Python and Ruby suceed with a quite low performance). Most succesful languages are « battery loaded ». With my difficulties to package GnatGtk dependencies with my application, I am puzzle ! It is not the fault of Ada… but it is a decision point.
It remains the education (not enough people know Ada), and lazyness (begin instead of { is long… and avoiding integer conversion is tempting…)
And yes, I remain some very silly comments of the press when OS/2 arrived, the performance issue where measured so accurately that they forget to measure the robustness of the OS compared Win3.1… a joke !
Just a remark about GtkAda. It is difficult to install because it does not use Ada! It is configure/make and other non-Ada mess.
I would claim all problems with Ada tools to be attributed to cut corners when some scripting mess, XML, YAML, Python etc in play.
That’s one of the things that continues to confuse me about Ada and its standard library.
I cannot begin to wrap my head around the Ada library missing a set of algorithms based on ranges or slices or cursors or iterators or whatever they’re called this month.
I searched a bit for the rationale behind this omission and found an old chain [1] with messages from the author of Charles (the basis for Ada.Containers) who said:
Alright, but this was 20 years ago. I’m not sure the original “it would be too much” or the customary “this is outside the scope of the standard library” ever held and surely it does not today.
Ada is sometimes praised as a high-level language. To me there are few things more fundamental to high-level programming than proper abstractions for “data structures + algorithms”. The use of declarative style through standard algorithms and data structure transforms is so much safer and maintainable than reading someone’s raw loops (even if they are Ada’s elegant type of loops).
I continue to be mystified by the lasting exclusion of such “batteries” and the evident lack of interest in having them included.
Strongly disagree. Leave declarations to declarations.
On the page of recommendations I make a fairly detailed remark on some features of the standard library that need revision or implementation. It would probably help it gain traction if there were more comments along those lines, especially specific recommendations.
I’d add that this is a large reason for @Lucretia comment on that page that Ada is largely relegated from general purpose to embedded work. Queues are so difficult to work with that I’ve had other Ada users recommend their own custom-made queues, but even making a vector of a vector requires more boilerplate than it ought (or feels like it).
Interestingly Robert Dewar states in his Ada past, present and future lecture that OOP was left out on purpose. He also said on the Ada mailing list something like that being all for OOP is as damaging as being all against OOP and what’s best in any particular case can be rather nuanced.
I think C++ certainly has an unwanted complexity due to adopting everything and the kitchen sink.
Ada 83 scope was constrained in the design process, so I don’t see a contradiction here.
They were aware, and chose against it not to bloat the language.
The problem, of couse, is that those Simula67/Smalltalk flavours, which Ichbiah was familiar with, were pushed out of the industry and replaced with the “roman numerals of computing” type of OOP we have today.
I agree… but as a developper who want to package a program with a GUI, I need a whole set. And if Java/Swing is more convenient than Ada/GnatGtk, I may choose the first solution whatever the qualities of the respective languages.
Just think many developpers have developed in BASIC because Visual Basic or Access where handy…
I guess you mean « functionnal » instead of « declarative ».
Something like (in OCaml):
let filtered_and_sorted_names =
names
|> List.map String.uppercase_ascii
|> List.filter (fun name -> String.get name 0 = 'C')
|> List.sort String.compare
(It is a bit more wordy in Java, but there is the same presentation since Java8 and streams (2014)).
@dmitry-kazakov: I guess this example give you the intent of the « declarative » proposition. It is declarative in the sense of « it declares a variable »… but you have here an example of « standard algorithms » chained. I have omitted « data structure transformation » (all strings are converted to strings), but you may have the idea. You can use a function which use the name and query a database and add other information, etc.
I have already wrote a program with nearly ten of such steps (some straight from the standard library, some with user defined functions)… the main function is quite easy to read. There were « data structure transformations » such as string to XML parsing, extracting informations, grouping by a single field..
I think the C++ folks and the Ada actually have similar goals that cause the complexity. They want to fix things without removing old stuff. The C++ folks rarely want to break C backwards compatibility (I think it happens, but very rarely). The Ada folks similarly will avoid breaking backwards compatibility. From my own point of view I think this leads to a lot more complex and dense set of features.
I’m more of a fan of “make changes for Ada New_Version_X and let old versions be themselves and different if need be, Compiler vendors will support whatever their customers want regardless”. I think it would make new compilers easier tasks to start because a newer version of the language could then be simpler and have less things to implement and there’s no early pressure to support all language versions (which you can do later once you have revenue and a customer base that supports it). I think it would help the C++ language too if they left behind some things.
Though I understand not everyone likes this methodology.
Which I do not want to be programmed in a “declarative” way.
If you need to transform data structures, then you have chosen them wrong.
If you use XML for anything but interfacing some messy alien software, then your software is wrong.
Wasting time and resources. There is no “information” to “extract” in a properly designed program.
What you have described is a quite good summary how not to do software design in my view and why Ada must raise a pretty high barrier for those who are tempted to do this in Ada. There are lots of other languages that promote and encourage this sort of things why breaking what left of Ada?
I explicitly mean declarative disconnected from the imperative/functional distinction.
You will note that declarative is the opposite of imperative, so this may sound absurd, but nothing should stop a programmer from writing declarative code in an imperative language. Instead of reading a multiline for loop, I would prefer to be reading one liners such as Ada.Algorithms.Rotate(my_array, 5)
or my_list.Shuffle
.
Your example goes further than that. I like this type of syntax and I use it across languages in shell pipes, in R data projects, even in C++ with <ranges>, but it is a step further than what I’m talking about because Ada doesn’t even have these individual algorithms. And to me this is just not needed in Ada. There is too much “language” in Ada already. There needs to be much more “library”.
One can write it all himself, but it is not always straightforward, always hard to get right, and it is telling that virtually all industrial languages in use nowadays include robust sets of algorithms.
Watch it get standardised in Ada 2034.