Evan Ovadia, creator of the Vale language, writes about memory safety, generational references, regions, and language design.
Commenters follow Vale closely and are interested in its approach to memory safety, with predictable latency and easier iteration than borrow checking.
Warning: Bit of a 'Hitch hikers guide to the galaxy"/conway game of life yak shave for a reply.
Nice start to providing a simple way to visually interact/experiment/manipulate
different multiple Neural network concepts by loading/transforming any
traditional code (working or not) & reshuffling/tesselating the structual representation of the code to generate a turing tape path via color execution paths.
Switching to pi calculus could provide the theory to support coroutine/coprossing/
threading" multiple interacting tape paths/color combinations/path diffs/scaled recusion
to perform assembly language instructions.
Raster graphics without the yak ( https://verdagon.dev/blog/yak-shave-language-engine-game )
Feed back between tape & "traditional code" as neural network layer(s)!
Flexiable code (via tessilations) without changing the actual imported source code!
So, complete svg (tape interactions) web page as code source on how to interact with web page,
( https://www.youtube.com/watch?v=r6sGWTCMz2k )
what's displayed/played, documentation & usage manual included within code structure!
Unicode permits implied piping rich kern font without all the tech fluff.
Unicode fails because allows infinate multics and is there for k&r incomplete.
But, this approach is way more dimensional/colorful than unicode/tech stuff.
?? can one's code unintentially provide a wordle problem & solution in one package ??
(https://www.youtube.com/watch?v=v68zYyaEmEA )
?? turing complete fourier…
Not staticassertion, but I'm a hobbyist in real-time audio. I like Rust as a vocabulary for describing/teaching safe programming (&/&mut/Send/Sync). I find that multithreaded programs written in Rust are usually correct while multithreaded programs written in C++ are usually wrong, because Rust encodes the rules of shared-memory threading in its type system (&T: Sync objects are thread-shared, but are either immutable or atomic or requires locking to acquire a &mut T). I also appreciate guiding users towards exclusive references (&mut) to make it easier to reason about code. However I find it makes it too difficult to mutate through shared references or write unsafe code (passing Stacked Borrows while lending out &mut is more like solving puzzles than writing imperative code, and writing code that never touches & and &mut is a quagmire of addr_of_mut!() and unsafe blocks on every pointer dereference), and the Rust community appears uninterested in making unsafe programming more ergonomic.
Personally I'm a fan of C++'s unique_ptr/& as an unsafe escape hatch from Rust's single ownership or runtime refcounting overhead. It's at least as safe as Rust's unsafe pointers, and far more pleasant to use. Qt's QObject ownership system is reasonably ergonomic and QPointer is fun (though dangerous since it can turn into null unexpectedly), but Qt uses it pervasively (rather than only when safe memory management fails), relies on prose documentation to describe which pointers transfer…
Language-level guarantees of memory safety are not critical to all low-level programmers, and sometimes this is fine!
Developers of games, compilers, digital audio workstations, video editors, and live performance software (such as openFrameworks) likely don't rank memory safety as their top concern.
Zig is already an attractive choice for those domains because it offers:
- Great compile times compared to C++/Rust, and future plans to implement hot reloading as a core part of the tooling: https://www.jakubkonka.com/2022/03/16/hcs-zig.html
- The ability to reason about where data exists in memory: https://ziglang.org/documentation/master/#Where-are-the-bytes
- Good readability and learnability, especially if you have a C/C++ background.
- Comptime that enables clean generics, compile-time reflection and general metaprogramming as a happy side-effect: https://kristoff.it/blog/what-is-zig-comptime/
- Better tooling than C/C++. The ability to cross-compile Zig and C/C++ from one machine lets you set up much more stable and reproducible build environments already. You can clone zig-gamedev and have the demos working with just three commands on Windows/macOS/Linux, for example, and two of those three are cloning the repo and changing to the directory: https://github.com/michal-z/zig-gamedev (to build the examples you will need the latest copy of Zig from the 'master' section for your platform at https://ziglang.org/download/ )
We should all be careful about insinuating…
> In an average Google Earth quarter, only 3-5% of bug reports were traceable to memory safety problems, and Address Sanitizer made them trivial to reproduce in development mode.
Bug reports, sure. But as for security vulnerabilities, both Microsoft and Google have reported that roughly 70% of them were memory safety issues.
Personally, as a Rust fan, I fully agree that the borrow checker limits developer velocity, and I'd be happy to toss it if I could. But verdagon has been promising memory safety with no overhead for years; I'll believe it when I see it.
Edit: Okay, that was unfair to say without further context, so let me add two things. First, although Vale is open source, the design has changed over time and the implementation was described as a "work-in-progress" as of two months ago. [1] Second, a month before that, verdagon described the design as providing "statistical safety", meaning use-after-frees may fail to be caught but are caught "99.9999999999996% of the time". Now, stochastic exploit mitigations such as ASLR and PAC are valid defenses, as long as that 99...% also applies in the presence of an active attacker. But the specific design described (allowing generation counters to wrap) sounds like, in many scenarios, an attacker could manipulate it to provide no protection at all. There may be ways to mitigate this, but in context it does sound like it's designed under the assumption that memory safety violations will occur at random, rather than…
Throwing exceptions might not be acceptable in your use-case, with many codebases disabling it for concerns of performance or executable bloat. And factory functions cannot really help the initialization problem anyway, since your field is still in an uninitialized state before calling the factory function. And also, returning std::optional or std::expected can sometimes lead to slower code (copy constructor being called) because of NRVO not working when the compiler “feels like it”. So an init() method/function that returns an error code is the best you can get.
I think the best way to really solve the invalid object problem in C++, is to always put sensible default values inside your struct/class definitions, so your code will at least fail without UB (in addition to using asserts liberally to check for index overflow problems, especially in your own containers even in. Release mode.) Zero-initialization is good for most cases, but sometimes you might need to default-initialize your indices to -1.
weak_ptr is really slow, because of the lock instruction generated for each lock(). Once you use them all over the place to fix reference cycles, the overhead of using these becomes hard to ignore. Generational indices/references remove all the ref-counting and gives programmers the semantics of weak_ptr without the performance cost (see https://verdagon.dev/blog/generational-references, the details are mostly language-agnostic).
Something that gives me hope is that I haven't seen anyone prioritize debuggability in a modern programming language or even a framework. Vale is maybe the first getting close: https://verdagon.dev/blog/perfect-replayability-prototyped.
I think there is a new era yet to come.
> probably too complex to visualize in a usable way
You can always abstract the complexity. A simplification of the control flow graph at the function level.
As an example, I want to understand the Postgres codebase better...there are a lot of very visualizable things going on there. If you look at lecture slides on relational DBMS, there are lots of diagrams...so why can't be view those animating diagrams as the code executes.
I was thinking of instrumenting the code to get a trace of every function call and its arguments, and then filter that and visualize it.
The key to this approach working though is a think ultimately we need to write our code and organize our code such that it can be easily visualizable. The purpose of code is for humans to understand it, otherwise we are writing assembly.