Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
I am not yet ready to switch to Zig from Rust (medium.com/penberg)
72 points by avinassh on June 14, 2024 | hide | past | favorite | 93 comments


I have no issue with the author's points but I just don't see these two as solving the same problem.

Zig, to me, is a better C (as the author notes). It seems like it's designed so you can combine easily with a C code base and incrementally migrate it. That's a great application. I'm not expert enough to speak on the merits of comptime (which the author talks about). But isn't comptime somewhat equivalent to constexpr and similar compile-time constructs?

Rust, to me, fills a niche as a better C++. Macros are better templates. Compile-time ownership checking is better than a C++ runtime smart pointer. There is legacy in C++ that you can never escape eg someone just calling .get() on your smart pointer and doing God knows what with it.

Rust treats memory safety as being of paramount importance and aims to do that with zero runtime cost. That's a great goal but it's also fundamentally different to Zig's goals.


I'm not sure Rust is in the same space as C++, so I'm not sure I'd call it a better C++.

I use C++ because I want performance without all the accounting operations that have to happen in C. I try to write my code in a safe way, but language safety just isn't a priority for me. I guess that's why I'm not using Rust. Fighting the borrow checker doesn't seem worth it to me to gain something that's just not that much of a priority. But I'm not writing an OS or a server.

I'd think of Rust more like a better Ada or some language where safety is first priority


Story time: Chrome is a Frankenstein of C and C++ code (both directly and through called libraries, static or dynamic). Now C++ has `std::string` obviously. C of course has `const char *`. To facilitate interoperability C++ has various methods to implicitly or explicitly convert between the two.

At one point it was found these every keypress on the OmniBar resulted in 25,000 string copies.

So my point is that you can write C++ as carefully as you can but on any sufficiently complex code base you'll going to need a pointer to something and then you've really lost all control and safety so the safety in C++ is a bit of an illusion.



Well, that's horrifying. Presumably the value is being copied whenever it is converted from a const char * to a std::string?

The right thing (TM) would probably be to refactor some of the std::string's into std::string_view's, for instance by adding overloads where it makes sense. I doubt you could avoid all the copies, but I think you could cut it down substantially if you collected metrics and focused on the most egregious cases.

Of course, I do not envy the person who is tasked with doing that, and I could be wrong for any number of arcane technical reasons.


I can only imagine that using std::string_view in a massive, complex application would be horrifying.

The borrow checker is one of the benefits of Rust in that case, simply because you can avoid copies while actually being able to trust that you're not opening the door to security & maintenance hell in the process.


Fun fact: this happened during the standardization of std::string_view, which ended up landing in C++17, a few years after this was fixed. Not that there weren't non-standard versions that existed.

In the end they did a number of things to fix this, the patches are linked in the story I linked above.

std::string_view has seemed, to this relative outsider, to be semi-controversial. It makes it pretty easy to introduce use after frees, that it's not null terminated can be easy to forget, and isn't bounds checked. So while it helps with some issues, it can create others, meaning it's not always a clear win.


a lot of the copies might be bits of code defensively copying the string because they don't want to deal with working out lifetime safety.


Fair but I never said it was safe, just that perfect safety isnt of interest to me


I don't really see the distinction you're making. C++ will still be around for legacy projects that don't want to switch, but I can't think of a new project that would benefit from picking C++ over Rust, apart from needing to integrate with the C++ ecosystem beyond what bindgen offers.

You get to write code that's just as or more performant, and you get to jettison the decades of bad language design that is C++, which is win/win to me.


The pool of C++ engineers is much bigger, and like it or not its a very proven solution. Rust still seems to have a lot of areas where its immature (gui toolkits for example)


Maybe because Rust is not a language made to make GUI applications? For GUI applications you are better of with a higher level language.


Don't you think that's a weird limitation though? Nobody says C++ isn't a language made to make GUI applications. If you're going to replace C++ you should probably be able to do the same things at least as well.


It's not actually a limitation, the ecosystem is just young:

https://github.com/iced-rs/iced

My general point though is that there's still some ecosystem/legacy reasons to stick with C++, but Rust very much fills the same niches as C++.


It's not "language safety", it's memory safety. You're saying that memory safety isn't a priority?

When you run Coverity or other static analyzer on your code, how many violations do you find? How many were unexpected?

The borrow checker is always being run - the difference is whether its in the compiler (Rust) or you in your head (C++). And I trust the compiler much more than I trust myself...


For what I use C++ for (game development and embedded systems), smart pointers are "good enough". Especially single player games, worst you run into is a crash, or my arduino code writes past a buffer.


I see Rust as neither a C nor C++ replacement, it feels more like a much less limited version of Java. Zig, on the other hand, feels more like a highly evolved C.

As a pretty hardcore systems programmer, there are three things that modern C++ has first-class support for that are difficult to live without: metaprogramming, handling cases where ownership is unknowable at compile-time, handling cases where lifetimes are unknowable at compile-time. Rust is still significantly more limited than C++ in what it can express effectively. There are very few features in C++ that are not critical and routinely used in some application domain.

A low-key strength of C++ is that it is not overfitted to any particular assumptions about application domain. This adds complexity (aside from complexity introduced by legacy and age) but with the benefit that there is a subset of C++ that is highly specialized for the requirements of almost any application domain.


Well said. Though it'd be sorta neat IMO if we could use just one language here, and the memory unsafe aspect could somehow be toggled off or on, gaining all the pros or cons of Zig vs Rust as needed.


What you're talking about here is disabling runtime assertions, which is a common practice in C/C++ (using #define macros). Runtime assertions are strictly inferior to Rust's compile-time assertions because Rust allows you to do a subset of what you can do in C/C++ but it verifies that the memory ownership is correct without a runtime cost, unsafe code notwithstanding).

There simply is no way you could do that in C/C++ (and, by extension, Zig) because of the legacy support.

I'm fine with having multiple languages. One language to rule them all just tends to mean something is mediocre at everything.


Are you thinking of something different than Rust's `unsafe`?


How is it a "better C" as compared to Go? Genuinely asking.


Go has a heavy runtime, including both a garbage collector and a userland scheduler. Those features both make it inappropriate for some applications where you would use c, and also make calling (and especially being called from) foreign code problematic. You effectively cant implement a library in go and then call it from another language, not without considerable ffi overhead at the very least.


Go is garbage collected. That's a non-starter for a lot of C use cases.


Go would be amazing if it didn't allow dumb mistakes such as:

    type Human struct {
        Name string
        MaybeHasCat *Cat
    }

    type Cat struct {
        Name string
    }

    func main() {
        h := Human{}
        h.MaybeHasCat.Name = "Taffy" 
    }
And boom. Null pointer exception because MaybeHasCat is null. The fact that go doesn't let you define an optional type is such a pain. A lot of newcomers while getting trained up fall for this bug.

edit: updating to add the pointer i missed. also adding a playground link: https://go.dev/play/p/izcod8xF7ZQ


That’s not true. Here is a go playground of pretty much that exact code running just fine

https://go.dev/play/p/v7OM9s_pRqY


Steelman their example. Given that they named the member "MaybeHasCat", it's pretty clearly meant to analogue an Option<Cat>; if you correct the small typo then (make the type of "MaybeHasCat" a pointer, so that it can store nil for the other half of the Maybe), the example behaves exactly as they describe.


Wtf? what are you doing? Did the point fly over your head, are you being malicious by removing the star, or?


They added the star as an edit because of my playground link. So, neither


That would work. It would need to be a pointer to get a nil pointer exception, or an interface (obv function call to trigger instead of field access), but there are some simple and common patterns you would follow to prevent that.

Edit: should do more than just suggest the fix is easy

So for pointer types you have two options IMO: nil checks, or getters that do the nil check for you.

I think a map type instead of a string would also make your point more strongly because your zero value will fail on access. Which yeah that sucks to run into, and I'd agree actually that a lot of Go painpoints pop up early. I appreciate that now, because most of my foe stubbing was done inside the first few weeks, but it is undeniable imo.


> nil checks, or getters that do the nil check for you

