Live data from Hacker News

Should I choose Ada, SPARK, or Rust over C/C++? (2024)

blog.adacore.com

151–160 of 173 posts

Re: Should I choose Ada, SPARK, or Rust over C/C++? (2024)

#151

Earlier quoted context omitted.

This is the smoking gun for me: procedure Overflow_This_Buffer with SPARK_Mode => On is type Integer_Array is array (Positive range ) of Integer; Int_Array : Integer_Array (1 .. 10) := [others => 1]; Index_To_Clear : Integer; begin Ada.Text_IO.Put ("What array index should be cleared? "); -- Read the new array size from stdin. Ada.Integer_Text_IO.Get (Index_To_Clear); Int_Array (Index_To_Clear) := 0; end Overflow_Thi…

> How did you prove that no one could just put in an arbitrary integer into that function? Does it fail to compile? The answer quite literally follows immediately after the code sample you quoted: > Attempting to prove the absence of runtime errors gives us the following warnings: buffer_overflow.adb:162:26: medium: unexpected exception might be raised 162 | Ada.Integer_Text_IO.Get (Index_To_Clear); | ~~~~~~~~~~~~~~~…

> The SPARK prover correctly notices that there's nothing stopping us from entering a value outside the array bounds. It also points out that the Get call we're using to read the integer from stdin can raise an unexpected Constraint_Error at runtime if you type in anything that can't be parsed as an integer.

To me, this doesn't sound like something unique to spark. Let's return to the solution example:

    procedure Overflow_This_Buffer
       with SPARK_Mode => On
    is
       type Integer_Array is array (Positive range ) of Integer;
       Int_Array : Integer_Array (1 .. 10) := [others => 1];
       Index_To_Clear : Integer := Int_Array'First - 1;
    begin
       while Index_To_Clear not in Int_Array'Range loop
          Ada.Text_IO.Put ("What array index should be cleared? ");
          --  Read the new array size from stdin.
          Ada.Integer_Text_IO.Get (Index_To_Clear);
       end loop;

       Int_Array (Index_To_Clear) := 0;
    end Overflow_This_Buffer;
All you have done here is proven that within the vacuum of this function that the index will be a valid one. Indeed, this is even confirmed by the article author just prior:

> If we wrap the Get call in a loop, and poll the user continuously until we have a value within the array bounds, SPARK can actually prove that a buffer overflow can't occur. (Remember to initialise the Index_To_Clear variable to something outside this range!)

You have to poll the user continuously until a valid input is given. Again, I don't see how this is any different or special compared to any other programming language that would handle the error by asking the user to retry the function.

> Key word here is can. You can write correct software using any language, from raw binary to theorem proving languages, but some languages check more properties at compile time than others. What using something like SPARK/Lean/Agda/Rocq buys you is the "more" part, up to allowing you to eliminate runtime checks entirely because you proved at compile time that the corresponding error conditions can not happen (e.g., proving that indices are always in bounds allows you to omit bounds checks). That's not something the more popular languages are capable of because their type system is not expressive enough.

But I think the discussion here is about Rust, Ada, C/C++ no? The type system in Rust, Ada, and C++ are all robust enough at least to accomplish this.

> This seems contradictory, especially when considering that type checking is creating a formal proof?

Exactly! This is the root of my issue: you can accomplish this magical "proof" you speak of without using SPARK or Ada or any special "contract" language.

Re: Should I choose Ada, SPARK, or Rust over C/C++? (2024)

#152
post #111

Earlier quoted context omitted.

Of course I can overload >> in Python, but I cannot foul up output stream state because it doesn't exist. Formally there is little difference between C++ and Python operator overloading and both languages have good syntax for it, but C++ has many rough edges in the standard library and intrinsic complications that can make operator overloading much more interesting in practice. For instance, overload resolution is ra…

It is only one pip install away, if anyone bothers to make on such set of overloads.

People don't though. That's the big difference. There's a certain taste in the Python community.

Re: Should I choose Ada, SPARK, or Rust over C/C++? (2024)

#153
post #66

Earlier quoted context omitted.

Aside from technical factors, there are social factors involved. For example, both Python and C++ has operator overloading. But in C++ that's horrible and you run screaming from it, while in Python land it's perfectly fine. What is the difference? Culture and taste.

> Culture and taste. You mean accumulated prejudices, myths, and superstitions that most in any given community (programming language related or not) won't challenge for fear of being cast out of the group for heresy.

Err... no I mean the good taste not to overload >> for console output. There's no fear of being cast out, don't be silly.

Re: Should I choose Ada, SPARK, or Rust over C/C++? (2024)

#154
post #104

Earlier quoted context omitted.

It's the exact same thing except in Python the community largely has taste. In C++ `cout >> "foo"` exists in the standard library.

I love how among a certain set the word "taste" has become an all-purpose substitute for having an argument or making a case. It basically means "I have more social media follows than you do, so I'm right"

