Hacker News new | ask | show | jobs
by erik_seaberg 1022 days ago
Ada’s take on memory safety is pretty limited. Heap allocation is explicit; there’s a procedure literally named Unchecked_Deallocation to free a pointer. It does have thread-scoped locals and arenas, but nothing like declared lifetimes or borrowing. The spec allows for GC but I believe it’s rarely offered.

It’s safer than C, but I’m not quite sure where recent specs line up against C++.

3 comments

Only true for those stuck in Ada83.

People keep repeating this nonsense without updating themselves beforehand.

EDIT: To simply education on Ada,

Yes there was an optional GC, no one ever implemented it, so in Ada2012 got removed from the standard.

Almost everything can be allocated on the stack, so a strategy is to catch exceptions of not enough stack space and retry the same function with a smaller size for the data structure.

Ada95 introduced controlled types, which is basically Ada's version of RAII, no need to call Unchecked_Deallocation outside implementation details. Hardly any different from Rust code that uses unsafe underneath.

Ada/SPARK, now part of regular Ada specification, provides theorem proving capabilities, and contracts, allowing another safety level still not available in Rust.

Additionally Ada Core is contributing improving lifetime rules for access types, to have a kind of borrow checker light, when needed.

Finally, there are still 7 Ada vendors in business, with 40 years of experience deploying Ada into safety critical scenarios.

>Ada95 introduced controlled types, which is basically Ada's version of RAII, no need to call Unchecked_Deallocation outside implementation details. Hardly any different from Rust code that uses unsafe underneath.

This is basically like C++ destructors, but the problem is there are no move semantics in Ada, so you can't implement something like unique_ptr.

It's hardly comparable with Rust.

Yeah, that is what happens when one doesn't understand contracts and formal proofs are used, my dear newly created account to advocate for Rust.
I've noticed a pattern that many Ada advocates on HN don't really seem to know the language. So they often conflate SPARK with Ada (as you just did) and make unfounded claims about Ada's memory safety, portraying it as being on par with Rust.

It isn't on par, Ada has no lifetime management whatsoever. It doesn't even provide C++ style smart pointers out of the box. It is possible to implement something like shared_ptr, AdaCore even has a tutorial[1], but as the other commenter pointed out, the language doesn't provide the primitives necessary for unique_ptr.

SPARK does have something like this. In fact, in SPARK, every pointer assignment transfers the ownership. But SPARK and Ada aren't synonymous. SPARK is a formal verifier built on top of Ada. Like most such tools, it's very constraining and time-consuming. It's not something that every (or even most) Ada projects use.

Nevertheless, Ada is a perfectly good language, and it's probably safer than C++. It has some really cool features. I'm really fond of in/inout/out references (cppfront stole this), named function parameters, secondary stack, fine-grained control over records (struct) layout, etc.

However, I'm not so fond of the extreme verbosity. It isn't just because of Algol-like keywords, Pascal is less verbose than Ada. Even basic stuff like instantiating generics is very noisy:

   procedure do_something is
     package Integer_Vectors is new
       Ada.Containers.Vectors
         (Index_Type   => Natural,
          Element_Type => Integer);

       vec : Integer_Vectors.Vector;
     begin
       return;
     end;
In C++ that would be:

    void
    do_something(int arg) {
        std::vector<int> vec;
    }
[1] - https://www.adacore.com/gems/gem-97-reference-counting-in-ad...
SPARK is part of Ada, time to update your ISO Ada knowledge.
No, it isn't. I think you're confusing contracts (added in Ada 2012) with the entirety of SPARK.
What’s your sense of the size of the Ada job market? High hundreds? Close to 10,000? Is it static or growing or shrinking? Is there a preferred online community for Ada devs?
The Ada job market is still large in aerospace and defense industries where lives are on the line.
When you say large, what do you guess in actual numbers? Just a rough impression; I'm not going to hold you to anything.
Probably a thousand max in France? extrapolating from the ones I know, if you're talking defense/aeronautics (but I don't know or see everyone). Someone from AdaCore would give a better approximate.

We (embedded company) don't hire specifically with Ada experience (it's welcome but not mandatory) we just train people and then focus on shipping stuff.

Recent work have introduced lifetimes and an ownership model into SPARK (the reduced easier-to-prove Ada subset) https://blog.adacore.com/using-pointers-in-spark and hopefully it'll trickle down soon in Ada.

Edit: there's also reference counting and controlled types of course. And the secondary stack makes many uses of heap allocation go away.

That secondary stack is cool! I want it for my C++ programs, particularly std::string which always heap alloc.

begin

   return "Forty Two";
end Get_Answer;
Yes the secondary stack is this thing that make many (most?) heap allocations inexistant in Ada. So when you're talking about memory safety to an Ada dev as if it was the biggest pain, they might look strangely at you.

Yes indeed, heap allocated pointers are a PITA but we don't use so many of them. In 16 years as an kinda embedded dev on multiple MLOC codebases, I can count on my fingers the times I had to reach to pointers (and unchecked_deallocation) and didn't have a safer alternative (usually Controlled scoped pointer types, but also containers, indefinite types, and if really stuck reference-counted things if really you must murky the scope - but I'd flag the last one as 'need to show why you can't just copy the data around' at code review...).

Not saying it's not missing but I wish we spent more energy on automated proof of absence of runtime errors, large-scale whole-system static analysis, and even more stringent runtime or compilation checks. And better tooling/language support around network, threading, and distributed processing, improved test and coverage tools.

You're returning a string which size might be known at compile time through inter procedural analysis. Too easy.

The secondary stack would better be used for 'functions returning objects, of which you don't know the size, at call time'.

   function Any_Number (A : Natural) return String is
   begin
      if A = 42 return "A = Quarante Deux";
      end if;
      return "A =" & A'Image;
   end Any_Number;
Or for those allergic to begin/end

   function Any_Number (A : Natural) return String is (if A = 42 then "A = Quarante Deux" else "A =" & A'Image);
It does have Rust like borrowing in SPARK subset of the language.

There was attempt to have it in Ada 2022 Standard, but it came late. Committee decided it's best not to rush and let compiler vendors implement how they think is best and go from there.

>It’s safer than C, but I’m not quite sure where recent specs line up against C++.

Ada allows to return objects of variable size, so it's not that common that you actually need to explicitly allocate stuff. The general guideline for dynamic memory allocation is:

1) Use Second stack (this is how Ada allows to return object of variable size) 2) If cant use containers 3) If cant use controlled types (RAII) 4) Only then use New.