Yes I agree there are patterns to solve for this but it is just strange that the compiler doesn't stop you from making these errors. I mean even Typescript has:

  interface Human {
    name: string
    cat?: Cat
  }


I don't know what 'even typescript' is supposed to mean. Are you saying that typescript is the natural bar for comparison here? That doesn't seem correct, isn't typescript a project that tries to correct javascript's lack of typing?

Since it isn't an error to have a nillable type, and it isn't an error to access a field, it makes sense that the compiler doesn't error when you do that thing. If you want a warning when doing something silly then you can setup a linter.

If your first thought is that is not very beginner friendly then I agree with you - I edited my original response. But otherwise there are solutions to these problems.

If that doesn't suit you and Go isn't sweet enough for you, well, fair. Its rather austere. I don't think it is a categorical error for the project (though there are features I would also like for asking).


My point is nillable values by default is a strange choice and throws out 50 years of computing history. It has been clearly established that it leads to null pointer exceptions. The fact that a modern language lets you do it is a bit strange.


Oh I didn't really get that from what you had been saying.

Sure, I'd agree it feels like a whoopsie, I dislike nil values because they are a common source of faults.


Could just do null -> none, nonnull -> some, optional doesn't introduce anything new here. Either you null check or you optional check

Optionals are just another outlet for "best practice" bullshittery and not much else. If go doesn't have, sounds like they're following YAGNI principle


> Could just do null -> none, nonnull -> some, optional doesn't introduce anything new here. Either you null check or you optional check

I am not sure what you mean by the first point but what I am saying is that the compiler doesn't stop you from having a basic runtime null pointer exception because of "simplicity" and "yagni".


I think you meant

  type Human struct {
     Name string
     MaybeHasCat *Cat
  }
As you have written (not making MaybeHasCat a pointer), go will correctly initialize (at least as of go1.20.5) the nested Cat structure and allow for direct assignment.

Having a null pointer exception for a null pointer is a behavior I would expect. Having one for a non-pointer structure would be surprising.


Let me preface this by saying I like Go. I do. But as much respect as I have for Rob Pike (which, again, I do), he doesn't understand the systems programming space. Go was originally pitched as a systems programming language, a better C, like you said.

But it isn't. It is, however, a better Python (IMHO).

The reason it's not a better C is that it's a garbage-collected language and it has a runtime overhead. As such, Go doesn't really have predcitable performance. It's easy to blow up memory usage (as it is on any GC language) eg goroutines.

So Go just doesn't suit a typical systems or embedded application. Yes, you can use a subset of Go to avoid dynamic allocation and GC in general but really, what's the point in that?

Why it's a better Python (again, IMHO) is that Python has all the same negatives but has a few more, most notably that it is dynamically typed or, as I like to put it, you need to write unit tests for spelling mistakes. I've come to abhor dynamic typing as a truly horrendous false economy. Go doesn't have that problem. Go does need to be compiled but it's a simple language and that compilation is incredibly fast.

My one criticism is that I find Go's unbuffed channels to be a less elegant coordination mechanism to cooperative async/await in other langauges. But YMMV.

Some evidence to back this up is that, at least while I was still at Google, Go projects on google3 were cannibzlizing Python projects and nothing else really.


> Go was originally pitched as a systems programming language, a better C, like you said.

I've always understood this claim as a particular (rather restricted) interpretation of "systems" code - meaning network servers, basically (maybe also CLI applications?)

I'd always thought of "systems" as including things like writing standard libraries, kernels and embedded code. But I guess there is a decent slice of other systemsy stuff that Go is good for.

Whereas something like Zig feels like it could really be a better systems programming language in general that C, in all of its different application areas.


> I've always understood this claim as a particular (rather restricted) interpretation of "systems" code

This is basically the retcon that the golang community has settled on but it's frankly not true.

When go was originally being promoted it was heavily advertised as a systems language suitable for writing low-level programs. Nowhere was it caveated that "systems language" means something different from what everyone understood a "systems language" to be at the time. Only when it more or less failed to gain traction in that space did this get redefined to mean "network servers that mostly just shuffle bytes around and CLI applications".


Python also has some positives that Go doesn't have, like iterators without the community freaking out about them. It's obviously way more ergonomic to use Python, and if you want types, Pyright works very well.

My issue with Go is that it's not low level enough to be good for systems programming but it's not high level enough to avoid boilerplate.


> My issue with Go is that it's not low level enough to be good for systems programming but it's not high level enough to avoid boilerplate.

That's really interesting because in general I find Go faster to work in than Python. Python has great flexibility but even production code I read is littered with noise that I don't see with Go applications. Other than error propagation - which is more a style choice than boilerplate - I find doing something in Go results in fewer lines of code and less spaghetti logic.

I'm a bit too dug in on Rust to spend a ton of time replacing it with Zig and my use cases frankly could be handled by a Go app without much worry about performance. But one thing Rust has is boilerplate out the wazoo.


I have heard this anecdote a few times but I don't understand it. Even ignoring error handling in Go, I feel like everything is noticeably more verbose and noisy than something like Python. A language that prioritizes readability is intriguing to me, but I just haven't experienced that with Go.

Not that I haven't seen messy Python code (I sure have). The best Go code is gonna look better than the worst Python. But on average, it seems like complicated flows can be written very elegantly and readably in Python and look ugly in Go.


Go isn't pretty to look at, but I feel so much more confident in a successful Go build than starting up Python–not knowing when exceptions will throw or crash until it's run is frustrating.

I'm sure Rust folks feel exponentially more safety than Go at compile time, but the jump from Python to Go is dramatic for me.


As someone who used to write a lot of Ruby and now has started to write some Go, I feel like you nailed it.

Go is compiled language for people coming from dynamic languages. The type inference is good enough and the compilation types are also quite fast.


I dubbed Go 'C+-' the first time I used it, and it was on a program that made heavy use of threading and used a producer-consumer workflow, so I don't think I could have used a better program to test it (and I think Go was the best language for my program).

It probably has changed since, it has been 10 years now, but my feelings were at first 'wow! This is easy' during the prototyping phase, then 'ugh, i'm so limited' during the finalization (and at random points in the middle too probably, but I was fanboying at the time so I didn't really notice). One of the worst thing is the debugger imho. I _get_ gdb. I haven't written a line of C in years, you put me in an interactive gdb, I'm home. Go, I didn't understand how to debug, I had to use my 1rst year technique of printing everywhere, except I never managed to make use of %p, so I was even less effective than that.


Delve is a great debugger for the Go.


Bear in mind this was 10 years ago hopefully Go have a debugger now, but still, it won't be gdb.


Go's debugger has worked just fine for years. What do you prefer about gdb (which also seems to support Go)?


Go is a garbage collected language


Why he is not ready :

> comptime feels like a hack, I much would prefer the legacy preprocessor macros C if I can’t have generics.

If comptime is a hack, the preprocessor is the king of hacks.

> You still end up chasing SIGSEGV

Don't the zig compiler in safe mode tell you about it ? Sure it's not as good as preventing a entire class of error but at least you probably get the line in your code where it happens. If you are used to C as you say you are, and if you think Zig's purpose is to work alongside/replace C as you say you think, well, that's not something to be held against zig adoption.

> You end up leaking memory

But he also says "Of course, Zig has really nice tooling here to catch them quickly, so perhaps not such a big issue." So nothing to see here.

All the rest is how zig/its ecosystem/industry/community is not there yet which, of course, it's not 1.0 yet. From the zig website : "Zig is immature. Even with Zig 0.13.0, working on a non-trivial project using Zig will likely require participating in the development process."

I don't blame the author but that's not really Hn worthy nor newsworthy


This

> You still end up chasing SIGSEGVs.

and the memory leak part are interesting.

The think is if you do very low level stuff with rust, like embedding programming are interacting a lot with C interfaces (or providing them) this is true without question. Similar if you rewrite some of the low level micro optimized parts of a async scheduler like tokio.

As a PSA the rust type system and borrow checker even helps with unsafe code as it doesn't remove this checks, just gives you additional tools do to stuff which can undermine them, but (the PSA part) at the same time you have to make sure you uphold the rust safety constraints and memory model (which isn't fully specified yet) which can sometimes mean some things which are fine in C are not fine in rust even if you can do them with unsafe code!

