# The state of Rust trying to catch up with Ada
----
## whoami
oli-obk
a maintainer of the Rust compiler
----
## what is this talk not about
Rust evangelism
Note:
I'm sure Ada has places where it could learn from Rust
you get enough of that from me whenever you talk to me.
---
## what it is about
* unsafe/unchecked
* generic packages/modules
* safety certification
* contracts
* subtypes
Note:
on everything else I think there's little difference in *capabilites*, even if there are in various important aspects of the usability and error avoidance.
----
### unchecked vs unsafe
```rust
#[no_mangle]
extern "C" fn malloc(_n: usize) -> *const u8 {
std::ptr::dangling()
}
```
Note:
extern + no_mangle not needing unsafe until very recently allowed you to do unsound things without mentioning unsafe
----
### generic packages/modules
```
error: expected one of `;` or `{`, found `<`
--> src/lib.rs:1:8
|
1 | mod foo<T> {}
| ^ expected one of `;` or `{`
```
Note:
We have negative support for it, not even diagnostics know what you meant.
----
### safety certification
Ferrocene (https://ferrocene.dev)
> [It’s official: Ferrocene is ISO 26262 and IEC 61508 qualified!](https://ferrous-systems.com/blog/officially-qualified-ferrocene/)
Note:
adacore internal drama
upper leadership severed coop with ferrous
core Ada folk quit (not just over this I think, but timings are curious)
----
## contracts
```rust
use core::contracts::*;
#[requires(x.bar > 50)]
#[ensures(|ret| *ret > 100)]
fn foo(x: Bar) -> i32 {
x.bar + 50
}
```
https://github.com/rust-lang/rust/pull/128045
Note:
very recent impl, not stable, may get dedicated (non-attribute) syntax.
SPARK contracts-in-comments became core lang feature a few years back
---
## pattern types/subtypes
Note:
finally we're getting to the real thing of this talk
----
### state on stable Rust
```ada
subtype Non_Zero is Integer range 1..Integer'Last;
subtype Non_Null_Foo is not null Foo;
```
```rust
use std::num::NonZeroU32;
type NonNullFoo = std::ptr::NonNull<Foo>;
```
Note:
hardcoded types using compiler-internal magic
----
### Tangent: strong vs weak type aliases
| `type Foo = u32;` | `type Bar = u32;` |
| ----------------- | ----------------- |
| `let x: Foo = 1;` | `let x: Bar = 1;` |

Note:
There's not implicit type conversion or anything, they *are* the same type
Rust uses the "newtype" pattern instead, giving you more control but less convenience
----
### Patterns
```rust
match foo {
1..100 => {}
_ => {}
}
```
```ada
case Foo is
when 1 .. 100 => null;
when others => null;
end case;
```
----
```rust
match bar {
Dog | Cat | Bat => {}
_ => {}
}
```
```ada
case Bar is
when Dog | Cat | Bat => null;
when others => null;
end case;
```
----
### Matching on two things simultaneously
```rust
match (foo, bar) {
(1..10, Dog | Cat) => {}
(10..20, Dog | Cat | Bat) => {}
(_, Bat) => {}
_ => {}
}
```
----
```ada
subtype Non_Zero is Integer range 1..Integer'Last;
subtype Non_Null is not null SomePointer;
```
```rust
type NonZeroU32 = u32 is 1..;
// non-null is WIP
type NonNull = *const Thing is !null;
```
----
### So what's the difference?
* pattern types need explicit creation
* instead of just being part of type conversion
* pattern types do not do strong typing
* `u32 is 1..` is always the same as any other `u32 is 1..`
* pattern types only coerce, they don't relate
----
### Creation
```rust
let x: u32 is 1.. = 42;
```
```ada
subtype Non_Zero is Integer range 1..Integer'Last;
X: Non_Zero := 42;
```
Note:
not on nightly yet, but PRs are open
----
```rust
let a: u32 = 42;
let x: u32 is 1.. = transmute(a);
```
```ada
subtype Non_Zero is Integer range 1..Integer'Last;
A: Integer := 42;
X: Non_Zero := A;
```
Note:
we don't even allow you to go from `u8` to `u16` silently.
so.. not happening
----
### Future creation
Without specifying the pattern again:
```rust
type Grade = u32 is 1..=6;
type Passing = u32 is 1..=5;
let grade: Grade = read_from_somewhere();
if let Some(passing) = Passing::try_from(grade) {
// yay
}
```
Note:
via automatically implemented traits
----
### Patterns can be combined
```rust
type SomePercent = Option<u32> is Some(0..=100);
type Disjunctive = u32 is 0..=100 | 500..=1000;
type Tuple = (u32, &str) is (0..=100, "cake" | "fruit");
```
Note:
not implemented yet
"obvious" extension due to patterns allowing this in general
---
## Summary
---
* TODO
* generic modules
* WIP
* contracts
* pattern types
* idiomatic conversion from/to
* caught up
* safety certification
* sound-by-default: `unsafe` opt-out
Note:
strong type aliases are probably not happening.
{"title":"The state of Rust trying to catch up with Ada","description":"extern/no_mangle not needing jnsafe","contributors":"[{\"id\":\"ce357653-6779-4c50-b873-5c2ef0815935\",\"add\":6158,\"del\":1290}]"}