Free monads in Ada

I disagree with your categorical approach, and I think there are applications and domains for which this is a perfect approach. Those tend to be more abstract domains.
Once you get to the raw software systems engineering that deals with the real-world, to the touch-the-grass programming, I agree with you FP doesn’t cut it.

… and the conclusion is that FP is badly needed in Ada? :laughing:

The conclusion is qualified that there is a range of problems that are solvable elegantly with FP idioms and were these implementable in hygeinc way, they would be desirable in any general-purpose programming language.

I’d rather not really talk specifically about FP though, because I never said that Ada badly needs it. In fact, I expressly tried to qualify what I said and merely noted my soft spot for FP (but also for type traits in Rust, an imperative language).

I’m much more interested in the underlying quest for higher expressivity and readability of code which helps construct elegant and correct programs.

This applies as much to goto, arithmetic if and EQUIVALECE blocks. For each language construct ever invented one can find a problem it elegantly solves. The question is the consequences for the rest of the language.

Rust cannot be seriously considered a shining beacon of advanced type system.

The litmus test for any type system feature is:

  • can this feature construct any of built-in Ada types?
  • can it create classes where Ada cannot? Say a class of integer types?

Type traits is a fancy word with no substance. You do not need anything but interface (=abstract type) to describe properties of a type implementing the interface. Languages with massively inferior type systems just hide their impotence behind word salad.

This is traits in Ada 83 (more than 40+ years ago):

generic
   type S is range <>;
package Bar is ...

This is Ada 95 (30 years ago):

generic
   type S is new T with private;
package Foo is ...

I like this. Unfortunately, there is an error:

Package Example.Child is
  Type Other_Color is tagged private;
  Overriding
  Function Image(Object: Color) return String;
Private
  Type Other_Color is new Color with null record;
  Function Image(Object: Color) return String is
    ("Black");
End Example.Child;

Image doesn’t override since Other_Color is not visibly derived from Color. Therefore Other_Color canot be converted to Color outside of the private visibility.
Please correct your otherwise excellent paper.

I don’t think user based indexing in general was a mistake. It’s definitely a needed feature. I do agree the implementation was very clunky. Implicit_Dereference is really clunky and very hard to do correctly. User defined iteration implementation was pretty clunky too.

Years ago (2019ish), I suggested aliased return types to Adacore. I see they got some discussion on the ARG end, so I hope that picks up some visibility. I think those could be helpful for some things in indexing (though doesn’t cover all the bases). At the very least, bounded containers could be much simpler to implement indexing and iteration on.

I suppose I didn’t communicate quite as effectively as I’d hoped: the “IMO user-defined indexing is a mistake” should have been explicitly qualified with “as-implemented, using aspects”. I’m honestly a little bothered by how you could think that I was thinking user-defined-indexing as-a-general-feature is a mistake given the context of the whole thread.

I haven’t had much trouble with Implicit_Dereference, though if we’re honest I haven’t used it extensively; but Implicit-Dereference (to include off objects/components) is really just a specific/special case of indexing as I noted up-thread.

I’m not sure how aliased return types intersects the notion at all… if anything, I’d think that a more useful construct would be a build-in-place return-mechanism. (IIUC, this would also handle the “Ada lacks constructors” argument some make.)

I’ve had generally good results from generics.

This argument is… honestly irrational.
It’s like criticizing that a function returning an integer is not an integer: of course it’s not an integer, it isn’t claiming to be. — What is termed a “generic package” is not a package, but more accurately “the generic construct whose instantiation produces a package”, which is far more wordy and “language lawyer-y” than is used in normal discourse.

It’s really tricky to do correctly when dealing with dynamically allocated memory (at least in the context of custom containers). You have to have some sort of system for preventing or detecting dangling references. It’s easy to mess that stuff up as a user. Obviously there are solutions, but implementing those solutions is tricker for less experienced folks (even some experienced folks get it wrong time to time).

I kinda wish there was some sort of aspect that would prevent a user from actually storing a refrence_type object at all. Still let the compiler make temporaries or whatever it needs under the hood, but prevent user made code from doing something like:

Reference : Vectors.Reference_Type := Some_Container.Reference(Some_Cursor);

Or if container aspect specifications (maybe wrong term here) would be allowed to assign operations in the private section. Then you could make your reference_types and associated operations private but still have indexing. Ala:

   type Container is tagged private
      with Variable_Indexing => Some_Private_Indexing_Op;
private
   type Container is tagged record
      -- stuff
   end record;

   type Reference_Type(Element : not null access Element_Type) 
      is limited null record;  -- Still need to do something here for dangling references potentially, but still safer than giving the user full access to the type.

   function Some_Private_Indexing_Op(Self : aliased in out Container; Position : Cursor)
      return Reference_Type is -- Implementation

I realize that has other implications, but just there could be other ways to make it safer or simpler than currently exist.

That fills me with joy but does not answer the question. I elaborate it more:

  • Create generic button
  • Create generic label
  • Create generic horizontal box
  • Instantiate all
  • Put button and label instances into the box instance

Not even close. Subprogram is an entity of the object language = Ada. Generic subprogram is an entity of a meta-language. It acts on the object language.

Yes it is a construct of the meta-language that produces code in the object language.

Macro definition would be succinctly and factually correct, but, strangely, people get offended. :laughing:

Right, my proposal would get rid of Reference_Type altogether.
But this is actually a separate/orthogonal issue from implicit-dereference altogether.
(Because dereference is a completely different operation than ‘copy’.)

IIUC, the thing that keeps it from being a macro is precisely that it isn’t textual-substitution… but this is a half-remembered discussion with, IIRC, a C/C++ guy.

Having a meta-language is not a bad thing, per se… the thing that you’d have to be careful of is preventing Turing completeness. (That way your solutions remain in the language-proper, instead of thrusting ad-hoc rules/limitations such as those done by C++ to prevent hanging the preprocessor/template-instantiation.)

Once it’s in, they’re not removing it. That’s my issue with them.

Macro substitution can be of any complexity and need not to be textual. You can expand or reuse some immediate code. Even if textual, texts can be annotated annotations validated etc.

It is a different language, that is.

The author is actually @mosteo, and he is part of the ARG :slight_smile:

1 Like

Yeah, I get that.
But that can be changed.
Especially if we get a non-GCC free/open compiler up and running.

1 Like