[HN Gopher] Vale's first prototype for immutable region borrowing
       ___________________________________________________________________
        
       Vale's first prototype for immutable region borrowing
        
       Author : modernerd
       Score  : 369 points
       Date   : 2023-07-12 04:44 UTC (18 hours ago)
        
 (HTM) web link (verdagon.dev)
 (TXT) w3m dump (verdagon.dev)
        
       | drwiggly wrote:
       | This language is interesting. General usability might be a bit
       | away? Higher RAII is something that would be nice in C++ too.
        
       | conaclos wrote:
       | I keep wondering what "safe" means in the context of generational
       | references.
       | 
       | If I understand clearly, this prevents use-after-free and double-
       | free? Thus, the program can still fail on a memory access when
       | the expected and actual generations don't match? In this regard,
       | this seems less "safe" than reference counting, tracing garbage
       | collector, or borrow checking?
        
         | marhee wrote:
         | Yes, I am wondering too.
         | 
         | How would it even stop use-after-free and double-free?
         | 
         | The "check" function accesses the allocation because it needs
         | the generation number of the allocation. So basically, the
         | reference needs to access the allocation to check if it can
         | access the allocation. Right.
         | 
         | (That doesn't work of course, because if the allocation was
         | freed, access to the allocation and so its generation number is
         | undefined).
         | 
         | This seems obvious so maybe I am missing something big here?
         | 
         | Or something entirely different is meant or targeted here with
         | "memory safety".
        
           | conaclos wrote:
           | If I am not wrong, there is a generation number embedded in
           | the reference (smart pointer?). This allows to check if the
           | generation of the reference and the generation of the referee
           | match.
        
             | marhee wrote:
             | Yes, there is a generation number in the reference. It is
             | checked against the generation number of the allocation
             | that is stored in the allocation:                 void
             | __check(GenerationalReference genRef) {         uint64_t
             | currentGeneration = *(uint64_t*)((char*)genRef.alloc - 8);
             | assert(genRef.rememberedGeneration == currentGeneration);
             | }
             | 
             | So indeed you it allows you to check for a match, as long
             | as the _alloc_ pointer is valid. The _alloc_ pointer is
             | invalid after a free, because it maybe be in a region no
             | longer accessible to the program (it was returned to the os
             | by free 's implementation) or it was given out as part of
             | an other allocation, in which case it can hold arbitrary
             | data.
        
           | flohofwoe wrote:
           | Traditional memory allocators set aside some of the memory
           | for metadata (for instance to keep track of allocated and
           | free memory regions), I guess that Vale stores the generation
           | count associated with an "allocation item" in a similar way,
           | e.g. somewhere else than the actual items.
           | 
           | Also, the blog post talks about 'generational indices', not
           | pointers. This seems to indicate that items of the same type
           | (or at least same size) are grouped into arrays (and since
           | it's an index anyway, the metadata could be stored in one or
           | multiple separate arrays at the same index).
           | 
           | PS: I already linked it elsewhere, but here's how the same
           | can be achieved without language/compiler support (at least
           | it's the same general idea):
           | https://floooh.github.io/2018/06/17/handles-vs-pointers.html
           | 
           | The big step forward by Vale is that the compiler can elide
           | most of the 'dangling checks' on memory accesses, the method
           | outlined in the blog post requires a few rules-of-thumb the
           | coder must follow when using a pointer that's been looked up
           | from a generational-index.
        
           | jsnell wrote:
           | I think the part where your reasoning is invalid is this
           | part:
           | 
           | > so its generation number is undefined
           | 
           | With e.g. a random C compiler and a random malloc, that's
           | true. But why couldn't the language and runtime cooperate to
           | ensure it _is_ defined?
           | 
           | For example deallocation can write a predictable value to
           | that slot, which is never used as a legit generation index.
           | The memory allocator can make sure that a memory address that
           | ever contained a generation can never contain anything else
           | than generation ids for the entire runtime of the program
           | (e.g. by ensuring that for a given page, all objects are the
           | same size and the allocations are aligned to that size). The
           | language can make sure that nothing else can get written to
           | such a memory address by enforcing bounds checks.
        
             | [deleted]
        
             | ajb wrote:
             | Ok but then aren't you going to get memory fragmentation?
             | If you allocate and then deallocate a billion 1kB objects,
             | you can't then coalesce them to allocate larger units
             | because the generation number locations before each 1kB
             | can't be given back to user code.
        
               | verdagon wrote:
               | In the basic generational references approach that was a
               | drawback, and the reason it couldn't release memory back
               | to the OS. We planned to use something like MESH [0] to
               | reduce the fragmentation.
               | 
               | We created two newer approaches since then, which let any
               | memory be reused for any purpose:
               | 
               | * Random generational references, where it's fine if
               | generations overlap with other data.
               | 
               | * Side-table generations, which is slower but we keep the
               | generations in a side-table. It's can be seen in old 0.1
               | versions as the "resilient-v2" mode, and I plan on
               | resurrecting it for unrelated reasons.
               | 
               | The former will be the default, and the latter we'll be
               | adding back in as an option. Hope that helps!
               | 
               | [0] https://arxiv.org/pdf/1902.04738.pdf
        
             | verdagon wrote:
             | Yep, this is the correct answer. Accessing released memory
             | is undefined in C, but well-defined in Vale. The goal is to
             | ensure that the user predictably+safely gets either a
             | segmentation fault or an assertion failure.
             | 
             | We have a future improvement planned here too: for
             | unrelated reasons (to support generation pre-checking) the
             | random generational references implementation will soon not
             | even unmap any virtual address space, instead remapping it
             | to a central page, so we won't even get any segmentation
             | faults, just assertion failures.
        
         | verdagon wrote:
         | Double-frees are prevented by Vale's single ownership (in the
         | C++ sense), generational references make it so use-after-frees
         | are safely detected. If we try to access released memory via a
         | reference, we should predictably+safely get either a
         | segmentation fault or an assertion failure (and a future
         | improvement involving remapping virtual space will make it so
         | we get no segmentation faults, which I'm pretty excited for).
         | Hope that helps!
        
           | flohofwoe wrote:
           | > Double-frees are prevented by Vale's single ownership (in
           | the C++ sense)
           | 
           | ...wouldn't that also be prevented by the generation-check
           | even if there is no single-ownership? Because once the
           | referenced item is destroyed (and thus bumping that "memory
           | slot's" generation counter) that item reference becomes
           | invalid because the generation no longer matches, so the next
           | attempt to release the item with that same reference should
           | also fail?
           | 
           | One nice property of generational-indices is that they can be
           | shared without compromising memory safety. As soon as the
           | item is destroyed, all shared references in the wild
           | automatically become invalid. But I guess single-ownership
           | still makes a lot of sense for thread-safety :)
        
           | Lk7Of3vfJS2n wrote:
           | How is Vale's memory safety approach different than CCured?
        
         | kreco wrote:
         | Is it less "safe" than your own restricted definition then...
         | maybe?
        
         | flohofwoe wrote:
         | It's safe the same way a segfault is safe instead of just
         | allowing to read or write random memory through a dangling
         | pointer, but generational indices should also allow to check at
         | runtime if an access would be valid before actually attempting
         | the access. Not sure if that's possible in Vale though.
        
         | rcme wrote:
         | It is less safe than GC, BC, and RC. But it's still more safe
         | than malloc / free. And it has other benefits as well.
        
           | cdcarter wrote:
           | I'm familiar with Garbage Collection and Reference Counting,
           | but what is "BC"?
           | 
           | EDIT: oh, borrow checking.
        
       | leksak wrote:
       | Nice "first"-type of Easter Egg! Would love to be a penguin.
       | Keeping it would make for a good TFA though!
        
         | verdagon wrote:
         | I would keep it! But alas, I have to remove it at some point
         | today. I plan on keeping a record of all of them at
         | https://verdagon.dev/blog/easter-egg-notes though.
        
       | garganzol wrote:
       | I downloaded and tried to try Vale.
       | 
       | The very first impression of running 'valec' compiler is that it
       | "panics" when no arguments are given. It literally writes so:
       | "(panic)". I want to point out that "panic" is a very strong word
       | and should be avoided in scenarios where a normal error handling
       | takes place. Any kind of panic is always a sign of an
       | uncontrolled situation, and if a program ever "panics" it leaves
       | a bad taste in the mouth.
       | 
       | The next struggle was to get the basic help for the command-line
       | parameters. But it's currently non-existent.
       | 
       | The next and final stuggle: trying a hello world sample. I copied
       | the code from the website:                 import stdlib.*;
       | exported func main() {         println("Hello world!");       }
       | 
       | and saved it to 'hello.vl' file. Then, I tried to build it:
       | > valec hello.vl
       | 
       | However, no luck for me this time:                  Unknown
       | subcommand, specify `build`, `run`, etc. Use `help` for more.
       | 
       | It looks like I should specify 'build' command. Let's try:
       | > valec build hello.vl
       | 
       | Well, here is the result:                 Unrecognized input:
       | hello.vl
       | (panic)
       | 
       | Hm. Let's try to get some help:                 > valec help
       | 
       | The result of the help command is:                 <nothing>
       | 
       | Not very helpful. At this point, I gave up. How does this thing
       | work?
        
         | verdagon wrote:
         | Sorry about that, it seems it doesn't print out the help file
         | correctly any more. If you manually cat the valec-help-
         | build.txt in the download, it should explain what you're
         | looking for.
         | 
         | The compiler is _very_ rough around the edges right now.
         | August-May was spent being 100% focused on prototyping regions,
         | and you 're experiencing the tech debt I accrued on the way
         | there (including the lack of an integration test for the help
         | system). I've been paying that debt down for the last 1-2
         | months and we're still not back up to where we were at the 0.2
         | release.
         | 
         | If you need any more help, let me know, or swing by the discord
         | server where there are many helpful folks. Cheers!
        
         | emblaegh wrote:
         | The github readme shows how to use the compiler.
         | https://github.com/ValeLang/Vale#building-a-vale-program
        
         | insanitybit wrote:
         | Isn't vale basically still in the R&D phase? That's how it has
         | felt, certainly. I would expect specific commits on specific
         | branches to work and that's it - no that they have a compiler
         | that arbitrary people can use to start building things.
         | 
         | Then again, their README doesn't really indiciate this and does
         | say "Try Vale" so idk. But it _seems_ very R &D/POC at this
         | point.
        
           | aktuel wrote:
           | From the home page: "Vale is currently in alpha!"
           | (https://vale.dev/)
        
             | msla wrote:
             | But that doesn't distinguish between "VC Alpha", which
             | means early access, and "Programmer Alpha", which means
             | basic functionality doesn't work.
             | 
             | (The inverse is "VC 1.0", which means pre-release but we
             | had to meet a deadline, and "Programmer 1.0", which means
             | it's the first stable version.)
        
               | flohofwoe wrote:
               | > "Programmer 1.0", which means it's the first stable
               | version
               | 
               | I thought "Programmer 1.0" is more like +Infinity and
               | never ever reached? ;)
        
           | [deleted]
        
         | yosefk wrote:
         | These aren't even bugs, they're "UI problems." For something
         | experimental, I think it deserves some slack even for actual
         | bugs. UI-wise and even bugs-wise, eg 40 years old C++ debugging
         | experience in 35 years old gdb will give any experimenral
         | language a run for its money (eg printing
         | funcname()::staticvarname is wierd UI and fails about half the
         | time, etc.), not to mention C++ build systems. I think for
         | experimental tech you might criticize the concept but it's
         | entitled to a rough UI.
        
         | bryancoxwell wrote:
         | This is about what I'd expect from software that's still in
         | alpha though.
        
       | a1o wrote:
       | I thought this was about Vala and only on a second read caught it
       | was a different language.
        
       | cantaloupe wrote:
       | Congrats to Evan on the milestone! I enjoy reading the Vale
       | articles even though I have no programming language design or
       | compilers experience.
        
         | pjmlp wrote:
         | Same here, I just wished there was another name for it.
         | 
         | Now we have Evan with Vale, and Adobe's Software Technology Lab
         | wit Val, it will be great searching for related stuff.
         | 
         | https://www.val-lang.dev
        
           | hobo_mark wrote:
           | There's also been a language called Vala, active since 2006!
           | 
           | https://vala.dev
        
             | solarkraft wrote:
             | And there's the game company actively developing low-level
             | open source software Valve, which my mind first sprung to.
        
             | promiseofbeans wrote:
             | Not to forget https://www.val.town, which call their lambda
             | functions 'vals'
        
             | iddan wrote:
             | When I entered the article I thought it was talking about
             | Vala
        
             | pjmlp wrote:
             | Yeah, that one as well.
        
             | verdagon wrote:
             | Yep, this was my bad. I thought Vala was dead because of a
             | certain post (I think it was this one [0]), and because I
             | rarely ever heard anyone mention it. I suspect I was wrong.
             | I've been tossing around the idea of switching Vale's name
             | to Valence to help avoid confusion.
             | 
             | [0] https://www.phoronix.com/news/GNOME-Vala-Bassi
        
         | verdagon wrote:
         | Thanks! Glad you enjoy them =)
        
         | NeutralForest wrote:
         | Same, I don't have the background to understand the articles in
         | most cases but it's interesting nonetheless.
        
         | davidkunz wrote:
         | Me too, the articles are great and I'm excited about the future
         | of Vale.
        
       | dang wrote:
       | Related. Others?
       | 
       |  _Making C++ safe without borrow checking, reference counting, or
       | tracing GC_ - https://news.ycombinator.com/item?id=36448759 -
       | June 2023 (214 comments)
       | 
       |  _Memory safety without borrow checking, reference counting, or
       | garbage collection_ -
       | https://news.ycombinator.com/item?id=36351415 - June 2023 (93
       | comments)
       | 
       |  _What Vale taught me about linear types, borrowing, and memory
       | safety_ - https://news.ycombinator.com/item?id=36156790 - June
       | 2023 (12 comments)
       | 
       |  _How Memory safety approaches speed up and slow down development
       | velocity_ - https://news.ycombinator.com/item?id=34410187 - Jan
       | 2023 (137 comments)
       | 
       |  _The Vale Programming Language_ -
       | https://news.ycombinator.com/item?id=31786487 - June 2022 (90
       | comments)
       | 
       |  _The Vale Programming Language_ -
       | https://news.ycombinator.com/item?id=25160202 - Nov 2020 (171
       | comments)
       | 
       |  _The Next Steps for Single Ownership and RAII_ -
       | https://news.ycombinator.com/item?id=23865674 - July 2020 (38
       | comments)
        
       | ivoras wrote:
       | Does the generational reference approach do something similar to
       | MVCC in databases (e.g. PostgreSQL)?
        
       | MilStdJunkie wrote:
       | I wish there was some way for me to know right off the bat that
       | this article _wasn 't_ about the Vale natural language linter. I
       | mean, it didn't take long, but still. Is there some notation for
       | the linter nomenclature I'm missing?
        
       | [deleted]
        
       | lovich wrote:
       | The callout to the Easter egg was a nice social hack to see how
       | many people read the article in detail
        
         | verdagon wrote:
         | Funny story, that wasn't my original intent! I have a
         | programming blog, but every day I'm finding weird facts that I
         | want to write about, so I tend to sneak them in:
         | 
         | * I like mythical birds, so I wrote an article about memory
         | safety and mythical birds: https://verdagon.dev/blog/myth-zero-
         | overhead-memory-safety
         | 
         | * The Rosetta stone fascinates me, so I wrote an article on
         | linear types and the Rosetta stone:
         | https://verdagon.dev/blog/linear-types-borrowing
         | 
         | * I heard about a pigeon named G. I. Joe so I added a side note
         | to about it on the C++ article at
         | https://web.archive.org/web/20230629052606/https://verdagon....
         | 
         | * And now I had to find a way to spread the word of Brigadier
         | Sir Nils Olav III, so I used a side note in this one. It's
         | embarrassing but I was giggling with glee all day yesterday at
         | the thought of putting that note in!
         | 
         | I suspect this is a curse that a lot of bloggers can empathize
         | with, but they don't have the proper lack of professionalism
         | that I do.
         | 
         | Once I had these little side notes, I figured I'd give some
         | sort of prize to the first person who told me they saw them,
         | which evolved into "comment somewhere mentioning it!" which I
         | guess is a social hack? Maybe? I'll allow it!
        
       | cultureulterior wrote:
       | That algorithm would be infinitely much faster if you were to use
       | bitboards
        
       | 3cats-in-a-coat wrote:
       | Correct me if I'm wrong, but I believe this is an alternative way
       | to describe a system that is equivalent to copy on write, but
       | with ahead of time analysis on reference counting, which means we
       | can eliminate most of reference counting. We have this kind of
       | analysis is already done in reference counted languages like
       | Swift which also do copy on write.
        
         | flohofwoe wrote:
         | It's not ARC, and not reference counting at all, but closer to
         | an idea that has become quite popular in game development
         | (because it's trivial to implement, doesn't need compiler
         | support, and works in any language that has indexable arrays):
         | 
         | https://floooh.github.io/2018/06/17/handles-vs-pointers.html
         | 
         | (disclaimer: I only wrote a blog post about it, that idea is
         | much older and probably has been re-invented many times over
         | since the first computers were built)
         | 
         | Essentially "non-owning weak references with spatial and
         | temporal memory safety".
         | 
         | What _is_ similar to ARC though is that moving that stuff into
         | the language lets the compiler remove redundant handle-to-
         | pointer conversions, similar to how with ARC the compiler can
         | remove redundant refcounting operations.
        
           | Buttons840 wrote:
           | I didn't understand that blog post very well, but it made me
           | think of "generational arenas"[0], and I'm curious how they
           | compare? Generational arenas sound similar because they
           | involve passing an index around instead of a pointer, are
           | designed to handle many small self referencing "objects", and
           | are popular in games, so in my mind they seemed similar.
           | 
           | [0]: https://docs.rs/generational-
           | arena/latest/generational_arena...
        
             | sirwhinesalot wrote:
             | Same idea but applied to the whole program and with
             | compiler optimizations to avoid redundant generation
             | checks.
        
           | sirwhinesalot wrote:
           | They don't seem to be quite zero cost though when applied to
           | the whole program, because they require changes to the
           | allocator to ensure the generations are never overwritten by
           | user data.
           | 
           | If you store them inline with the program data for max
           | speed(tm) you need to ensure that e.g. after 2 2kb chunks are
           | deleted, you don't overwrite them with a 4kb chunk, because
           | that would trample over a generation.
           | 
           | If you do keep the generations inline and rely on a
           | statistical approach, you have to be very careful to never
           | generate "common numbers" like 0 as a generation because then
           | it's extremely likely there will be a collision.
           | 
           | It'd a hard problem and I'm quite curious how all the edge
           | cases are handled.
        
             | flohofwoe wrote:
             | Maybe Vale's "regions" are per-type (essentially arrays)?
             | That way a specific memory location would only ever be used
             | for that same type (== same size in memory) until the whole
             | region is destroyed.
             | 
             | iOS is getting a 'typed allocator' which seems to work
             | similar:
             | 
             | https://security.apple.com/blog/towards-the-next-
             | generation-...
        
               | sirwhinesalot wrote:
               | Yeah typed allocator would be my guess but those aren't
               | zero cost either. They increase memory usage since if
               | your program allocate an array of 100 ints, delete them,
               | and then allocate an array of 100 floats, unless you
               | allocate more ints on the heap that memory isn't getting
               | reused.
        
               | flohofwoe wrote:
               | The physical memory could be reused, only the virtual
               | address range is "burned" (don't know if it actually
               | works that way though)
        
         | GolDDranks wrote:
         | This is not a reference counted system, but you manually free
         | the memory. However, the references are safe to use in the
         | sense that they can detect when the object they are referring
         | to, is deleted.
        
       | cpeterso wrote:
       | "Vale is Fast: Vale is AOT compiled to LLVM, statically-typed,
       | and uses the new generational references technique for memory
       | safety with speed and flexibility, and will soon have region
       | borrow checking to make it even faster."
       | 
       | https://vale.dev/
        
       | hinkley wrote:
       | I feel like I'm eavesdropping on an argument that two people have
       | been having for five years.
       | 
       | Anyone have an explanation of what is going on here? I'm finding
       | the article impenetrable.
        
         | verdagon wrote:
         | Yeah, this article was rather sparse on background, more
         | intended for friends and sponsors and people who have been
         | following along with Vale. A strategy that backfires with
         | general audiences like HN!
         | 
         | TL;DR: Vale is like a cleaner C++, and it uses generational
         | references [0] which are similar in spirit to running with ASan
         | [1] turned on. Generational references have a bit of overhead,
         | but it can be removed by regions [2] or more specifically,
         | immutable region borrowing [3]. This helps Vale achieve its
         | goal of being a high-performance language while still remaining
         | memory safe.
         | 
         | Hope that helps, happy to answer any other questions =)
         | 
         | [0] https://verdagon.dev/blog/generational-references
         | 
         | [1] https://github.com/google/sanitizers/wiki/AddressSanitizer
         | 
         | [3] https://verdagon.dev/blog/zero-cost-borrowing-regions-
         | overvi...
         | 
         | [4] https://verdagon.dev/blog/zero-cost-borrowing-regions-
         | part-1...
        
       | crunchengine wrote:
       | [flagged]
        
         | pxeger1 wrote:
         | I'm 99% sure you're confusing this with V. This is Vale, which
         | is not the same. (And V is controversial but I wouldn't say
         | it's a scam either)
        
       | revskill wrote:
       | Thanks. At least i don't have to write Rust.
        
       | jupp0r wrote:
       | The approach of having options to optimize hot code paths with
       | zero cost abstractions while still not having to worry about
       | memory management in the vast majority of the rest of your code
       | sounds like the best of both worlds to me (given that we only
       | trade performance, not safety for convenience).
        
         | mgaunard wrote:
         | I write C++ exclusively and never worry about memory
         | management.
         | 
         | I don't use smart pointers since shared ownership is a bad
         | concept.
         | 
         | The problem of memory management is largely trivial.
        
           | jlouis wrote:
           | If you witness the amount of effort/work/man-hours that is
           | being poured into making memory management easier, I'd say it
           | is far from a trivial problem.
           | 
           | If you witness the endless amount of bugs, many security
           | related, which stems from the idea that people can handle
           | memory, I'd say it is far from a trivial problem.
           | 
           | If you witness any modern language, a common design principle
           | is to eliminate memory management. Which argues it is far
           | from a trivial problem.
        
           | jupp0r wrote:
           | std::unique_ptr is smart without shared ownership. You not
           | knowing this makes your claim that memory management is
           | trivial much less credible.
        
           | willvarfar wrote:
           | The problem of memory management is largely trivial _if_ you
           | are in a small clean opinionated private codebase without
           | cruft, collaborators, third party code, ...? :)
           | 
           | Google et al have been working on sanitisers etc because,
           | even in well kept codebases with strict coding standards that
           | are rigorously applied in reviews, memory bugs do actually
           | creep in.
        
             | jupp0r wrote:
             | Memory management is trivial if your problem is trivial. In
             | the real world you have network connections that fail,
             | third party libraries with other conventions than yours,
             | multiple threads with their own lifetimes, memory mapped
             | files, etc.
        
             | zelphirkalt wrote:
             | Not disagreeing with your first paragraph and will add,
             | that memory management mistakes happen to the best. But it
             | is also probably true, that Google and others do this,
             | because they know there will always be someone committing
             | shit, no matter, whether they are at Google or another big
             | company. So they want guarantees, not blind trust.
        
             | mgaunard wrote:
             | Third party code is a risk and should always be carefully
             | managed and properly isolated.
             | 
             | This applies regardless of programming language.
             | 
             | Of course the web people and their "frameworks" is just
             | another demonstration of how bad relying on third party
             | code is.
        
               | chubot wrote:
               | Not true, taking on C or C++ dependencies has different
               | potential consequences than taking on Java or Python
               | dependencies
        
             | flohofwoe wrote:
             | > _if_ you are in a small clean opinionated private
             | codebase
             | 
             | This is actually an important point. I think _all_
             | codebases can (and should) be split into small,
             | opinionated, privately owned sub-codebases. This is why
             | developing large scale projects can work even in languages
             | like C. After all this is what that whole  'modularity'
             | thing is about ;)
             | 
             | (it also implies that external dependencies need to be
             | managed the same way you handle internal dependencies, as
             | soon as you use an external dependency you also need to be
             | ready to take ownership of that dependency)
        
               | kaba0 wrote:
               | Memory management is fundamentally a cross-cutting
               | concern, so modules don't help, unless you introduce some
               | hard barrier (like copying everything at boundaries).
        
               | flohofwoe wrote:
               | Generational-indices also help to secure system
               | boundaries. The memory is always owned and manipulated by
               | a system, and the system only hands out generational-
               | index-handles as "object references".
               | 
               | Arguably that's even a good idea in memory safe
               | languages, it avoids tricky borrow checker issues, and
               | also prevents the outside world to directly manipulate
               | objects. Everything happens under control of the system.
        
               | anonymoushn wrote:
               | Modules work if they can operate without allocating or
               | are generic over allocators. I don't really get why
               | people think it's normal for e.g. a websocket decoder to
               | insist on calling read, write, epoll, and mmap, if the
               | user just wants to encode and decode messages.
        
           | dataflow wrote:
           | > I don't use smart pointers since shared ownership is a bad
           | concept.
           | 
           | I think you mean you don't use _shared_ smart pointers? Or do
           | you avoid unique_ptr too?
        
             | mgaunard wrote:
             | I use values.
        
               | dataflow wrote:
               | You never use the heap?
        
               | JonChesterfield wrote:
               | C++ uses value type to mean either a scalar object (int,
               | tuple<double> etc) or a container that manages heap
               | memory for you, e.g. a vector of a value type. If you
               | stay in that world you can basically ignore memory
               | management.
        
               | dataflow wrote:
               | Staying away from std::unique_ptr<T> and
               | std::unique_ptr<T[]> while using std::vector<T> sounds
               | kind of silly. The last one is a generalized version of
               | the first two. So claiming you don't use the first two is
               | really misleading.
        
               | spacechild1 wrote:
               | But std::shared_ptr is also a value type :)
        
               | Tehdasi wrote:
               | I dunno about the GP, but it's a JPL guideline to never
               | use dynamic allocation after initialization. So it's not
               | unthinkable. I'd suspect that many microcontroller
               | programs might have to be really careful about using the
               | heap just because they just don't have the memory to
               | allocate that much.
               | https://www.perforce.com/blog/kw/NASA-rules-for-
               | developing-s...
        
               | rcxdude wrote:
               | It's pretty easy in a lot of embedded applications to
               | basically only have objects that live forever or are
               | allocated on the stack. I usually aim for zero heap at
               | all, and just have statically allocated objects for the
               | 'forever' set (which makes it easier to see what's using
               | memory). If you're careful you can also statically work
               | out worst-case stack usage as well and have a decent
               | guarantee that you won't ever run out of memory. If there
               | are short-lived objects, a memory pool or queue is
               | usually the best option (though at that point you do
               | invite use-after-free type errors and pool exhaustion). I
               | would say with this style it's extremely rare to have
               | memory safety issues, but it's also not really suitable
               | to a lot of applications.
        
               | Lk7Of3vfJS2n wrote:
               | Why is it not really suitable to a lot of applications?
        
       | jadbox wrote:
       | What is Vale used for today?
        
         | verdagon wrote:
         | Not much! It's still _very_ young, still in the prototype
         | phases. When it 's more mature and polished I hope it will be
         | useful for those writing servers and games mostly.
        
       | hu3 wrote:
       | ...more predictable latency than tracing garbage collection.
       | ...better performance and cache friendliness than reference
       | counting.        ...prototype and iterate more easily than with
       | borrow checking.
       | 
       | Ok, you had my curiosity, but now you have my attention.
       | 
       | Just started following your RSS feed:
       | https://verdagon.dev/rss.xml
        
         | iopq wrote:
         | Finally some new ideas for AOT compiled languages that don't
         | devolve to "what if we just have memory bugs some of the time?"
        
           | JonChesterfield wrote:
           | Generational references leak if a counter reaches int_max and
           | involve an increment on alloc and on free. Seems pretty close
           | to reference counting to me.
           | 
           | https://verdagon.dev/blog/generational-references
           | 
           | Statically eliminating memory operations does seem to be a
           | win though.
        
             | pxeger1 wrote:
             | Reference counting involves an increment every time a
             | reference is shared. That's a lot more overhead than just
             | on alloc and free - in particular, it involves going to
             | main memory (or using part of the cache) a lot more in
             | order to change the ref counts. Whereas on alloc and free,
             | those frames have to fetched anyway (at least in my
             | understanding of how memory allocators work)
        
             | klabb3 wrote:
             | Ref counts have cycles, which cause leaks (in this
             | universe).
             | 
             | But I digress. Overhead like increments only matters on hot
             | paths, which are very few. The Python + C stack for ML is a
             | manifestation of this truth.
             | 
             | Having ergonomics of a "regular language" (affects all
             | code) and the ability to optimize for performance (hot
             | paths only) _and stay in the same language_ is what I'm
             | excited about.
        
             | foota wrote:
             | My understanding is that this has some benefits over
             | reference counting, though it it similar. Part of the
             | issues with reference counting is that they are shared,
             | meaning that it needs to be atomically incremented and
             | decremented whenever you make a new reference (for instance
             | in C++ if you return a shared_ptr or similar). Generational
             | references though instead track something as a part of the
             | value you pass around, meaning that it has better locality
             | and doesn't suffer from contention.
             | 
             | Copying references is assumed to be more frequent than
             | allocating and freeing, so this is a win.
        
             | flohofwoe wrote:
             | Typically that slot is disabled on overflow, so that no
             | more objects can be created at that slot / memory location,
             | which avoids the handle collision. The slot could be
             | recycled at specific points in the code when it is certain
             | that no more handles for this slot are out in the wild (not
             | sure if Vale does that)
             | 
             | (Or possibly the whole region could be discarded once it
             | was running full, and the physical memory recycled at a new
             | virtial address. There's plenty of virtual address space to
             | burn through when not limited to 32 bits)
        
             | Tuna-Fish wrote:
             | > Generational references leak if a counter reaches int_max
             | 
             | With 64-bit counters, that's never going to happen.
             | Alloc/free costs more than a nanosecond, and there are lot
             | more than one element that you will be allocating, but even
             | if you somehow managed to reallocate the same object a
             | billion times a second, it would take over 500 years to run
             | out of indexes.
        
               | pulse7 wrote:
               | What about if you reach 100 billion times a second (maybe
               | with 128 cores) and have a long running system? Maybe in
               | this case 128-bit or 96-bit counters are better...
        
               | nyanpasu64 wrote:
               | You can't allocate and deallocate the same address
               | (incrementing that address's generation by 1 each time)
               | 100 billion times per second.
        
               | jeremyjh wrote:
               | Is it even physically possible to allocate memory that
               | fast?
        
               | slashdev wrote:
               | If your program is allocating so much that you can
               | exhaust a 64bit counter, you have a seriously bad program
               | plus a serious memory leak. Exhausting the counter would
               | be the least of your worries.
               | 
               | Practically speaking you could never allocate memory that
               | fast, a memory allocation is going to be well over 1000ns
               | on average.
               | 
               | Then there's the little matter of address space. Pointers
               | on x64 are limited to 47 bits, meaning that if even you
               | had a magical memory allocator with no book-keeping
               | overhead, and all your allocations were 1 byte, you'd run
               | out of pointers first. The actual virtual memory space is
               | limited further on many operating systems, but you're
               | still always going to be well short of 64bits.
        
               | dmytrish wrote:
               | Memory is meant to be reused, "64 bit counter will be
               | enough for everybody" is not how systems programming
               | works.
        
               | nyanpasu64 wrote:
               | > "64 bit counter will be enough for everybody" is not
               | how systems programming works.
               | 
               | Except when it is: https://threatpost.com/another-linux-
               | kernel-bug-surfaces-all..., fix at https://git.kernel.org
               | /pub/scm/linux/kernel/git/torvalds/lin...
        
               | hinkley wrote:
               | VMAs sound expensive. Of course a 64 bit counter is going
               | to work for moderately expensive things.
               | 
               | If you have a multithreaded app doing a lot of
               | communication, that's going to be a lot of cheap
               | allocations happening very fast.
               | 
               | Reducing GC and allocation overhead results in more
               | allocations being done, and pushback against ever-
               | expanding allocation behavior is more of a challenge.
               | Instead of ten other things being a higher priority than
               | judicious data architecture, it's dozens or more.
        
               | slashdev wrote:
               | Except when it is. You'd be surprised what systems
               | programming looks like.
               | 
               | Reference counts are not re-used when memory is re-used.
               | And again, even if for some reason you had a global 64bit
               | counter that you incremented on every allocation and
               | never decremented, and you could somehow handle a billion
               | allocations per second, you'd have 585 years before that
               | counter overflowed back to 0. No computer or program can
               | run for that long.
        
               | Tuna-Fish wrote:
               | There is a separate counter for every memory object. One
               | counter is only ever going to be touched by a single core
               | at a time.
               | 
               | And even if there was a single counter, multithreading
               | cannot make incrementing a counter faster. Two cores
               | cannot write to the same cache line at the same time.
               | Instead, cache lines need to bounce across cores when you
               | write to them, and this takes such a long time that it
               | turns the time it takes to roll over from centuries to
               | millennia.
        
           | renox wrote:
           | Uh? While generational reference are memory safe your program
           | still crash when there is a memory issue.. It's much better
           | than going on in a corrupted state but still it's a crash.
        
           | reilly3000 wrote:
           | I have a new favorite HN comment :)
        
       | garganzol wrote:
       | A distinguishing feature of Vale is: a) natively-compiled safe
       | language b) that still has a sane syntax.
       | 
       | I remember seeing Vale many years ago (~10). Back then, it was
       | something revolving around Gnome project, but now it still has a
       | pre-prelease version 0.2-alpha. This means that the project's
       | progress is relatively slow, but the language is very interesting
       | to me.
       | 
       | Update: I confused Vale with Vala! Vale is the new project, Vala
       | is 10+ years old, but they have an intersection of syntax, goals
       | and ideas. That's why I was misled by seeing a similar name. Val-
       | vale is almost the same!
        
         | asabil wrote:
         | I think you are confusing Vale with Vala[1] :)
         | 
         | [1]: https://vala.dev/
        
       | modernerd wrote:
       | Vale needs more sponsors!
       | 
       | https://github.com/sponsors/ValeLang
       | 
       | Let's use this post's time on the front page to help the project
       | meet its $3,000/month goal.
       | 
       | I'd love to help Evan work on this full time (I'm a sponsor). A
       | fast and safe language that's also fun to prototype with is worth
       | supporting.
        
         | verdagon wrote:
         | Thanks for your support, I really appreciate it =) I would love
         | to do this full time!
        
         | cinntaile wrote:
         | What's the difference in revenue split github vs patreon when
         | sponsoring?
        
           | Bedon292 wrote:
           | GitHub: They keep 6%. With 3% for CC fees and 3% for GitHub.
           | [1]
           | 
           | Patreon: Varies a bit more. Patreon takes 8%, unless they
           | have been on the platform since before the 2019 change and
           | are still on the 5% plan. And payment processing depends on
           | size. Under $3 is 5% and $0.10 per transaction. Over is 2.9%
           | and $0.30 per transaction. And more if PayPal or Venmo in not
           | USD. [2]
           | 
           | So the split seems much better on GitHub. But the conditions
           | are a bit different for using the platforms, and you can get
           | perks on Patreon which you may not be able to get on GitHub.
           | I can't remember who / which project but I believe I saw one
           | that said something about a difference in taxes / VAT and not
           | being able to give some of the perks on GitHub because of it.
           | Cannot find it right now though.
           | 
           | [1] https://docs.github.com/en/sponsors/sponsoring-open-
           | source-c... [2] https://support.patreon.com/hc/en-
           | us/articles/11111747095181...
        
       | [deleted]
        
       | cbsmith wrote:
       | Just acknowledging the Nils Olav Easter Egg.
        
         | kubanczyk wrote:
         | Nobody in their right mind would believe it tho.
        
           | verdagon wrote:
           | Honor to Brigadier Sir Nils Olav III!
        
       | JonChesterfield wrote:
       | Not the same language as V. The latter got a very critical review
       | at https://mawfig.github.io/2022/06/18/v-lang-in-2022.html which
       | I've misattributed to Vale because they're similarly named.
       | Leaving this here in case someone else has made the same mistake.
        
         | amedvednikov wrote:
         | This "very critical review" is just a list of small bugs that
         | were fixed a year ago.
         | 
         | Nothing in this article is relevant, but it still stays up, the
         | only article in the blog.
        
           | sealeck wrote:
           | Note: the author of this comment is author of "V lang".
        
       | bluejekyll wrote:
       | > Vale-specific pre-optimizer, similar to Rust's Cranelift
       | 
       | I think this might instead be MIR, mid-level IR, there's a good
       | blog post here: https://blog.rust-lang.org/2016/04/19/MIR.html
       | 
       | Cranelift is a compiler backend, mainly focused on JIT, but
       | theoretically could replace LLVM, there's an alternative backend
       | being worked on but has limitations:
       | https://github.com/bjorn3/rustc_codegen_cranelift
        
         | conaclos wrote:
         | Yes I think so Cranelift is a Rust optimizer for WebAssembly
        
           | duped wrote:
           | Cranelift is a separate compiler backend, not an optimizer.
        
           | verdagon wrote:
           | You two are correct, fixed, thanks!
        
       | halfmatthalfcat wrote:
       | Frontend in Scala - very cool!
        
       | megamorf wrote:
       | I was confused by the title because when my bubble talks about
       | Vale they mean this:
       | 
       | https://github.com/errata-ai/vale
        
         | zahllos wrote:
         | There is also https://project-everest.github.io/vale/, which is
         | a programming language used in formal verification.
         | 
         | I was slightly confused when I first read the title as well :)
        
       ___________________________________________________________________
       (page generated 2023-07-12 23:02 UTC)