But for a lot of the daily work of a lot of rust project you don't really run into segfaults (if you don't do premature micro optimizations or write in a very non rusty stile of using a ton of unnecessary unsafe). Similar memory leakage is limited to stuff like circular Arc/Rc or global collections where you put stuff in but don't remove it. But due to shared long lived ownership (e.g. Rc) being very explicit it happens less often in my experience compared to GCed languages.

Anyway that is if you stay in rust, especially safe rust.

So I'm not surprised that someone who considers Zig as tooling doesn't have this experience as they are likely having a lot of tasks which involve aspects where rusts type system runs into limitations of how it can help you.


When I read articles like this I feel compelled to respond in the hope that someone can benefit. So take this however you like but it's a bit of advice from someone who has had a long, fruitful and (at times) happy career in software for nearly 30 years at this point and has programmed professionally at a very serious level in probably nearly 10 languages at this point.

Don't worry about which language is the "best" according to the opinions and fashions of the day. Just pick something and go really really deep. If you are lucky enough to stick around in this industry you will inevitably over the course of your career end up programming in a plethora of languages anyway but especially to start with, you will gain a lot from learning how to become a real expert in one thing. Much more than you would gain by flitting from one new hotness to another.

For me, I had messed around and done professional work in a bunch of languages but the real turning point came when I decided to really get good at perl[1]. I went through a period where I would go on comp.lang.perl.misc on usenet every day and answer every question I could. Read docs and source code, write little test programs, try things out until I knew and understood the answer. I wouldn't always post my answers because sometimes it took long enough to find the answer that someone else would beat me to the punch, but I got really good at perl in a short space of time. That got me my next two jobs during which time I consolidated that knowledge until I really really really knew perl well (and it's a big language and there is a lot to learn so this is a serious undertaking).

The effort involved in doing this - sticking with one thing and learning it really well - has paid off enormously ever since. I have learned and used tons of other languages since then and it is really fast because I really knuckled down and took the time to get good at perl and that taught me a lot about how to learn languages in general.

[1] A language I realise as I write this that I have not touched for about 20 years other than to use in shell oneliners when I'm trying to do something in regexes that's a bit too hard to do some other way.


I like Zig a lot. It feels like C, it's easy to use C libraries in Zig, and it's more ergonomic and has fewer footguns. As soon as Zig's standard library stabilizes I'll be all over it.


My current feelings are that I really like Cargo, but don’t enjoy writing Rust. To be honest, if C++ had its own cargo I don’t think I’d ever reach for anything else.


To be honest, because Cargo is good it makes me not want to leave it behind for something like Bazel.

If Cargo existed, people would not have developed interesting build systems like Meson and Ninja- and especially not Bazel which really leans in to fixing C++'s build issues.

In some cases, worse is better.


I don't think you can do dependent builds with cargo.

Like build a sub-target using say wasm-pack to then embed the output into a binary. IIRC it gets upset because the cargo lock is already acquired or something.


I have always wondered if it would be possible to write a language agnostic package manager. Lord knows we probably don't need more programming languages, but it would be much easier to get on of the ground if it could just plug itself into an existing package manager.


Same here, and I periodically research but remain disappointed; people usually just write a tool to address their current pet peeve and 1-2 years later the tool is of course abandoned.

Using just[0] as a task runner has solved a lot of per-project-scripts problems for me but it still cannot do DAG analysis + parallel task running of tasks not blocked on each other (or allow you to opt into serial or parallel task running). So it remains firmly in just the "task runner" territory.

I know many people would jump at the opportunity to say "just learn `make`!" but no thanks, I value my sanity. `make` is also inheriting a lot of bash-ism weirdness which makes it even worse.

The mage[1] tool that uses `Magefile`-s might be it but it's a bit more verbose (as it's Golang) and I am not sure how well does it integrate with the shell. Maybe script[2] can be used to complement it.

Sadly I don't have the time (and lately the inclination) to experiment but there are tools out there and I wish we finally started unifying things.

