Basic computer games: rewrite in Ada?

If some of you have free time, want to exercise their Ada skills or learn Ada, it could be fun to provide Ada implementation for some of the 96 basic computer games. The current list of languages include a set of 10 languages. One requirement is that the language must be memory safe. They also speak about a general purpose scripting languages but this is not clear since rust, Java and Kotlin are listed.

3 Likes

Ada may not be considered memory safe by their definition. Do you know if they’ll accept Ada submissions?

EDIT: Nevermind, looks like they have an Alternate_Languages section in the repository for other language submissions, so it should be ok to submit Ada versions there at least, regardless of their criteria.

2 Likes

A survey of a large number of real-world Rust programs found that they all make extensive use of Rust’s unsafe features, so Rust is not really memory safe in practical use. There’s a memory-safe subset of Ada, and all of these programs may be implemented in it, so it should be just as acceptable as Rust.

2 Likes

I don’t disagree. However, they excluded other languages because of the same logic, so just going off of their discussion. I think mainly it comes down to how aggressively they think the language enforces those rules for the programmer.

I do wish Ada did a better job of defining rules for compilers to enforce memory safety. A lot of stuff is documented in the RM as unsafe/unchecked/bounded error/etc, but doesn’t have a way (via the language spec) to enforce that the programmer doesn’t use it (at compile time). For example in Ada you are allowed to use unsynchronized variables in tasks (though thankfully the new parallel blocks are stricter here), which can lead to data races.

I don’t know what survey you’re talking about, but at my job, with our very large code base, we use “safe” Rust all the time. The only time we use unsafe Rust is when we interact with other languages (C++, JavaScript).

If Rust isn’t memory safe, I’m not sure what languages are. Perhaps, in a sense, Rust relies on all sorts of low-level things, etc. But we basically never have memory issues.

I do wish Ada did a better job of defining rules for compilers to enforce memory safety. A lot of stuff is documented in the RM as unsafe/unchecked/bounded error/etc, but doesn’t have a way (via the language spec) to enforce that the programmer doesn’t use it (at compile time).

This is what pragma Restrictions is for. For memory safety,

pragma Restrictions (No_Allocators); -- Ensure memory safety

seems to do the job

1 Like

That would be insufficient for a memory safe language. It’s part of the puzzle but not all memory safety issues are allocator related unfortunately.

Embedded Rust uses unsafe all over the place. For the embedded code that I write Ada is far more memory safe than Rust would be. Unsafe is far less secure than unchecked_conversion. Ada is a much safer language than Rust.

Being able to search for unsafe in Rust is neat but using unsafe removes too many protections at once. Something they have tried to reduce, but it is still a sledge hammer for a nail today. And of course runtime protections (which Ada has much more use of with strong typing) are safer than compile time protections due to simplicity. Pragmas seem to be way more powerful actually. Granted an all encompassing safe pragma would be nice but that is what Spark silver mode produces.

I don’t deny that Ada can be safer than Rust for embedded; since I don’t work with embedded, I simply don’t know. I’m definitely aware that Ada has some memory layout features that are supposed to be a big plus. I doubt most developers work with embedded, so you might have a harder time selling them on, say, that particular feature.

On the other hand, when you write:

And of course runtime protections (which Ada has much more use of with strong typing) are safer than compile time protections due to simplicity.

…it makes me wonder what you’re talking about. “Ada has much more use of”… as opposed to what? Rust has both strong typing and runtime protections: index checking, over- and underflow checking, the requirement for explicit conversion of types such as integers or strings, etc. Meanwhile, Ada lacks Rust’s borrow checker, which you seem to disdain, though SPARK’s designers apparently disagree.

Ada/SPARK can learn from other languages, and it should, and it has, on multiple occasions (object-oriented, contracts, borrow checker). What makes Ada such a great language is that it incorporates them carefully, with great deliberation, so that it doesn’t have to walk back a major language feature, the way Rust had to walk back its async system some years ago.

I would not call Rusts typing strong else what would you call Adas? Rust does not have integer overflow checks nor ranged types nor Adas array capabilities so it’s ability to ensure safety through both compilation and runtime checks is much more limited.

I have never needed the borrow checker functionality that spark now has. Additionally spark silver mode can with comparible effort to Rust compilation ensure that there are not only no buffer overflows but also no exceptions or runtime errors.

Ada was one of the first languages with OO design features. Though I do not like fully fledged OOP such as inheritance for general use personally. It works in some specific areas.

I am also not saying that borrow checking is useless, just that it is rarely of use in Ada. The heap is often needed only because of e.g. Linux limiting stack use.

Definately and to avoid any potential argument then you could use Spark silver mode.

Here’s a pretty simply Rust program that disproves that assertion.

fn a(value: u8) -> u8 {
   value + 1
}

fn main() {
   println!("{}", a(u8::MAX));
}

When compiled and run:

thread 'main' panicked at 'attempt to add with overflow', rust_overflow.rs:3:4

I have never needed the borrow checker functionality that spark now has.

Completely beside the point.

Ada was one of the first languages with OO design features

Simula (60s) Smalltalk (70s), Objective-C (mid 80s), C++ (early 80s), Eiffel (mid 80s), Oberon (mid 80s), Oberon-2 (1991),Modula-3 (late 80s) all beg to differ. Ada was the first ISO standard object-oriented language, but it was not, by a long shot, one of the first languages with OO design features.

The heap is often needed only because of e.g. Linux limiting stack use.

Sure. Rust programmers also tend to work on the stack as much as possible.

As for Ada’s array capabilities, make a specific claim. Only then can I evaluate the statement. I strongly suspect that it will turn out like your mistaken assertion on integer overdlow checks.

Only in debug mode and limited to basic machine types. In production mode overflow checks are disabled by default.

Early 80s classes it as one of the first to me. Check out Grady Booch books.

Sure, and I can disable overflow checks in Ada for the sake of performance. That was even standard behavior in gnat until recently.

From my point of view, a language like Ada 83, which lacked inheritance, is not object-oriented. I’m aware that OO is sometimes defined differently, but even if you want to restrict so that its major feature is encapsulation on account of, say, packages, that strikes me more as an effect of modular programming, which was in abundance well before Ada, as well (e.g., Modula-2).

Interesting that it was in violation of the spec. Therefore non standard behaviour :slightly_smiling_face: