I am working on a programming language that is more secure than Rust.. In Rust

This language, is called HolyLang, currently I am working on the bootstrap phase of it.

It is written in pure Rust, with 0 dependecies. Handmade simple recursive-down parser and developed paranoidly with defensive coding techinques.

Additionally, for the parser and semantics layers, I have over 100% unit test coverage, not just lines covered, but also regions, functions and branches covered! Extremely time consuming, but worth it.

README:

HolyLang is more secure than Rust, but not as performant as Rust. The purpose of HolyLang is divine security, not speed.

  • HolyLang has readable syntax, and semantics. That is a security feature in its own because readable code = auditable code = maintainable code = probably secure code.
  • HolyLang has no borrow checker, and yet is still more secure than Rust. programs can be easily reasoned about due to the simple binary safey model of “move, or copy”.
  • HolyLang arithmetic is always checked, including bitwise. Floating point arithmetic is also always checked.
  • HolyLang has no warnings, only errors. Unreachable code? Error. Unused variable? Error. Etc.
  • HolyLang forces documentation for functions, structs, and constants.
  • HolyLang has no type inference, everything must be explicilty stated.
  • HolyLang does not allow overshadowing at all. Making codebases look cleaner, and reducing likelyhood of logic bugs.
  • HolyLang lock and unlock statements allow you to declare “zones” where variables behave as constants, dynamically.
  • HolyLang’s bootstrap compiler transpiles down to pure Rust for a mathematical guarantee of safety: "If Rust is safe, then HolyLang must also be at least as safe as Rust".

.. and a lot more! This is just the bootstrap compiler, the actual compiler will have even more security features, such as static stack analyzes that guarantee (at compile-time!) a program cannot overflow the stack, allowing for even stricter security than Rust, and even other formally verified languages like Ada SPARK, whom have no stack overflow protection.

I already have compiler warnings as errors, but, I still haven't integerated clippy yet, so code base is certainly going to get very cleaner as soon as I am finished with the PR I am working.

Any feedback on syntax/ semantics, whatever, is welcome. Also contributions are welcome

Looks interesting! For the safety aspect to be interesting I think you will need to describe exactly how it provides safety -- the description of locking is not enough IMO.

This bootstrap compiler purpose is only to compile the up coming compiler.

The actual compiler will have static stack analysis to allow for complete stack overflow protection at compile time. Something which Rust, and even other languages lack.

But, even the bootstrap compiler is more secure than Rust, because it enforces checked arthiemtic. even bitwise shifts are checked (like shift amount is not negative , nor exceeds bit width), and floating points are also checked against inf/nan. I know that floating point checking goes against the spec, but that is what I decided on doing.

Also the syntax and semantics readability is in its self a security feature, because it makes it easy to reason about codebases. readable code = maintainable code = auditable code = probably secure code.

The "lock" and "unlock" are still work in progress. ultimately, I am doing a PR where variables will be similar to rust behavior, where they're immutable (locked) by default. So, once the PR is complete, variables with expliclit values are locked by default, while ones that aren't expliclity initalized, are unlocked by default.

More on lock/unlock thing: It allows you to make a variable mutable / immutable. Basically declarating "zones" where the variable is mutable / immutable, to make it easier to reason about programs for auditing purposes, and also reduces logic bugs.

Like take the following imaginary code

func some_long_function(a int32) {
own x int32 = some_other_func(a)
lock x

# Some long code blocks here

unlock x
x = 5

} 

Basically, the "zone" from "lockk" and "unlock", is guaranteed to ensure x is never modified. but still allow you to re-modify it. this is not a wow feature or anything, but its better than equivalent rust approach of overshadowing with different mutability imho.

It doesn't sound like you have a model for memory safety quite yet.

I don't actually see any security features mentioned? What does it do to know the difference between, say, returning an image from the image library vs a copy of my passwd file?

Or by "security" do you just mean "can't abort"?

TBH, I've never seen this do anything useful. It just results in tools like SubMain / GhostDoc - Painless Help Documentation that bring the codebase to a worse position than having zero documentation.

As in, memory safety and logic safety.

Rust covers memory safety well, but not logic safety very well..

Code documentation is powerful if done right... I am not here talking about "documentation" that just rehearses what the function header is, I am talking about comment that describes the function purpose its self..

The primary safety model of the language is the "move checker". Which is like borrow checker, except. there is no borrowing. no aliasing, no references, nothing. you either move or copy.

At end of function, all data is freed, including heap allocated data, unless they're returned.

This model prevents race conditions, use after frees, etc, it's like using Rust, but you never borrow, you always either move, or you clone (copy in holylang).

Yes, I am aware, writing a high-performance server, or a game engine, or whatever in this language will be painful and slow, but this is what I came up with, to make reasoning about codebases easier imho.

This is incomplete because it is extremely inconvenient to call a function that modifies a parameter when you must pass it and return it (move twice), and there is nothing you've said about shared state.

And how are you enforcing that the documentation actually does that?

If you're not, then you're not getting anything from a mechanical check that someone put /// todo on everything.

There is no shared state. That's the thing.

Yes.

"Move twice" doesn't matter, even if you move a billion time. there are n o "move" instructions, it's just semantics layer that ensures safety. its a concept.

But yes, if you are heavily used to &mut, you will have bad time in holylang.

but on flip side, programs will become mentally easier to reason about... for once, whenever i compile a rust project that heavily uses borrow checker &mut, etc, i find myself extremely hard to reason about it.

That's a great question. The defintive answer is: I will make it annoying to write "# todo"

For instance, the length of the comment above a function, will depend on the lines of code in the function its self. a 100 line function might require 5 words (1 word is minimum 3 characters long), a 500 line function might require 10 words. etc.

Obviously you could do # blas lnblsdgorewgrewgokehtetdrsheroljrw

But at that point... you're fighting the compiler to write unreadable code.. it's not that hard to describe a functions purpose in a sentense or two :slight_smile:

P.S. comments enforcer will be implemented in phase 2 of holylang, not the bootstrap compiler.

That's a great question. The defintive answer is: I will make it annoying to write "# todo"

For instance, the length of the comment above a function, will depend on the lines of code in the function its self. a 100 line function might require 5 words (1 word is minimum 3 characters long), a 500 line function might require 10 words. etc.

Obviously you could do # blas lnblsdgorewgrewgokehtetdrsheroljrw

I will make it so the comments have to be valid english words.

you can still make dummy comments, but...

But at that point... you're fighting the compiler to write unreadable code.. it's not that hard to describe a functions purpose in a sentense or two :slight_smile:

P.S. comments enforcer will be implemented in phase 2 of holylang, not the bootstrap compiler.

Most useful programs need shared state. Even in pure functional languages like Haskell, this is necessary and is done with monads.

Without at least &T or shared references of some other kind, you must pass and return many variables. I know that a move is not expensive. It is the inconvenience that is the problem. See languages like Swift and Hylo for how this has been done transparently, if you don't want explicit borrowing.

My point is that this needs to be spelled out, along with real world examples showing how it will work, in order to be believable.

You are right on this. It will be weird and inconvient. but simple. really, simple.
If you are not want do this approach of pass and return, then you can simply pass a copy. most functions written in any language don't need a &mut, so copying would be fine. no ugly inconvenience needed, if performance not issue :slight_smile:

That's why I suggested looking at Swift and Hylo. They internally pass by reference for better performance with large structures, but they do this transparently as if a copy is being made.

I have made the decision while ago to stick to the simple binary safety model of "move, or copy", because apparently God likes it.

I don't intend on implementing a borrow checker, let alone one that behaves impliclity..

It's just is what it is. Feel free to use Rust if your program design relies heavily on mutable state,... it's just not for holylang.

Excellent, I can use your language.

I'm curious how you plan on doing static stack analysis when functions can nest and recurse arbitrarily deep in ways you can't statically observe. Will you just forbid any and all recursion?

Recursion is unsafe by the definition, NASA, for example, prohibits a recursion in programming space vehicles. So certainly the language shouldn't allow it for the reason. Most companies I applied for a job asked me to rewrite recursion algorithms to a loop based.

Well, I still haven't decided on the approach yet.
So far my options are either to allow recursion but allow programmer to set up a "max" recurssion
Or
Just forbid recursion at all

I am leaning toward option 2, because it's easier to implement and test.