Ubuntu: not GNU anymore. An opportunity for Ada/SPARK?

In all fairness to myself, that’s links to the standard library, not The Rust Book. :grin:

Still, point conceded: some panics can be caught, so long as it isn’t the aborting kind.

Guess what Ada’s standard library does in the same circumstance.

2 Likes

Yes, I probably misremembered where I read that originally, sorry!

1 Like

Re: finding a key in Python or Ada.

I didn’t know that as a result of being new to Ada, but I could have guessed. You got me there!

I just checked the ARM, and, for Find for Map, it says that No_Element is returned if the key is not present. What am I missing?

I like the way it works in OCaml fairly well. There are two interfaces. One raises a “Not_found” exception. The other returns an Option, from which one can get the result using a match expression similar to the method in Rust. Unfortunately, there are no static analysis tools to help avoid unhandled exceptions in OCaml. (One exists for an old version of OCaml, but it hasn’t been updated, and I don’t think the license obviously allows modifications to be distributed.)

With Spark, at least I can avoid unhandled exceptions. The ReasonML community is trying to do something similar for OCaml.

It works if you remove this switch from the Alire generated gpr file.

           ,"-gnatW8" -- UTF-8 encoding for wide characters

Did you change the codepage to unicode?
(You need to be cognizant of the dependencies; FWIW, this is why I want a DB-amiable IDE with no/minimal dependence on the file-system: eliminate, in as much as possible, the dependencies.)

This indicates that the above (not setting the Windows commandline codepage) is at fault.

I have that in EVIL: evil-util.files.ads.

See the Abstracting TYPE and INTERFACE #104 ARG issue, interact and advocate for it.

The big problem with Python is the “It works on my computer” sort of attitude: it’s really easy for “smart people” to code up an unmaintainable, or hyper-weirdly configured system, that is unmanageable.

You are correct: the intention was to be able to, with minimal instruction/coaching, have subject-matter experts able to audit relevant pieces of code.

On the algorithmic side of things, having a distributed DB of algorithms, data-structures, and templates would be incredibly useful.

Actually this was the first thing I checked when I ran into this since I ran into problems with code pages (for different reasons) when writing Trendy Terminal in Ada. Normally Windows terminal starts up with code page 437, so I had tried UTF-8 (65001) and still get this issue.

I see this on Window and Linux. I was also seeing this when writing to file, which is where I originally ran into this problem before trying to simplify it (trying to write unicode lines to write directory trees and also trying to use emojis in blog posts in my generator). Alire writes -gnatW8 into the config by default, but I’ve tried with and without it and got the same result, even after cleaning and rebuilding.

Maybe it’s something Alire is doing.

Well, you need classes of non-tagged types first. That is String’Class, for example. For that you need an implementation that keeps the tag out of the specific instance. E.g. String has no tag. String’Class has a tag. Conversion between String and String’Class is not a view conversion anymore. Redispatch on String is not possible.

And you need to remove all hacks like aspects, attributes, discriminants when they play the role of a primitive operation. E.g. index is clearly a primitive operation, so is 'Length etc.

I do not think anything will happen. So, in practice consider String UTF-8, forget that Wide_String and Wide_Wide_String exist and you will be good.

After removing the switch from the Alire generated file, I run gprbuild directly, otherwise Alire will overwrite again the configuration. The Alire way would be to add the compilation switches in the alire.toml file to overwrite the Alire defaults.

The rationale for Alire including this switch is in Feedback on a possible Alire Unicode policy · alire-project/alire · Discussion #1334 · GitHub

In my opinion, this switch fixes some issues and breaks other things, so it is a mixed blessing. I think GNAT needs a new switch (or switch combination) that interprets source code as UTF-8, but reads from the OS environment as it is configured (in Unix-like systems according to the LANG and LC_* environment variables).

You didn’t read the proposal, because that’s exactly what it does.

No, you don’t need tags at this static/abstract level.

I don’t think more switches is the answer, so much as better defaults. They had the perfect chance to change the defaults when they released Ada2012, but they didn’t and so you’ve got a lot of inertia on bad-defaults. (The one that’s surprising is the defaults regarding assertions.)

Which is in direct contradiction with the first statement. Of course I need tags in order to use the array interface (any interface). Think about:

procedure Put_Line (S : String'Class);

How it is supposed to work without a tag identifying the specific string implementation?

There are only three forms of polymorphism:

  • static = generics (no run-time instances of classes)
  • ad-hoc = overloading, this is what Ada standard library does (no run-time instances of classes)
  • dynamic (has run-time instances of classes)

Ada non-tagged types lack the dynamic polymorphism, which is the core problem.

P.S. If you are serious about proposing a change, just show how your change would allow implementation of UTF-8 and UCS-4 strings with a code snippet of looping over/indexing the representation units (octet vs. 32-bit word) and looping over/indexing code points.

   S :: String'Class := UTF8_String'("hello");
   C : Character; -- Unicode code point
begin
   for I in S'Range loop -- Dispatches
      C := S (I);        -- Dispatches
   end loop;

Of course you don’t need tags to use an array’s interface: X : Array(1..5) of Integer:= (6,8,2,3,-1); may be referenced with X(3) and For Index in X'Range loop completely without tags, as we can do now.

How does the above work without specifying any actual array-type?

We don’t need dynamic polymorphism, precisely because the issue [metalanguage specification] is constrained within compile-time… though there could be some argument for allowing a form of self-evaluation/-manipulation/-curation akin to staged-compilation-systems, but at that point we’re essentially including the compiler in the runtime. (While that may be useful in some circumstances, such an “extended runtime” would be rather heviweight.)

The proposal is for a meta-language, and as yet it is not developed enough to propose syntax, therefore I decline your challenge as it would invite whinging about whatever syntax I would use and other bikeshedding. — that said, it would be simply defining the abstract interfacing of array (ie indexing) on the type-class, and then specifying to the compiler to use that abstracted-interface.

There would be no need, at all, for any sort of dispatching.

You had written:

Later you added:

I use Python a lot, and the natural inference to me what that you meant something like this sequence of instructions:

>>> M = {"a": 3}
>>> M["b"]
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    M["b"]
    ~^^^^^
KeyError: 'b'

Assumign that’s what you were thinking, the comparable Ada code would be

with Ada.Containers.Ordered_Maps;
with Ada.Text_IO;

procedure Test_Maps is

   package Char_Maps is new
     Ada.Containers.Ordered_Maps
       (Key_Type     => Character,
        Element_Type => Integer);
   Char_Map : Char_Maps.Map;

begin
   Char_Map.Insert ('a', 2);
   Ada.Text_IO.Put_Line (Integer'Image (Char_Map ('b')));
end Test_Maps;

When run, this results in: (additional output snipped)

raised CONSTRAINT_ERROR : Test_Maps.Char_Maps.Constant_Reference: key not in map

That’s my point.

You later reference Ada’s .Find method, and sure, that’s another matter. I’m not a Python expert, but for a long time I’ve understood that the Python way of doing the same thing is this:

if "b" in M:
   # do stuff

…which I guess is what your followup meant.

So I’m a bit confused by what you meant.

1 Like

Thanks. That’s enlightening.
I meant that Python doesn’t have the equivalent of Find for Map in Ada or Hashtbl.find_opt in OCaml.

Yes, that’s what my followup meant.
I could do:

def my_fun():
    # try could go here
    if "b" in M:
        print(M["b"])
    else:
        # other action
    # actions in common for both cases
    # except could go here
# end of def my_fun

without needing to use try-except for normal-case control flow, like:

def my_fun():
    try:
         print(M["b"])
    except KeyError:
         # other action
    # actions common for both cases

(I don’t remember if dicts are supposed to be thread-safe, but possibly “b” could be deleted by some concurrent thread between the if and the print. Even, in that case, I might be satisfied with try-except at the beginning/end of the function or a calling functio and not use it for normal control flow of my algorithm.)

It doesn’t look like a substantial difference: try-except instead of if-else. But in OCaml, I’m doing:

match (Hashtbl.find_opt M "b") with
| Some x ->
   (* do stuff *)
| None ->
   (* other actions *)

Which is conceptually what I’m trying to do: try to find it, and if I found it, then do something with it; otherwise, do something else. And all without involving errors.

I assume I would get that in Ada in a way something like:

-- ...
   x: Integer;

begin
    Char_Map.Insert ('a', 2);
    x := Char_Map.Find('b');
    if (x /= No_Element) then
        -- do stuff with x
    else
        -- other actions
    -- common stuff
end

I could still make a mistake and omit the if statement and start using x, but in this particular algorithm (that I’m imagining), there is something important that I need to do if I don’t find the entry with key ‘b’. Handling that with an exception doesn’t seem appropriate to me, but I maybe there is not a substantial difference, at least not in Python. Obviously, I wouldn’t forget the try-except, if that is my only way of handling the not found case. So, that might have been a poor example.

Thanks.

You do not use interface here. X has a specific type, the interface is implicit. E.g. the fact that

X : array …;
Y : String …;

share same interface is not used and cannot be used.

Like with any concrete type. Certainly you can use types separately. Remember, interface describes a collection of types.

Again, if you believe in that provide a sample implementation of Put_Line working with any string type.

Cool, show me Put_Line implementation.

Such a long thread and you all miss the point.

The only reason why Ubuntu is switching to Rust coreutils is here: Initial commit · uutils/coreutils@d4e96b3 · GitHub

Someone, 12 years ago, just started to write coreutils in Rust…

Now if you want to see Ubuntu switch to Ada/SPARK coreutils. You can debate for 12 years which of Rust or Ada has better Unicode support, or you can start writing coreutils in Ada/SPARK :sweat_smile:

8 Likes

Rust has a very devoted open source community using it for real work. They really like the language and like to use it everywhere.

And by “using it for real work”, I presume that means “paying” work. I think this is the difference WRT Ada adoption. When I had paying work with Ada, I could easily justify spending time doing “Ada adjacent” activities that were not paying. Kudos to those people who either have paying Ada work or are still able to contribute without it.

2 Likes

Nice talk from Sylvestre Ledru during last FOSDEM: FOSDEM 2025 - Rewriting the future of the Linux essential packages in Rust ?

1 Like

Are there plans for Interfaces.Rust and Convention => Rust? I don’t know how I would interface with a Rust lib in Ada.

Hi Riccardo, hi all,

For my part,

  1. I see no interest in recoding in another language something that works very well and has been extensively tested.
  2. In any case, it is a long-term task that will eventually produce a result for Ada’s image in 5 or 10 years.
  3. Moreover, I don’t believe it’s a good promotional use case, because replacing something that works with something that works the same is anything but spectacular and appealing.
  4. And anyway, I don’t think the Ada community has yet the scale necessary for this huge specific task.

Once again, it’s just my opinion, but I think that:

  • To justify the investment in SPARK, we need to target essential functions, not command-line utilities, whose bugs have little consequence anyway.
  • To gain some traction for Ada, I think it’s more effective to propose a different and visible app rather than a slightly improved version of an existing one. (And that probably implies giving up backward compatibility)