Making a game in Ada with Raylib

Patrick Kelly: https://youtu.be/0XDamZHwTo0

Patrick posted that resignation video about 4 years ago. I think there was someone else who had a similar pile-on quite recently; he does a podcast about programming languages. He only planned 2 or 3 episodes on Ada, so it’s not as though our bad treatment lost us a continuing resource.

That said, let’s not make the same mistake again!

2 Likes

The source will be released to gh tonight at the end of the stream, apparently.

Eepers

2 Likes

Episode 20 had no Ada takes, so I will not be commenting on it. My comments/reviews about Tsoding’s wonderful journey can be found in my previous posts with all their edits.

As Luke just added, the repo is open. He encouraged anybody to use it and improve it as they see fit. However, he said nothing about letting PRs be merged. I saw that he merged a fix to the code, so that is good. Maybe some simplifcations and cleanups will be allowed. He really likes it when something makes the code cleaner, leaner and with less bugs; specially when the changes delete more lines than the ones they add.

He also learned about Ada in his journey. At the beginning he did not use some features (see renames or importing C functions as part of the external pure Ada procedures) as he did not know they existed. Maybe it is worth submitting a couple of PRs that clean/organise his code with the features he started using at a later point in time.

I think a great PR would be to put all the Raylib C functions as part of the internal declarations of pure Ada functions and let the body of those functions cast the Ada types to the C ones. This would greatly improve the type casting in the main game file and it would make it a pure Ada file, without the necessity of using Interfaces.C :slight_smile:

2 Likes

The guy is quite funny actually, it was fun watching the first part of the first video.
I can’t criticize him too much because I guess I behave like him every time I have to explore something in C!
I don’t think C should be forbidden, but it definitely should not be used for everything. He definitely has a point in that lots of libraries are written in C and then bound in Ada… Most of these are however widely used and tested. However maintaining theme is often a pain. So in any case it is a very wise advice to start a transition to other programming languages.

I can confirm that maintenance of bindings is a pain.

Specially when libraries are continuously being modified and interfaces change like the weather on April in Belgium. I had the impression GTK was like that. For that reason I am happy GTK3 is finally no longer developed!

I made a pull request for a clear simplification, but for the moment, he hasn’t put attention to it. Let’s see if it’s just a matter of time.

So I was watching episode 7 at right at the beginning he was excited to try out variant records and immediately hit a wall and eventually had to give up. He ran into the age old problem of variant records being unconstrained/indefinite and trying to use them with a standard container (which only takes definite types). He didn’t find the solution. I thought this might be a good place to start. Do a small issue on his Item type with the description offering a small explanation of why it wouldn’t work and offering some alternatives to how to approach it. Go for short explanations (this means not always 100% technically correct in order to be concise), and lots of small examples.

See an example of what I am thinking below:

Problem:

Cannot use a variant record with Hashed_Maps or arrays. It complains about unconstrained subtypes.

Explanation of why it doesn’t work:

Since a variant record can have multiple variants with all different sizes, the Ada compiler can’t determine how much memory to allocate in general. In contrast both arrays and Hashed_Maps requires a type with a known size at compile time.

Option 1 to fix it:

Add a default value to the discriminant. This allows you to switch variants at run time and tells the compiler to pick a size (The largest variant’s size). Doing this you can use the type with Hashed_Maps and arrays

with Ada.Containers.Hashed_Maps;
    type Item_Kind is (Item_None, Item_Key, Item_Bomb_Gen, Item_Checkpoint);
    
    type Item (Kind : Item_Kind := Item_None) is record
       case Kind is
            when Item_Bomb_Gen => Cooldown : Integer;
            when others        => null;
        end case;
    end record;

    package Hashed_Map_Items is new
        Ada.Containers.Hashed_Maps(
            Key_Type        => IVector2,
            Element_Type    => Item,
            Hash            => Hash_IVector2,
            Equivalent_Keys => Equivalent_IVector2);

OR

    type Item_Kind is (Item_None, Item_Key, Item_Bomb_Gen, Item_Checkpoint);
    
    type Item (Kind : Item_Kind := Item_None) is record
        Position: IVector2;
        case Kind is
            when Item_Bomb_Gen => Cooldown : Integer;
            when others        => null;
        end case;
    end record;

    type Item_Index is range 1..100;
    type Item_Array is array (Item_Index) of Item;

Option 2

