Top
Best
New

Posted by verdagon 10 hours ago

Valen's Memory Safety: A New Kind of Borrow Checking(verdagon.dev)
124 points | 75 commentspage 2
SleepyMyroslav 4 hours ago|
This looks cool for code-driven systems where code has static knowledge of every path in the system. It might be strictly better for things like rendering where types of rendering are code-driven. Like your world can have skybox and such. The examples assuming gamedev 'world' and 'entity' are completely misleading though. Because I think everyone has moved on to data-driven worlds. Think of entity 'advance' from the code examples as an 'entity blueprint execute'.
maufl 8 hours ago||
How likely is it that such a borrow checker could be "backported" to Rust? Maybe in a new edition?
verdagon 8 hours ago||
You know, it's not crazy. Niko wrote about lifetimes based on places back in 2024, [0] though it was in the context of shared-xor-mutable, which is consistent with Rust's spirit.

And Rust already supports forms of mutable aliasing already, such as with Cell, and GhostCell which is halfway towards Valen's approach. I would love to see someone augment GhostCell to have the sort of "invalidation" logic that group borrowing does. In fact, Plecra is working on something like that with their (WIP) "Exclusion Typing". [1]

On top of that, Polonius already thinks in terms of "paths", just like Valen does. So it's not so much a question of compiler design, but of language design, and how Rust would expose it to the user.

[0] https://smallcultfollowing.com/babysteps/blog/2024/06/02/the...

[1] https://dilated.me/blog/posts/introduction-to-exclusion-typi...

zozbot234 7 hours ago||
It would have to take &Cell<T> references or the like in order to preserve the existing uniqueness properties for &mut T references. Not so different ultimately from what GhostCell, QCell, LCell etc. do already, except possibly simpler in some ways.
sebastianmestre 10 hours ago||
IIRC this Verdagon guy had a language called Vale... is Valen a rename or a new project?

Edit: tfa makes it clear it's a separate project

verdagon 9 hours ago|
Hi! Kind of both. Even though Valen reuses 90% of the Vale compiler, its approach (Rust interop, borrow checking with mutable aliasing, etc.) is so different that it really needed a new name.

Also, I really like where Vale ended up, Vale's generational references + region borrowing was a truly weird and unusual memory safety blend. I didn't want that combination to be lost to time, so I wanted "Vale" to keep referring to that.

Arodex 2 hours ago||
A bit sad to see Vale archived. Have you written a final post on it (lessons learned, the good and the bad, fundamental strengths and weaknesses, future research needed, all that)?
verdagon 2 hours ago||
No, but that's a great idea. Vale definitely taught me a lot about languages and architecture. I might do that...
Arodex 2 hours ago||
Thank you. Your writings on memory safety and other similar topics is appreciated, and the work you are doing seems to point in a very interesting direction that I am sure will bring a new breakthrough similar to what Rust (or, more accurately, Cyclone) brought. Very interested in what will percolate in Mojo and Ante too.
c-fe 6 hours ago||
the link under recent posts here https://verdagon.dev/home 404s, as it links to https://verdagon.dev/blog/valen-memory-safety instead of https://verdagon.dev/blog/valen-group-borrowing . Interstingly this shows the page is hosted on Firebase, which is a bit unexpected for a static blog
verdagon 6 hours ago|
Should be fixed now, thanks!
user142 8 hours ago||
I noticed that there is no control flow in the examples.
verdagon 8 hours ago|
Next article =) How the borrow checker handles ifs and loops is a pretty fun topic. If-statements work like you'd expect (invalidations from both branches are merged). Loops is where it gets weird: we have to scout all the invalidations that happen inside the loop and then "replay" them _before_ the body of the loop. I can explain it more if you'd like.
user142 8 hours ago||
I was wondering about the case where a reference points to a different path depending on control flow. I guess you can just design your language to make this impossible but this is still possible to do with pointers in C/C++.
verdagon 8 hours ago||
Theoretically, we can have a reference that points to two paths, a "path union" so to speak. If the user explicitly typed out the path union, it would be something like:

let my_ref &Entity in (live_list[], dead_list[]) = if ...

though it would be nicer in practice, because the compiler could infer that.

Haven't implemented it yet of course, but the data structures in the borrow checker are designed with this in mind.

eptcyka 6 hours ago||
Would it then be possible to mutably reference two entries in the same hashmap?
verdagon 4 hours ago||
Yep, that comes for free from the model. Though, if you're asking if we can have two unique references (like `&mut`) to two different entries, not yet. Nick's original proposal had some thoughts on how we can do that, and Zeta (another language implementing group borrowing) has some neat dependent-type-ish mechanisms for that. I'm still considering what Valen will want to do there.

Edit: it turns out, Ante has path unions! https://www.reddit.com/r/ProgrammingLanguages/comments/1x37b...

JackSlateur 5 hours ago||
Checking the following code, could you confirm that is does not work concurrently ? The "world" var is read-only, does it mean that all other entities are also readonly (cannot be modified by another thread, for instance) ?

  struct World {
    entities Vec<Entity>;
  }
  func step(world &World, entity in world.entities[] mut) {
    entity.advance();
    let collision = world.get_collision_for_entity(entity);
    entity.resolve(collision);
  }
verdagon 4 hours ago|
Yep, that works today. The neat thing here is that `world` is immutable _except_ for its `.entities[]` elements.

That wouldn't be shareable with another thread, because part of it is `mut`. _Theoretically_ we could make this shareable with other threads if we had another kind of effect, let me know if you're curious about that.

The `entity in world.entities[] mut` gives `step` blanket permission to mutate any element inside world.entities. We wouldn't be able to say "all other entities are readonly".

Though, it's worth mentioning that `advance` and `resolve` both receive the entity as a unique reference (since it's the only reference into a group which has a mut effect).

fithisux 8 hours ago||
Is it possible to retrofit it to Freepascal, D, Freebasic or even Java?
verdagon 8 hours ago|
Maybe! I think about D a lot when designing Valen, since they attempted to blend borrowing with garbage collection. Swift is facing some of the same challenges, and I expect Java could soon too now that Valhalla has landed.

If Valen solves those challenges as well as I think it can, it could be a good direction for them to explore.

fithisux 3 hours ago||
D is my favorite (I am a dinosaur) and I hope both Valen and D progress on that front.
octoberfranklin 3 hours ago||
A function signature describes the paths it modifies.

The problem with this is that it imposes a cost on abstraction. Zero-cost abstraction is one of the most fundamental design principles behind both C++ and Rust.

A field-path into a struct/enum fundamentally depends on its concrete implementation. If you hide the fields of a struct and use getters/setters, you break the ability to talk about the "paths modified" by a function which uses getters/setters.

Aside: it really annoyed me that I had to read halfway through this article to find the first attempt at defining "group borrowing". The whole first half of the article is basically fluff.

swiftcoder 3 hours ago|
> The whole first half of the article is basically fluff

There are multiple links in the article that suggest the reader skip to the good stuff if they are already familiar with how borrow checking works

falconBrisk47 9 hours ago|
Path Borrowing reads clearer to me, "group" made me look for a group type.