I don't think I'm the only one.
I don't think I'm the only one.
Ada is as safe as Rust and lower-level but very fast and very mature. It gets a bit of a bad rap for being ugly, but after a couple hours the Pascal-ish syntax is not any uglier than C. The type system is much less expressive than Rust's, however, which makes a lot of things more awkward. What you lose in conciseness you make up for in performance and readability. Ada does require you to be extremely explicit about everything, which many people do not like. Still, if you're looking for a language around the abstraction level of C but safe and easily auditable, Ada is a quite well-designed language.
D is basically C++25. There's still some undefined behavior, but you hit it much less often. Also it has excellent metaprogramming support. It is not as safe as Rust, but a little safer than C++. Overall it's a very pleasant language if you're a C programmer and want something higher-level.
OCaml also has a syntax that many people find unpleasant at first. Personally I got over that pretty fast and now fine ML syntaxes beautiful. OCaml is essentially garbage-collected Rust with prettier syntax. It has predictable performance (in the sense of being fairly easy to predict what the compiler will generate—the GC will make actual runtime performance a little unpredictable, but isn't bad; probably because OCaml programs tend to involve much less GC pressure than Java or C#).
I don't think Go should be lumped in with those languages though. It is not very safe (it has a terrible error-handling mechanism and doesn't isolate unsafe code particularly well), it has a large runtime and slow generated code, it offers piss-poor abstractions, etc. If Go becomes the next popular systems language, language design will be set back another 30 years.
When programming Ada my thought process is relatively close to C (but with proper modules and generics). From what little Rust I've used, it was more like an ML—specifically more usage of higher-order functions and discriminated unions (which Ada supports, but is 100x less convenient than ML, but still 10x better than C's struct { enum { } what; union { } val; }; pattern).
In general, memory management is more manual in Ada than in Rust as well. Actually, Ada is technically less safe than Rust since you can use Ada.Unchecked_Deallocate to circumvent the accessibility checker and Ada doesn't have an equivalent of the unsafe { } block. But you almost always use RAII and memory pools and Unchecked_Deallocate for C types gets hidden in a RAII wrapper. Additionally, fat pointers are opt-in (though roughly as inconvenient as thin pointers), which can be useful for very low-level code. I believe Rust's pointers are always fat?
Also I went ahead and checked Rust performance again. I didn't realize you'd gotten so fast. Ada, like FORTRAN, does not allow pointer aliasing by default (there's an ‘aliased’ type qualifier though), so theoretically it can generate faster-than-C. Embarrassingly I don't actually know how alias analysis works in Rust, so maybe you have this advantage too.
One thing that you may not realize, talking about HOF and such: LLVM is very good at compiling them down. If you use a closure that doesn't actually close over anything, it will get turned into a regular old function, for example. Which means it can be inlined...
Rust pointers are not always fat. Slices are, but &T is a regular old pointer, as far as the assembly goes.
&mut T automatically gets `restrict` applied to it, basically, we do a lot of aliasing stuff as well.
Thanks for elaborating :) I should spend some time with Ada.
It also has support for hardware interrupts and real time programming.
A fellow stands up at the end and says, in detail, something that can be summarized as "it's all golden until you invoke the I/O monad."
Yes, most languages do, unless they are formally defined (ML is formally defined, but most other languages are not. In this book http://www.amazon.com/Masterminds-Programming-Conversations-... several of the language creators say that fully defining the language formally is not worth the effort).
Unlike C, Undefined Behavior is pretty limited in scope in Rust. All the core language cares about is preventing the following things:
- Dereferencing null or dangling pointers
- Reading uninitialized memory
- Breaking the pointer aliasing rules
- Producing invalid primitive values:
- dangling/null references
- a bool that isn't 0 or 1
- an undefined enum discriminant
- a char outside the ranges [0x0, 0xD7FF] and [0xE000, 0x10FFFF]
- A non-utf8 str
- Unwinding into another language
- Causing a data race
And all of those things require `unsafe`, so safe rust cannot do any of them (barring compiler or unsafe library or OS bugs).Edit: And I must admit I don't know much about language theory or formal definition, but there is also a self-described formal grammar [2].
[1]: https://doc.rust-lang.org/nomicon/races.html [2]: https://doc.rust-lang.org/grammar.html
let a = Int.max + 1
Produces a compile error as the overflow is within Swift's conception of a "literal expression".If we step out to a case where the overflow is not trivially a literal expression:
func foo(a: Int) -> Int {
return Int.max + a
}
foo(1)
This causes a runtime assertion failure in optimized or unoptimized builds.There is a (rarely-used) "Ounchecked" optimization level for which this program produces UB.
let x = std::u32::MAX + 1;
This line will generate a warning upon build, and in a debug build, will panic. In a release build, it will overflow.