I'm very curious, because I don't know much about Ada.
How does Ada ensure that taking a reference/pointer to an element of a vector is safe? (i.e. the vector doesn't get reallocated/deallocated while the pointer still exists etc.) The three options I can think of are:
- pervasive garbage collection,
- disallowing such references and just copying the data out every time, and
- the borrowing/freezing system of Rust
Really only the latter is acceptable for the sort of 'fast' that Rust is aiming for.
Rust also allows for memory safe concurrent code. Message passing is safe due to move semantics and transferring ownership of data between threads, and shared memory is safe because the type system has the power[1] to ensure that any mutation of it is atomic (either using atomic data types, or mutexes). Does Ada allow for both 100% memory-safe message passing and 100% memory-safe shared memory?
As I understand it, Ada can't ensure that. The safe subset of Ada doesn't have allocation with multiple references. SPARK is mostly designed for things like avionics controllers, which tend not to allocate.
Sorry, those links are far far too broad to be useful for answering my specific questions for someone unfamiliar with Ada (like me).
I took the time to Google a little, and as far as I can tell, Ada just doesn't allow you to take a reference (aka 'access') into a vector: http://wiki.ada-dk.org/ada.containers.vectors#vectorselement I don't know if this means that it copies elements for every access or there is some black magic happening on the inside.
Similarly, it seems that the only shared memory is so-called 'protected' types, which compulsorily have a mutex around every interaction, even if the shared memory is entirely immutable, or if they are some other sort of atomic type.
As such, it seems that Ada doesn't necessarily have the same claim to those adjectives as Rust does. (Of course, I know next to nothing about Ada, so could easily be wrong.)
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure example is
data : array (1 .. 10) of aliased integer;
dataPtr : access integer;
begin
for i in 1..10 loop
data (i) := i;
end loop;
dataPtr := data(4)'access;
Put("The array 4 is ");
Put(dataPtr.all);
New_Line;
end example;
No. I'm interested in a dynamically allocated vector, where you take a pointer/reference/access to one of the elements and then try to add some more, which may cause the vector to reallocate and move in memory. Naively, this will leave the access dangling, pointing at invalid memory (which is not safe).
The three solutions I mentioned: GC protects against this by not deallocating the original array. Disallowing taking references makes the whole situation impossible. Rust protects against it by disallowing mutation of the vector while the reference exists.
I dare to say Ada and the respective compilers meet all those requirements.