I believe the C++ community as a whole are quite convinced that overloading >> for stdout was a mistake.

Re: Should I choose Ada, SPARK, or Rust over C/C++? (2024)

#155
post #90

Earlier quoted context omitted.

Though if you do that km times km isn't km it is a volume - so your custom type would be wrong to have all operations. what unit km times km should be isn't clear.

These libraries already exist. God how people underestimate C++ all the time. Of course you can use a unit type that handles conversions AND mathematical operations. Feet to meter cubed and you get m³, and the library will throw a compile error if you try to assign it to anything it doesn't work with (liters would be fine, for example)

I know of about 7 different libraries, 5 of them private to my company (of which 4 are not in use). Every one takes a fundamentally different approach to the problem.

> Feet to meter cubed and you get m³, and the library will throw a compile error if you try to assign it to anything it doesn't work with (liters would be fine, for example)

Liters would not be fine if you are using standard floating point values since you lose precision moving decimal points in some cases. Maybe for your application the values are such that this doesn't matter, but without understanding your problem in depth you cannot make the generic statement.

I could write books (I won't but I could) on all the compromises and trade offs in building a unit type library.

Re: Should I choose Ada, SPARK, or Rust over C/C++? (2024)

#156
post #90

Earlier quoted context omitted.

Though if you do that km times km isn't km it is a volume - so your custom type would be wrong to have all operations. what unit km times km should be isn't clear.

who said `operator*` needs to return the same type as its parameters?

operator* can return exactly one type. You can choose which, but metric offers many possible choices, and with floating point math on computers you will lose precision converting between them in some cases so you need to take care to get the right on for your users - which will not be the same for all users.

Re: Should I choose Ada, SPARK, or Rust over C/C++? (2024)

#157
post #25

Their example of why Ada has better strong typing than Rust is that you can have floats for miles and floats for kilometers and not get them mixed up. News flash, Rust has newtype structs, and you can also do basically the same thing in C++. I don't know much about Ada. Is its type system any better than Rust's?

This was posted to about a day ago: https://github.com/johnperry-math/AoC2023/blob/master/More_D... But a noteworthy excerpt: ``` Ada programs tend to define types of the problem to be solved. The compiler then adapts the low-level type to match what is requested. Rust programs tend to rely on low-level types. That may not be clear, so two examples may help: Ada programmers prefer to specify integer types in terms of…

Ada's mechanism is what Fortran has been using and doing for decades.

Re: Should I choose Ada, SPARK, or Rust over C/C++? (2024)

#158

Earlier quoted context omitted.

These libraries already exist. God how people underestimate C++ all the time. Of course you can use a unit type that handles conversions AND mathematical operations. Feet to meter cubed and you get m³, and the library will throw a compile error if you try to assign it to anything it doesn't work with (liters would be fine, for example)

As a more general rant - people who have maybe used 5% of the feature set of C++ come along and explain why language X is superior because it has feature Y and Z. News flash, C++ has every conceivable feature, it's the reason why it is so unwieldy. But you can even plug in a fucking GC if you so desire. Let alone stuff like basic meta programming.

GC was removed from the C++ standard in C++23 because all the compilers were like "hell no" and it was an optional feature so they could get away with not adding it. So this optional feature never actually existed and they removed it in later standards.

Re: Should I choose Ada, SPARK, or Rust over C/C++? (2024)

#159
post #25

Earlier quoted context omitted.

This was posted to about a day ago: https://github.com/johnperry-math/AoC2023/blob/master/More_D... But a noteworthy excerpt: ``` Ada programs tend to define types of the problem to be solved. The compiler then adapts the low-level type to match what is requested. Rust programs tend to rely on low-level types. That may not be clear, so two examples may help: Ada programmers prefer to specify integer types in terms of…

Ada's mechanism is what Fortran has been using and doing for decades.

F'77 added arbitrary lower bounds on arrays, including explicit-shaped and assumed-shaped dummy arrays. It is a useful and portable feature, though somewhat confusing to newcomers when they try to pass an array with non-default lower bounds as an actual argument and they don't work as one would expect.

F'90 added arbitrary lower bounds on assumed-shape dummy arrays, as well as on allocatables and pointers. Still pretty portable, though more confusing cases were added. F'2003 then added automatic (re)allocation of allocatables, and the results continue to astonish users. And only two compilers get them right, so they're not portable, either.

Ada's array indexing is part of its type system. Fortran's is not (for variables).

Re: Should I choose Ada, SPARK, or Rust over C/C++? (2024)

#160

Earlier quoted context omitted.

who said `operator*` needs to return the same type as its parameters?

operator* can return exactly one type. You can choose which, but metric offers many possible choices, and with floating point math on computers you will lose precision converting between them in some cases so you need to take care to get the right on for your users - which will not be the same for all users.

One return type, for any given combination of parameter types, not to mention the possibility of templating to manipulate the return type….
Post reply on HN