remix logo

Hacker Remix

Ask HN: Memory-safe low level languages?

47 points by hyperbrainer 2 days ago | 105 comments

I am looking for memory-safe languages that can be used for systems/graphics programming. I love Rust, but it often feels like too massive a language with too much stuff going on. Is there a language like C, which is simpler (obviously without all the UB and other problems)?

This is an especially hard ask, given how useful the FP-like features of Rust are, and I find it almost impossible to live without them. Basically, I am looking for a middle ground between C/Zig and Rust.

One such language I have found is Austral[0]. What other such languages are there?

[0] https://austral-lang.org/

sn9 13 hours ago

You might try OCaml [0] or SML [1] if you want speed, memory safety, and an expressive type system.

[0] https://ocaml.github.io/ocamlunix/index.html

[1] https://matt.might.net/articles/best-programming-languages/#...

codr7 2 days ago

There have several attempts at cleaning up C without giving up too much of its simplicity; from what I can see, Zig is the only one even close to reaching critical mass.

A programming language is always going to make some kind of compromise; better at some things, worse at others.

Simplicity/power and safety pull the design in different directions.

chrisrodrigue 14 hours ago

Zig hits on a lot of Zen of Python.

> Beautiful is better than ugly.

> Explicit is better than implicit.

> Simple is better than complex.

> Readability counts.

What really sets Zig apart from the usual suspects (C, C++, Rust) is that it has first class compile-time reflection capabilities built into the language (comptime, @field, @typeInfo, etc.) rather than bolted on as macros or templates.

hyperbrainer 2 days ago

I don't mind the language having substantially worse "something" as long as it can be a smaller alternative for Rust, for the lack of a better word. Of course, there always needs to be some compromise. I don't mind that. I just have two requirements, and am curious to see how people have tackled that problem.

codr7 2 days ago

Sure, and I'm just as curious.

But at the same time, I'm pretty sure that smaller/simpler is going to mean less safe.

uecker 1 day ago

I think the opposite is true. The Rust philosophy is the idea that a complicated type system should ensure safety. This may work to some degree, but the overall complexity will introduce new issues. I say this as someone who was really excited about type systems in the past, but Rust is ... meh.

SkiFire13 1 day ago

> The Rust philosophy is the idea that a complicated type system should ensure safety.

I don't think the "complicated" is part of the philosophy. Rather the idea is that a "strong" type system should ensure safety. The general consequence of this however is that the language becomes quite restricting and limiting. Hence the need for more more complex feature that allow for greater expressibility.

hyperbrainer 1 day ago

I think the problem is that some of the more advanced things related to generics or traits are half-baked or maybe somewhat function only in unstable, leading to horribly written code, or code which takes far more complexity to run than it should.

tiffanyh 2 days ago

SPARK (Ada) is about as memory-safe as it gets.

https://github.com/AdaCore/spark2014

andsoitis 1 day ago

I was also going to suggest Spark https://www.adacore.com/sparkpro

There's also this paper, "Memory Safety in Ada, SPARK, and Rust"

https://www.adacore.com/papers/memory-safety-in-ada-spark-an...

tiffanyh 1 day ago

I’ve always found the table comparison (Rust/Ada/SPARK) from that same source to be very informative:

https://blog.adacore.com/should-i-choose-ada-spark-or-rust-o...

oconnor663 11 hours ago

Can you give some examples of Rust features that you don't need? Unfortunately a lot of common answers (the borrow checker, traits, move semantics) are things that are fundamental to the safety story. I guess one thing you could definitely subtract is async (Rust shipped without it after all).

whytevuhuni 9 hours ago

I would keep lifetime generics, but remove traits and type generics (and therefore the really complex trait bounds, most of the GAT/RPITIT shenanigans, etc). I feel like that would remove most of the complexity, while leaving a mostly C-like language.

At most it should have pointer generics (similar to void* or Box<dyn Any>), where the generic function can't assume anything about the data, the data has to be heap-allocated, and the generic function can own and move the pointer around. Enough to implement collections, maybe iteration, and nothing else. Enough to not need monomorphization.