If you don’t want to change your variant record to have a default discriminant and are willing to use containers use the Indefiniite_ versions of the containers. For example, with Hashed_Maps it would be Indefinite_Hashed_Maps. Those are designed to handle variant records, Strings, unconstrained arrays, etc. NOTE: You can use the Indefinite_Vectors package to simulate using an array of these instead of a map.

with Ada.Containers.Indefinite_Hashed_Maps;
    type Item_Kind is (Item_None, Item_Key, Item_Bomb_Gen, Item_Checkpoint);
    
    type Item (Kind : Item_Kind) is record
       case Kind is
            when Item_Bomb_Gen => Cooldown : Integer;
            when others        => null;
        end case;
    end record;

    package Hashed_Map_Items is new
        Ada.Containers.Indefinite_Hashed_Maps(
            Key_Type        => IVector2,
            Element_Type    => Item,
            Hash            => Hash_IVector2,
            Equivalent_Keys => Equivalent_IVector2);

OR

with Ada.Containers.Indefinite_Vectors;
    type Item_Kind is (Item_None, Item_Key, Item_Bomb_Gen, Item_Checkpoint);
    
    type Item (Kind : Item_Kind) is record
       Position : IVector2;
       case Kind is
            when Item_Bomb_Gen => Cooldown : Integer;
            when others        => null;
        end case;
    end record;

    type Item_Index is range 1..100;

    package Vector_Items is new
        Ada.Containers.Indefinite_Vectors(
            Index_Type   => Item_Index,
            Element_Type => Item);
4 Likes

I believe whether the max storage is allocated or not is compiler dependent. For example, I read that Janus/Ada always dynamically allocates the variant part to exactly what is needed. GNAT chose to implement it by allocating a max size.

2 Likes

Yep, but he is using GNAT, so just keeping it simple. Trying not to overcomplicate things if that makes sense?

Ah ok, understood. I watched some of episode 10 and he finally figured out how to use the default initialized variant record which he loved. If I am not mistaken, Irvise mentioned this in a previous post.

Tsoding answered my pull request and was critic about Ada this time due to a bug he encountered in FSF GNAT 12. He says using floorf() from C was intentional due to mistrusting Ada management of floats in general. I don’t know if he’s half joking about this, because the relation is very unclear. In any case, I have tried to defend the case agreeably, so readers don’t buy that bad impression.

2 Likes

Gotcha. I’m still behind on videos (on episode 7 still).

What do you think about the presentation of it (as a general approach)? I tried to break it up into clear and small sections with code examples. I was trying to balance how much information to provide with accuracy (with some compromises in both areas).

I regard your idea and the examples very positively. What do you plan to do?, open an issue with these proposals?

Regarding my pull request, I’m disappointed by his behaviour there; he closed it saying that “No, I’m sorry. The trust is broken beyond repair. Nothing can be done at this point.”, but nothing about why the change is not accepted or whether his bad judgement on the floating point management was justified by the bug or not.

This is not rational. Probably he’s just acting as the streamer he is, he’s a showman; so don’t expect a temperate evaluation of Ada or GNAT. There’s only two possibilities, either it is a terrific perfect language, the best kept secret in SW engineering, or it is a terrible bad idea, a goof. It’s unfortunate that he stumbled upon that GNAT bug, because it seems his judgement is going to fall on the negative side, no matter what we do. I hope at least that part of his audience can see beyond what their influencer is saying and get some interest in trying themselves.

It’s unfortunate, because it’s one bug that is only present when you consciously activate the Ada 2022 mode, for a compiler in which it is not the default. Only to use [] as the single new feature (and probably directed by misleading compiler warnings)…

2 Likes

I added a comment there too. TBH, he just comes across like other c programmers wanting to find reasons not to like the language, although he’s gone further than most.

The community was gifted a ten episode usability study of Ada by a talented C programmer. How many people who had never seen Ada code before, have seen it now?

Given Tsoding’s experience, what documentation, tutorials, and demos can you make to help the next person running into those problems?

5 Likes

I don’t have any specific plans. I was just trying to get discussion going as a community (per my earlier post). I’m not a great wordsmith, so I was more trying to get some ideas out to get people thinking.

Like the thing I posted above wouldn’t be worthwhile since he already figured out how to do default discriminants later, but maybe someone else can see my presentation and maybe get some ideas for a different thing they think he might be interested in learning about in the language (not that my example was great, but maybe it at least gets people thinking about better ways to present things).

Your text would already be a great contribution for the Tips & Tricks section of ada-lang.io. More of that kind would be useful. They could have references to the instant in Tsoding’s stream as an example of a new user encountering the problem or made totally independent; I’m not sure what’s best.