[0] https://github.com/casey/just

[1] https://magefile.org/magefiles/

[2] https://github.com/bitfield/script


What's so good about Cargo?


Cargo makes the easy cases very easy. And because it has existed for a very long time, this means that “the easy case” is a very very large amount of the overall cases.

This means that for the majority of folks and projects, it ends up being a very smooth experience.

That does not mean that Cargo is perfect, and there’s a lot of stuff it doesn’t do well.


In my limited experience, it makes the hard cases harder. I had a project where I needed to do some weird linker things and ended up moving to C++ because Cargo couldn't handle it.


At $dayjob we have ended up building three different build systems on top of Cargo. You're not wrong. But luckily those things are pretty rare, in my experience.

I am hoping that buck2 can get easier to use "in the small" and then just switch to it for all things, but it's too immature outside of Meta just yet.


How long have you been writing Rust?


> I quickly discovered that I really like Zig because it feels like C!

I honestly cannot imagine anyone feeling this way. Here's some code randomly pulled from the Zig website:

  const std = @import("std");

  pub fn main() void {
      const msg = "hello this is dog";
      var it = std.mem.tokenize(u8, msg, " ");
      while (it.next()) |item| {
          std.debug.print("{s}\n", .{item});
      }
  }
That's the kind of code you write with Zig. It's definitely not C. The author probably means something else, but to me the two are very different.


That's just syntax. Once you get past the syntax, the structure and flow of the language feels like a highly evolved C.

Zig has a high degree of mechanical sympathy with C programmer brains.


The author wrote "it feels like C". You're saying "the language feels like a highly evolved C". Those are two very different things. I agree with your statement but "highly evolved" implies they're substantially different.


"feels like C" and "looks like C" are not quite the same thing.

That Zig feels like a modern C is a very common opinion.


IMO, only in the sense that many languages feel like a modern C. The differences between C and the Zig code are much more than just syntax.


Any idea how many years away Zig is from v1.0?

As someone sold on Rust, I really want Zig to succeed.


Is that sentiment for rising-tide reasons, or to help erode the C footprint in industry, something else?


For me, I found Zig to be really un-ergonomic especially when trying to hack something together quickly. Do I know that printing to stdout could fail? Sure. Do I want to explicitly handle that potential failure every single time I want to print something to the screen? No.


Then add the following and handle it later:

    … catch @panic("todo")
I do it all the time. Lots of @panic during development and then I come back later and handle the error cases separately.


> Perhaps I am still thinking in C too much.

> I much would prefer the legacy preprocessor macros C...

Holy cow you weren't kidding :)


Is there actually a compelling reason to use Zig over Rust?


I only played with Zig for a weekend, so others will need to chime in, but a few points:

- Zig's comptime is extremely flexible, while Rust's generics are more constrained. It's not clear if Rust will ever get "specialization" for example, but Zig gets that sort of thing for free by making the whole language available at comptime.

- Zig is very explicit about memory allocation, and the standard library doesn't include types like Rust's Vec or String that implicitly talk to a global allocator. If you're writing an application that must not allocate in the render loop / control cycle / etc, that can be a feature.

- Zig doesn't have a borrow checker. If your application plans to use memory management strategies like "a bump allocator that frees everything at the end of a frame" or "a bump allocator that frees everything at the end of a query", it can be painful to express the lifetime restrictions of those allocations in Rust. Zig doesn't get in the way of those strategies, though that also means there's no such thing as "safe code" in the Rust sense.


> Zig doesn't have a borrow checker. If your application plans to use memory management strategies like "a bump allocator that frees everything at the end of a frame" or "a bump allocator that frees everything at the end of a query", it can be painful to express the lifetime restrictions of those allocations in Rust. Zig doesn't get in the way of those strategies, though that also means there's no such thing as "safe code" in the Rust sense.

