Hypothesis: Rust is "hard to learn" because experimenting is hard. Getting code to work requires a lot of thinking and "in-head" design. There are also many concepts needed to get started.
People ask to "disable the borrow checker".
What if we can create an EZ rust mode that is used to introduce users to Rust. It is a slightly different language, but is compatible with Rust itself. EZ mode is enabled / disabled at the crate level but ez-mode crates can call non-ez-mode crates and vice versa.
Ez-mode is primarily focused on app-developers (CLI, net services, etc…). Ez-mode will not be zero-cost and will come with some runtime. Ez-mode will not use a GC as GCs are quite intrusive.
Infrastructure libraries (e.g. Tokio, Hyper, …) will still be implemented in Rust for performance. The idea is that the application layer business logic is more "scripting" and can have some level of runtime overhead without a measurable total performance impact.
Generally, Rust is overall fast and overall performance tend to be avoiding "death by a thousand cuts".
Features
Inspired by: Revisiting a 'smaller rust'.
Goal: remove borrow-checking related challenges from the ez-path. They can still be there, but they are not required to be productive. Users can explore ideas without having to think-ahead.
Withoutboats proposes to decouple Copy
and memcpy
in order to support things like "persistent data structures" that feel natural. Example, instead of having &str
, &String
, &mut String
, and String
, there would just be String
which would be Copy
and could be passed by value.
In this example, String
is hypothetically backed by a persistent data structure. This could also make slices possible.
What about user-defined structs? How do we remove borrowing from the happy path?
A naive implementation could essentially be clone, but that has problems with managing "resources" (as boats calls them) as well as letting functions mutate values.
Rc
/ Cell
Forgetting about thread-safety for a bit, what if structs had an implicit Rc
and each field was implicitly Cell
. It would be possible then to update fields. Example:
Note that there is no mut
mentioned here. Pet
has an implicit Rc
and each field has an implicit Cell
. The Copy
implementation of Pet
increments the ref count and updating the age
field is done using get
and set
semantics.
Send
and Sync
?By using implicit Rc
/ Cell
, we are forcing types to be !Send
. How does this work? We can't give up concurrency.
Instead of supporting arbitrary concurrency strategies, EzRust forces a light-weight task + message passing pattern (similar to Go / erlang).
In this pattern, logic is pinned to a "task". There is no shared data between tasks. Instead, tasks communicate by message passing.
But, how do we define a message if all structs imply Rc
? We have different categories of types. One for "logic" and one for "data" / message passing.
For resource types. E.g. a File
should close on drop and guards (e.g. mutex guard) is still a useful pattern.
TODO: But, in general, the borrow checker still works as "normal", it is just needed less often.
Another crazy idea… but how plausible would it be to have an Object
type that does dynamic dispatch and runtime typing? Think of this as the opposite of Typescript. Instead of doing gradual typing, we do gradual un-typing?
The idea would be to minimize the amount of work one has to do when exploring / experimenting and types could be added later (a lint could be used to disable untyping).
Maybe this could be a debug mode only feature.