Live data from Hacker News

Allocgate: Restructuring how allocators work in Zig

pithlessly.github.io

11–20 of 52 posts

Re: Allocgate: Restructuring how allocators work in Zig

#11
post #6

Earlier quoted context omitted.

`defer` and `errdefer` give you 90% of what destructors & co give you for 0% of the complexity. For now the the closest thing to RAII is this proposal, but there is no guarantee that it will be accepted. https://github.com/ziglang/zig/issues/782

I find in C++ at least reasoning about RAII is always surprisingly complex. The second you have to write a custom destructor you get into the weeds of reasoning about copy/move/copy-assignment etc. https://en.cppreference.com/w/cpp/language/rule_of_three C++ RAII also rubs up painfully against handle based APIs (looking at you Windows) in my experience. There is a lack of standardized RAII wrappers for handle types l…

> There is a lack of standardized RAII wrappers for handle types like there is for pointers.

.. what's wrong with

    #include 

    template
    using safe_handle_t = std::unique_ptr;

    using file_handle = safe_handle_t;

    void file_example() {
        file_handle f{fopen("foo", "r")};
    }

Re: Allocgate: Restructuring how allocators work in Zig

#12

Does anyone know if RAII types will ever be a thing in Zig?

It's unlikely. RAII comes with a surprising amount of complexity. In order to have a reasonably complete language that has RAII and value types, you must also have: - constructors - destructors - overloadable copy assignment operators - placement new - move semantics and rvalue references These features come together or not at all. If you lose any of them, the language becomes less complete. I think Rust and C++ are…

> In order to have a reasonably complete language that has RAII and value types, you must also have: - constructors - destructors - overloadable copy assignment operators - placement new - move semantics and rvalue references

Rust has RAII and value types, and does not have constructors, overloadable copy assignment operators, placement new, or rvalue references (though we do of course have a very similar notion to rvalue/lvalue in general, but that's not the same thing as "rvalue references" with relation to all of this). While it has move semantics, they're significantly different.

Re: Allocgate: Restructuring how allocators work in Zig

#13

Does anyone know if RAII types will ever be a thing in Zig?

When people talk about RAII in relation to Zig I think they mean something slightly different than RAII, but then the conversation starts to become about what is the definition of RAII rather than whether the Zig language is lacking a certain kind of useful abstraction. Examples: [1]: https://news.ycombinator.com/item?id=29506814 [2]: https://gist.github.com/andrewrk/190170bc1441839644c3f15725a...

Not saying this means you actually need to add constructors and destructors, but I think the main tricky bit is when you have eg. a grow / shrinkable array and want to call something on it that removes elements and it should be calling destructors on those. AFAICT there's no clear place to add a `defer` that makes it happen at the right time at the lexical site those elements are originally added. I think this is where the main RAII complexity comes from vs. the lexical scope local variable scenario which is definitely handled by `defer`.

All that said, not an argument for having that, just wanted to nuance it. I think not having it and keeping the language focused on its priorities can be good, for example.

Re: Allocgate: Restructuring how allocators work in Zig

#14

Does anyone know if RAII types will ever be a thing in Zig?

It's unlikely. RAII comes with a surprising amount of complexity. In order to have a reasonably complete language that has RAII and value types, you must also have: - constructors - destructors - overloadable copy assignment operators - placement new - move semantics and rvalue references These features come together or not at all. If you lose any of them, the language becomes less complete. I think Rust and C++ are…

Only C++ has all of what you mention. Plenty of languages provide RAII without introducing all that complexity such as Ada, Rust, Vale. D has RAII but unfortunately it too carries much (but not all) of the complexity of C++.

Re: Allocgate: Restructuring how allocators work in Zig

#15

why not just an an interface type instead of this giant mess?

"allocgate" is actually a meme name that we purposely gave to this API change. In reality it's not a big deal and that's the superpower that a language v0 has: you can make breaking changes.

As for the builtin interface type, why get locked into one particular implementation when you can have all of them by leaving the choice to the programmer.

Re: Allocgate: Restructuring how allocators work in Zig

#16
post #6

Earlier quoted context omitted.

I find in C++ at least reasoning about RAII is always surprisingly complex. The second you have to write a custom destructor you get into the weeds of reasoning about copy/move/copy-assignment etc. https://en.cppreference.com/w/cpp/language/rule_of_three C++ RAII also rubs up painfully against handle based APIs (looking at you Windows) in my experience. There is a lack of standardized RAII wrappers for handle types l…

> There is a lack of standardized RAII wrappers for handle types like there is for pointers. .. what's wrong with #include template using safe_handle_t = std::unique_ptr ; using file_handle = safe_handle_t ; void file_example() { file_handle f{fopen("foo", "r")}; }

Now you have a double indirection. Worse, the handle probably already references dynamically allocated memory. So that’s two dynamic memory allocations per “safe” handle. Which might be perfectly acceptable for non-critical programs, but it is certainly going to tank your memory usage efficiency and thrash your CPU cache if scaled up to millions of handles.

Re: Allocgate: Restructuring how allocators work in Zig

#18

Does anyone know if RAII types will ever be a thing in Zig?

It's unlikely. RAII comes with a surprising amount of complexity. In order to have a reasonably complete language that has RAII and value types, you must also have: - constructors - destructors - overloadable copy assignment operators - placement new - move semantics and rvalue references These features come together or not at all. If you lose any of them, the language becomes less complete. I think Rust and C++ are…

Rust doesn't end up with an overloadable copy assignment operator, it does something else which I would argue is cleverer (although you can't just add it to an existing language)

Because Rust knows the lifetime of everything in your program (in Rust the lifetime of things is part of their type) the effect of the assignment operator = is to dispose of whatever was in the variable before, and move the assigned item into the variable.

Rust's Copy trait does not alter the semantics of the assignment operators - you can't overload that. You promise that your type's in-memory representation is all that matters, and then if you move from a variable the value in that variable is still live even though there was a copy made, usually that value would be dead because it was moved from.

Rust's Clone trait behaves a little like a C++ copy constructor, except, it's an explicit trait, the only way to get a clone of x is to x.clone() or various moral equivalents e.g. Clone::clone(&x); so you're not getting one without explicitly asking for it.

Rust doesn't formally have Constructors, or from another perspective, any Rust code anywhere which wants to make a Thing, is a "Constructor" for that Thing. (safe) Rust won't let you do any of the shenanigans which is common in C++ like having two separate pieces of code share responsibility for initialising a data structure, in Rust when you make a Thing you need to explicitly set all the values in the Thing at once, if the easy way to write that involves temporaries, no matter the compiler does have an optimiser and knows how to use it.

It is idiomatic in Rust to provide a function named new() in the implementation of a structure which will make you one of that structure if doing so makes sense, but that function and its name aren't magic, it's just a convention. Rust's vector type Vec has a new() function but it also has a with_capacity(n) function, they're both "Constructors" in the C++ sense if you want to think about it that way, with_capacity() isn't calling new() to make the vector, that would be crazy.

Re: Allocgate: Restructuring how allocators work in Zig

#19

I am not fully understanding how fat-pointers allow LLVM to devirtualize the function calls. If the allocators are polymorphic then a particular piece of code doesn't know which vtable it will get at run time correct?

You aren't modifying the same object When you have a fat pointer, llvm can tell you are modifying the ptr, bot the vtable

You can then cache the function call

When your vtable is in the object you are mutating, it needs to read each time

Re: Allocgate: Restructuring how allocators work in Zig

#20

why not just an an interface type instead of this giant mess?

"allocgate" is actually a meme name that we purposely gave to this API change. In reality it's not a big deal and that's the superpower that a language v0 has: you can make breaking changes. As for the builtin interface type, why get locked into one particular implementation when you can have all of them by leaving the choice to the programmer.

> As for the builtin interface type, why get locked into one particular implementation when you can have all of them by leaving the choice to the programmer.

that's a very good point!

Post reply on HN