I don't use Rust often, so I'm admittedly not that knowledgeable on what's already possible, but does seem like something that could benefit Rust is if there were a way to express in some limited context that something like a doubly-linked list is safe because all its nodes are associated with / owned by the same allocator, and their lifetimes all end when the allocator dies. The rule could be that, within the context of an arena allocator, these arena pointers could point to any memory also allocated by the same arena allocator (including mutable aliasing pointers), but the things they point to could never be moved (or else other arena pointers might dangle) and they wouldn't ever be freed until the "allocator context" ends (or else you might get use-after-free mistakes), and it would have to be within the context of one thread (or else there might be data races). The idea being that all the memory in the arena is allocated at once. Then you could do things like e.g. join two doubly-linked lists that were allocated by the same arena allocator. Then multiple doubly-linked lists could be expressed in safe Rust, as long as they were backed by one arena allocator that deallocates all at once.


Arena allocators can be used with lifetimes in the way you describe, but that's just not people's usual definition of linked list, as it misses out on some key properties people use linked lists for.


How can you? (genuine question)

I found this project: https://git.sr.ht/~vlmutolo/chainlink

But they use generational indices into a vector. You can't append two doubly-linked lists because they have their own vectors. I was thinking of two separate doubly-linked lists using real pointers (not indices into a vector), but since they were allocated by the same arena allocator, they can be appended.

Is that already possible (in safe Rust)? If so, I guess I should have done more research, sorry :)

Edit: Oh, do you mean the normal one from the standard library? https://doc.rust-lang.org/std/collections/struct.LinkedList....

My bad. I was thinking of something similar, just not implemented with raw pointers underneath, but it already takes an allocator argument in the type, so there would be no benefit to this. Kind of embarrassed now.


I wasn't thinking "use std::collections::LinkedList with an allocator parameter," just that like:

1. The reason linked lists in Rust are difficult is due to lifetimes.

2. Arenas in Rust are parameterized by a lifetime, and that does the stuff you want here, that is, make sure that they can't go away until the arena does.

3. This means this should Just Work.

I haven't written the code because I don't think it would be that useful. I already wrote one terrible linked list based on generational indices that's not useful for anything, so doing it again doesn't sound that fun, haha. Looking at chainlink, it's roughly the same design, except with a Vec instead of the arena, which isn't much of a difference.

> Kind of embarrassed now.

No need to be embarrassed by asking good-faith questions.


You can put nodes in a Slab or a SlotMap, use keys/indexes for your next pointers, and create multiple interacting (possibly overlapping) lists that way. You have to be careful not to combine nodes from different collections, but that's also sort of true with memory allocators.


Interoperability with C is amazing. You can literally include C headers in your Zig code and start using it without manually writing / generating any boilerplate. So I would imagine if you need to heavily interact with a lot of C libraries, it might be better for that use case.

https://ziglang.org/documentation/master/#C


Rust makes writing incorrect programs hard, Zig makes writing correct programs easy.


I would be interested if somebody also writes "Zig vs. V". I know the latter ate a lot of flak around here but I've been checking it a few times a year and it seems to legitimately make progress. But I won't be trying it myself, sadly my plate is quite full already.

Maybe an organization doing something like "Yearly round-up of systems languages" would be hugely beneficial to the community, provided anybody is willing to pick up the torch.


so don't.


"I just learned mandarin, I am not yet ready to learn arabic"


zig is just a temporary resting place for HN language hipsters

in four months you will be moving on to Swift6

then either Gleam or Roc, that should take us to 2025

oh look, Mojo hit 1.0, time to make the jump!

at that point you will throw your hands up and try Perl


You know, we have a fair amount of older scripts written in various languages.

I don’t love Perl, but the fact the language failed to get to version 6 means that these old Perl scripts just keep working.


Perl 6 exists. It is just called Raku nowadays. https://raku.org/


>in four months you will be moving on to Swift6

How many keywords does the language have at the moment? I churned at @ResultBuilder.


I think we are going to circle back to "Modern" Fortran for a while to try out the parallelism features once generics get finalized in the next release.

https://github.com/j3-fortran/generics/


When will those generics be available in a portable fashion with multiple compilers?


Woah, we'll be bored and move on long before Fortran generics will become portable or supported by multiple compilers in 2034. Avant garde.


Pft, I'm already all-in on Odin.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: