[HN Gopher] Zig and Rust
___________________________________________________________________
Zig and Rust
Author : avinassh
Score : 204 points
Date : 2023-03-27 12:02 UTC (11 hours ago)
(HTM) web link (matklad.github.io)
(TXT) w3m dump (matklad.github.io)
| MrBuddyCasino wrote:
| This is easily lost in the noise, but Matklad wrote a good
| comparison between Rust and Zig which is worth linking to,
| highlighting Zig's strengths:
| https://www.reddit.com/r/rust/comments/123jpry/comment/jdv9x...
| fnordpiglet wrote:
| This sort of convinced me to stay away from Zig
| avinassh wrote:
| can you elaborate why
| fnordpiglet wrote:
| Essentially the other comments capture my view. Speed and
| memory safety with a rigorous type and language system that
| disallows unsafe operations unless explicitly marked as such
| is worth a lot. I don't think this means zig is worthless,
| and I see a lot of utility in a fast to write lower cognitive
| load language that offers the same speed and memory
| efficiency at the cost of runtime safety, but I don't trust
| myself or other programmers to do a good enough job. Memory
| safety bugs are just so difficult to reason about most of the
| time that I find the compile time safety mechanisms worth
| whatever overhead they impose, to a point. Rust is far from
| reaching that point and is generally easy to develop very
| complex stuff very quickly. So, after reading the article
| (I'm more familiar with rust than zig, so it was very
| informative) it led me to conclude it'll be fun to learn zig
| but I don't think it'll be useful for Serious Stuff.
| lucasyvas wrote:
| Not the parent, but Zig being much easier to use unsafely is
| not a good thing IMO. Rust tries to pave a path for all types
| of developers to eventually learn how to write performant
| code safely in a way that integrates cleanly. This is a much
| more practical need for the programming community at this
| time.
|
| I have to agree with the parent - I was interested in looking
| at Zig eventually, but after reading this I am not. They seem
| to have much more different philosophies than I expected, and
| Zig's does not resonate.
|
| The author's summary really sums it up nicely. I don't need a
| language that prides itself on being a bit more dangerous in
| exchange for some extra control.
| throwawaymaths wrote:
| the assumption with Rust is that memory safety (or,
| generally, resource provenance) is something that needs to
| exist in the type system. Zig is still young, so i would
| say it's not 100% certain that this shouldn't exist, for
| example, in a separate step, for example using static
| analysis.
|
| Rust is already bumping into important cases where the
| typesystem is incapable of resolving things that "you might
| want its typesystem to track", and support for these would
| require breaking all of rust.
|
| Before you say, "static analysis is impossible" -- that's
| very likely generically true for C (something like Sel4 is
| in C but gives even stronger guarantees than rust, but IIRC
| it analyzes machine code). It might not necessarily be. _In
| extremis_ you could in principle attach a separate file
| that provides rust function headers for every single
| function in zig, and checks resource lifetimes inside of
| each function. So it is not _theoretically impossible_ ,
| just a question of whether or not it's _ergonomic_ and
| easily accessible.
| monocasa wrote:
| FWIW sel4 could have verified the C, they simply decided
| to verify the machine code so that they didn't have to
| trust that the compiler correctly complex the verified
| software.
|
| The issue with more broad formal method use is that it's
| quite a bit of work. The code to be verified has to be
| designed on the onset for verification, which limits
| design choices in interesting ways, and even then the
| verification code far outweighs the code being verified,
| at about 25:1.
| estebank wrote:
| > Rust is already bumping into important cases where the
| typesystem is incapable of resolving things that "you
| might want its typesystem to track", and support for
| these would require breaking all of rust.
|
| I would be interested in hearing what it is you had in
| mind. Are you referring to the discussions around
| capabilities?
| nindalf wrote:
| Agree with everything you've said.
|
| > I don't need a language
|
| This, but the bigger issue is that I don't think I can be
| trusted with such a sharp tool. I'm just aware of my own
| limitations, and I think I'd better stick to safe
| languages.
| xedrac wrote:
| I don't want to need to be trusted. And I don't want to
| have to trust others so much. I want my tools to tell me
| I, or someone on my team, did something stupid.
| fnordpiglet wrote:
| Even better, to not be allowed to do something stupid.
| estebank wrote:
| > - Rust is about compositional safety, its a more scalable
| language than Scala.
|
| > - Zig is about perfection. It is a very sharp, dangerous,
| but, ultimately, more flexible tool.
|
| Depending on project, experience, goals, team composition and
| personality, reading these two bullet points you're very
| likely to gravitate much more towards one or the other, and
| potentially feel rejection towards the other.
| olodus wrote:
| Probably just a small miss, but in the first section the author
| refers to stack space limitations possibly hit when calling
| malloc. That should probably refer to heap space. Or if it is
| stack space they meant then maybe not malloc but rather stack
| allocations / function calls.
| jamincan wrote:
| I think he's referring to the fact that as a function, calls to
| malloc result in a new stack frame.
| olodus wrote:
| Besides that little inaccuracy I very much agree with most
| things in the article and think it brings up good points.
| Specifically the part about allocator handling is a huge thing
| for me. Having the allocator be a global thing has always been
| a bit of a cheat imo and it solves so many memory issues just
| to remove that part. And opens up some optimization
| possibilities ad well.
|
| I do agree with some of zigs Cons that you bring up as well.
| Currently I have really been into Linear types and feel like
| that would be the perfect "simple" type-based memory safety zig
| could incorporate without making it too c++ complicated. But at
| the same time I don't know if it would work with its comptime
| and maybe it too would compromise on the simpleness of the
| language. I don't know.
| messe wrote:
| I think they're actually referring the stack usage from the
| function call itself (the creation of a new stack frame). I
| believe the point the author is making is that while it's
| common to check the return value of malloc to see if heap
| allocation was successful, it's comparatively rare to do any
| analysis of stack usage to verify that none of your function
| calls are going to cause a stack overflow.
| monocasa wrote:
| Rust at least will stack probe to trigger any guard pages
| upon allocation.
| 0xfedbee wrote:
| TLDR: Zig bad (like C), Rust good.
|
| Not surprised to see an article like this from a core Rust member
| after two positive articles for Zig on HN frontpage. Gotta keep
| that strong hold on HN!
| Ygg2 wrote:
| It seems you didn't really read the article. Nor do you have
| any ideas who core Rust members are.
| crop_rotation wrote:
| I tried zig after reading so many HN articles and I am not
| impressed. You have to remember to free after each allocation.
| The language is supposed to be simple, yet there exist try,
| catch, defer, errdefer. Rust enums make defining errors so simple
| with arbitrary payload. Using data structures in rust is much
| nicer. I think unless you have some precise needs about memory
| allocation, and want to control exactly where when and how memory
| is allocated, it is hard to argue in favour of Zig. The
| allocation control is very nice if you need it though.
| hhhhmycmd22 wrote:
| That's my complaint about Zig as well coming from C.
|
| I feel that there are too many reserved words in Zig, and some
| of them are too long (comptime for instance).
|
| Maybe that's just me being too picky about surface level
| concerns, but that kind of stuff really bothers me for some
| reason.
|
| Other than that, I do like some parts of Zig. The way templates
| are designed seems superior to C macros and C++ templates,
| having your build scripts be in the language you are building
| is something more languages should do, the compiler is
| impressive in some ways... I suppose in theory all of that
| should make up for the poorly chosen keywords and whatnot.
|
| I disagree with other commenters that think Zig is simple. At
| least compared to C, which I think is fair given Zigs target
| audience. C feels simpler despite all the undefined behavior
| and extensions to the standard and portability issues. Somehow
| I think it's down to the reserved words that were chosen.
| kaba0 wrote:
| > The way templates are designed seems superior to C macros
|
| Everything is superior to C macros, that's like the worst
| thing ever created. Honestly, C is not a good language but if
| it would have had at least a proper macro system it could at
| least be remotely usable, e.g. having proper generic data
| structures.
| chenzhekl wrote:
| Actually I found rust to be easier to learn than zig, as it is
| more consistent in most cases.
| Animats wrote:
| _" (Zig's) collections are not parametrized by an allocator,
| like in C++ or (future) Rust. Rather, an allocator is passed in
| explicitly to every method which actually needs to allocate.
| This is Call Site Dependency Injection, and it is more
| flexible.'_
|
| I'd once considered the idea of having "space" as a type. Space
| is an array of bytes, and it cannot be read or written.
| Constructors take in "space" and turn it into an object.
| Constructors have the privilege of casting "space" to something
| else. Destructors take an object and turn it back into "space".
| Destructors can cast their object to "space", and this destroys
| the data. This separates construction, which is a typed thing,
| from allocation. It can be used with malloc/free type
| allocation, garbage collection, or fixed allocation. You'd
| probably encapsulate this with a generic depending on what type
| of allocation you are using.
|
| C++ probably would have been cleaner if it took that route, but
| C++ added both generics and allocators as afterthoughts.
| gpderetta wrote:
| This is exactly how C++ work. union {
| MyObject space; }; // just a bunch of bytes MyObject *
| myObject = new(&space) MyObject(); // invoke the constructor
| myObject->~MyObject(); // invoke the destructor
|
| If you want RAII use some wrapper like Optional.
| spacechild1 wrote:
| > This separates construction, which is a typed thing, from
| allocation.
|
| But this is what C++ actually does! C++ ctors run _after_
| memory has been allocated (on the stack, on the heap, from a
| pool, etc.) Or maybe you mean something different?
| Animats wrote:
| The lifetime of the space can be different, but must
| enclose, the objects created in that space. C++ doesn't
| track lifetimes.
|
| Such a separation is only useful in specific situations,
| such as the one the original article mentions. It could be
| useful in avionics or industrial control, where you often
| avoid memory pools and have arrays of specific kinds of
| objects instead.
| crop_rotation wrote:
| I actually did find the allocation control very interesting
| and useful. It seemed like something that can be so useful in
| the context of request/response servers. Use an allocator per
| request and reset it at the end.
|
| However, it alone does not compensate for all the other
| missing niceties. e.g. Just dealing with strings is not
| straightforward compared to Rust/C++.
| rrishi wrote:
| Super interesting idea.
| ok_dad wrote:
| Goddamn, this is a great way to consider this problem! I
| dabble in a lot of languages, Zig included, and I never had a
| good way to consider the allocation model that fit in my head
| in a reasonable way. See, I like to think of software as a
| transformation process that happens to physical objects that
| I actually visualize, and so thinking of an allocator as a
| "space" that can be transformed is super useful to me. I also
| love very-strictly-typed programming. I enjoy making
| everything a type, so thinking about a "space" type is
| something I can use in the future.
| kristoff_it wrote:
| This is a good comment that I hope can help other readers
| manage their expectations.
|
| Zig is verbose and low-level and, to like it, you have to
| appreciate simplicity and what it means to have control over
| tiny details. If you don't like either thing, then Zig will not
| bring anything particularly interesting to the table for you.
| handwarmers wrote:
| Yes to the appreciating simplicity bit, but if you go to Rust
| expecting to not sweat over having to control tiny details
| you are in for a ride.
| satvikpendem wrote:
| To be honest I just clone and unwrap everywhere when
| writing the first iteration. If I care more, then I'll
| refactor to remove unnecessary clones. I really haven't
| felt the pain of the borrow checker like some people say.
| titzer wrote:
| I think you might actually like Virgil more. It's actually
| memory safe and has nice enums. It has no way near the adoption
| of Zig, nor the standard library or batteries included. But it
| is my fullest expression of what I think a systems programming
| language should be.
| fpoling wrote:
| I second that. Several ideas of Virgil like unification of an
| argument list and tuples or handling of objects are very
| nice.
| fpoling wrote:
| Rust without std lib can control all details of allocations and
| you still get safe sum types, automatic free etc.
|
| The real problem with Rust is hostile syntax for unsafe code
| that one often needs when doing low-level programming.
| MrBuddyCasino wrote:
| > I think unless you have some precise needs about memory
| allocation, and want to control exactly where when and how
| memory is allocated, it is hard to argue in favour of Zig.
|
| I do have a hard time to think of use cases other than embedded
| microcontroller work where that matters nowadays. That said, I
| suspect that while they could have written TigerBeetle in Rust
| (no_std does not assume the existence of an allocator), it
| would have been more difficult.
| snek_case wrote:
| JIT compilers, games, database server. Anything where you
| need high performance and do a lot of allocations.
| kaba0 wrote:
| JIT compilers don't actually need that low-level
| programming, and compilers in general use memory in a very
| haphazard way so they are likely better off with a GC.
|
| In fact, you probably loose way more by not being able to
| write as many/great optimizations in a low-level language
| than what you lose on a slight overhead -- e.g. Java's
| Graal JIT compiler is nowadays performing better (written
| in Java itself) than the "original" C2 compiler which is
| written in C++. But this is mostly a maintainability
| question.
| cmrdporcupine wrote:
| Indeed, having played with doing compiler / parser /
| transformation type work (for relational query
| transformation, etc) in Rust, and got stuck in a maze of
| borrow-checker disasters around the tree of references...
| what I'd say is: this kind of thing is actually better
| done in a higher level statically typed _garbage
| collected language._ For myself, I 'd use a mature
| functional something like OCaml/StandardML or a Lisp or
| similar. It's just easier to not have to worry about
| borrow checking references and allocation issues when
| writing stuff like that.
|
| The case against garbage collection is where latency is
| key. P95, P99 latency _always_ suffers under any kind of
| garbage collector, no matter how advanced. You can
| minimize pauses, you can move them around, you can play
| with different collector aspects, but in the end...
| compare to explicit allocation /destruction/lifetime
| mgmt, it's going to suffer.
|
| I don't think compilers generally have these latency
| concerns. Throughput matters, but not the odd
| unpredictable pause.
|
| There's only so many application domains where that is
| super important: Certain kinds of high traffic servers,
| database _engines_ [not so much query parsing &
| planning, but execution, data structures, buffer mgmt,
| networking], operating systems, and games. Also embedded
| systems where a tight memory profile is important.
|
| I like Rust (and Zig) but sometimes when people have a
| good hammer, they go looking for nails where there aren't
| any...
|
| (All that said, I feel like some tree/DAG-heavy problems
| in garbage collected languages could benefit from static
| (and runtime) reference analysis tools that look a lot
| like Rust's borrow checker, purely for code
| sanitation/tracing.
|
| Also, GC tracing and some of the programming patterns GC
| encourages can cause havoc on L1 caches reducing
| throughput as well as a side-effect, so there's that)
| titzer wrote:
| I second that; there is nothing inherent about a JIT that
| requires low-level memory tricks, except that last step
| of making the machine code executable and callable. I'm
| not sure that Rust is a good fit for optimizing
| compilers, either. E.g. most compiler IRs are
| fundamentally graph-based and use unrestricted cycles.
| TurboFan in V8 uses arena-style allocation, as do most of
| the JITs in other JSVMs, mostly because managing every
| single node is overkill. A GC with a big enough young gen
| will do well for the kinds of allocation patterns of a
| JIT.
| AnIdiotOnTheNet wrote:
| > I do have a hard time to think of use cases other than
| embedded microcontroller work where that matters nowadays.
|
| People keep saying things like this and software keeps
| getting more bloated and shittier. It is difficult to believe
| there isn't a correlation.
| mr_00ff00 wrote:
| I might be misreading this comment, but the answer to
| bloated software is not writing all of it in rust/C++/zig.
|
| The reasons for bloat is not garage collection.
| AnIdiotOnTheNet wrote:
| It is not about the minutiae of language choices no, it's
| about a pervasive programmer mindset of not wanting to
| think about resources like memory of clock cycles or
| bandwidth as things that actually matter.
| titzer wrote:
| A lot of it is that APIs, particularly for GC'd
| languages, often require lots of intermediate garbage and
| defensive copies. It wasn't until Java 17 that there was
| a standard way of parsing integers that didn't allocate.
| I blame libraries more than languages, TBH.
| kaba0 wrote:
| Sure, I am just confirming that mindset, but can you
| really reason about the performance impact of that
| allocation? Even if it does end up allocating due to
| escape analysis not being sufficient, it will do a thread
| local pointer bump allocation on a hot, in-cache arena
| basically, and will just be zero-cost cleared once the
| still achievable objects are moved.
|
| My point is, knowing when to think/not think about
| allocating and its relevant costs is the proper way to
| program in a high level language. Only care about it when
| you are at a part that runs in a hot loop or very often,
| etc. Pretty much as per the second part of the often
| partially quoted "premature optimization...".
| wyldfire wrote:
| I think as hardware and software have matured, more and
| more people have access to develop software. They get
| correct results without having to dictate every little
| item. I think it's great, personally. I don't know if it's
| necessarily "bloat" because it's probably a net win that we
| wouldn't get some of this software otherwise.
|
| The really awesome news is that for those of us who still
| develop software whose requirements mandate this kind of
| control - better tools like Zig (and Rust) are making
| things easier but without requiring things like a GC.
| cmrdporcupine wrote:
| The issue is not always garbage collection. The issue is,
| as others have pointed out, not having to think about it
| (memory & cycles.) But this also ties very much into
| another thing about many modern applications: excessive
| reliance on third-party packages, many of which are written
| with (or without) constraints and features that aren't
| always a match for the core application. It's very easy to
| blow out your memory use and runtime costs this way.
|
| And in this respect Rust could be vulnerable, because
| Cargo.toml makes it way-easy to pull in a huge tree of
| transitive third party dependencies without even thinking
| about it.
| cmrdporcupine wrote:
| Re: TigerBeetle... caveat with I haven't looked at the
| TigerBeetle internals&source code, but. Some thoughts...
|
| The kind of page buffer allocation done inside databases is
| kind of a different nature than the kind where you, e.g.
| override the default allocator in STL collections, or pass a
| different allocator into your standard collections library in
| Zig.
|
| It's generally such that only specific data structures --
| usually BTrees or HashTables meant to store
| relations/tables/indexes -- are managed this way. And so
| they're usually built from scratch around an explicit
| specific page buffer mgmt system. In some systems (like Umbra
| or LeanStore) this might be somewhat murkier in that it might
| use pointer swizzling etc behind the scenes, but it's still
| usually the case that the data structures used for relation
| storage are tied directly to the DB's own page buffer
| implementation anyways.
|
| Now, other parts of the application stack may benefit from
| having a custom allocator in the same way as any performance
| critical system might, but that's of a different nature.
|
| (That said, Rust is also not easily suited to the kind of
| "pointer-swizzling" behind the scenes bait-and-switch with
| memory that e.g. LeanStore does with C++. I've tried, and,
| while it's possible, the language in general gets in the way
| and you're `unsafe` all over the place anyways.)
|
| Anyways, all this to say, TLDR given that all serious
| databases do explicit memory / buffer pool mgmt ... and build
| data structures specific to them, I don't see any intrinsic
| advantage to Zig for this purpose really? Other than it's a
| decently modern systems programming language that mostly
| stays out of your way.
|
| But... I _can_ see major advantages to using Rust: more
| developers, bigger community, larger ecosystem, safer for
| memory mgmt elsewhere in the stack, safer for concurrency,
| etc.
| spacechild1 wrote:
| > I do have a hard time to think of use cases other than
| embedded microcontroller work where that matters nowadays.
|
| Another example: realtime audio applications. There are
| rather strict rules about what you can and cannot do in the
| audio callback. In particular, you must not use the system
| memory allocator (because it may block). Instead you have to
| pre-allocate memory or use real-time safe memory pools. For
| this reason, the vast majority of (realtime) audio code is
| still written in C and C++.
| skribanto wrote:
| try = ? in rust. catch = match in rust. Zig does have its own
| general match statement, and the reason it needs a catch is
| because errors in Zig aren't actually ADT's, but it's not that
| much more complex.
|
| And you're really going to argue that defer,errdefer is more
| complex than RAII?
| lenkite wrote:
| "Rust enums make defining errors so simple with arbitrary
| payload."
|
| enum variants are overused in Rust and are _highly_ expensive
| in memory IMHO. One tends to run into problems like:
| https://github.com/serde-rs/json/issues/635 in Rust projects
| when used at scale. Value is an enum variant:
| https://docs.rs/serde_json/latest/serde_json/value/enum.Valu...
|
| Comment from that issue: "For example, ElasticSearch returns a
| 8,683KB document, I deser it into Value and the next RAM
| reading gives me delta of 98,484KB of RAM use. That's more than
| 10x the original size."
|
| Compare that with a similar issue in simdjson (written in C++),
| where people are complaining about parsing 4GB documents into a
| tree !!! https://github.com/simdjson/simdjson/issues/128.
| serde-json has trouble moving a bullock-cart while simdjson is
| moving a container ship.
|
| I don't like some parts of Zig - I think not having RAII in the
| language is a terrible mistake. But I do love that anything and
| everything that can be allocated needs to be passed an
| allocator. I do think they could have introduced an allocation
| context for RAII cleanups though instead of forcing the
| programmer to manually coding defer base cleanups - this is a
| major source of errors even for advanced programmers.
| Ygg2 wrote:
| I don't think serde-json has a limit on size. But under some
| usages it will allocate extra. For example see:
| https://github.com/serde-
| rs/json/issues/160#issuecomment-841... 2.4 GB file can be
| read and parsed with serde.
| flohofwoe wrote:
| > ...and want to control exactly where when and how memory is
| allocated...
|
| Isn't this the whole point and the reason why manual memory
| management is still a thing - and actually getting more
| important with the ever widening CPU/memory latency gap?
|
| There simply _is_ no silver bullet for memory management, you
| can either have high performance or automatic memory
| management, but not both.
|
| (vastly simplified of course - but in languages with automatic
| memory management - no matter if garbage collection or
| refcounting - you need to spend so much effort to reduce memory
| management overhead that it is usually less work to do it all
| manually in the first place)
| Dwedit wrote:
| Reference Counting (including a secondary counter for
| internal cycles) is your silver bullet.
|
| The only hairy issue then becomes multiple processors needing
| to update the reference counter, where the count has to go in
| an out of the various processor's cache. One possible way to
| resolve that is to have a per-thread reference count, and
| only change the globally shared reference count when a per-
| thread's reference count would reach 0.
| kaba0 wrote:
| > There simply is no silver bullet for memory management, you
| can either have high performance or automatic memory
| management
|
| That's only true for workloads where you can optimize the
| memory layout/allocations. This may not be true in general,
| where you will end up implementing a shitty GC that will
| definitely perform worse than a properly written one.
|
| Also, the cost of a proper GC is heavily overblown in my
| opinion. Especially when value types are available.
| fpoling wrote:
| GC is not a solved problem and can be costly. We clearly
| see in a production server written in Go spikes in latency
| and memory usage. So most likely for the next server-type
| application we will use Rust.
|
| Then there are benchmarks where Nginx is faster than Caddy
| by factor of 3.
| kaba0 wrote:
| Go doesn't really have a good GC for what it's worth. And
| of course there will always be domains where the
| tradeoffs of a GC doesn't worth it, but those are very
| very rare.
| fpoling wrote:
| The problem with GC is that when it does give problems,
| there are no good choices. One either spends time trying
| to tune available knobs to hide the problem or rewrite
| application to try to reuse objects etc. turning the
| initial nice architecture into spaghetti mess.
|
| I very much prefer for this reason reference counting.
| Yes, time can be wasted fighting leaks through cycles,
| one still have avalanches of releases problems, the
| performance can be bad with certain usage patterns. But
| solving these problems is at least local and does not
| required rewriting the whole application.
| Patrickmi wrote:
| [dead]
| za3faran wrote:
| What kind of workload does the server run?
| fpoling wrote:
| It serves as a proxy or manager for other components. It
| is IO bound. As such Go should be an ideal language for
| it. But GC kicking in a wrong moment still brings
| troubles.
| Patrickmi wrote:
| So Go GC just need a api that pauses GC when it wants to
| run
| munificent wrote:
| _> you need to spend so much effort to reduce memory
| management overhead that it is usually less work to do it all
| manually in the first place_
|
| That has not been the case in the vast majority of
| applications I've written across a number of domains using
| garbage collected languages.
|
| Yes, there is runtime overhead to GC. But for many many
| programs, the cost of the overhead is acceptable and you can
| spend all of your time worrying about the application domain
| and not worrying about allocation.
| lenkite wrote:
| "and you can spend all of your time worrying about the
| application domain and not worrying about allocation."
|
| This has never been my experience in 10+ years of
| middleware development in GC languages in large teams. The
| problem is just deferred to production where you need to
| analyze heap dumps and run a profiler to hunt down
| excessive allocation issues and why the GC is running all
| the time.
|
| Sometimes, troubleshooting and correcting many of these
| issues take multiple more man hours than coding the service
| in the first place! The usual solution of "throw more
| hardware at it" only works until mgmt starts complaining
| about costs and uptime.
|
| I have spent more time debugging memory issues in Java/C#
| projects than in my first large scale project in C++ where
| the lead architect strictly mandated the use of a custom
| allocator for everything.
| munificent wrote:
| I'm not sure why you trimmed the beginning of my
| sentence.
|
| The parent comment says: "(vastly simplified of course -
| but in languages with automatic memory management - no
| matter if garbage collection or refcounting - you need to
| spend so much effort to reduce memory management overhead
| that it is usually less work to do it all manually in the
| first place)"
|
| That suggests they are claiming that _all_ users of GC
| languages will eventually spend more effort dealing with
| memory than if they 'd skipped a GC in the first place.
|
| I am making an existence proof counterargument: I have
| worked on many many programs in GC languages where at no
| point in the program's lifecycle did I need to spend much
| time worrying about memory.
|
| I believe the claim "all programmers will spend more time
| dealing with memory in GC languages" is false.
|
| I have absolutely not made any claim that " _no_
| programmer will spend more time dealing with memory in GC
| languages ". There are certainly programs that are better
| written with manual memory management. I've written
| plenty.
|
| My point was only that there are also plenty of programs
| where that's not true.
| 59nadir wrote:
| Not allowing you to talk about allocation in any great
| detail certainly on the surface seems to simplify things,
| but as with most things of that nature it tends to
| complicate things in edge cases (or just entire parts of
| industry). What the GP is alluding to, it seems to me, is
| that in those cases the effort to remedy the problem tends
| to become a constant hunt and guessing game of "Where are
| we accidentally allocating and ruining everything?".
|
| Inevitably some kind of object pooling comes into play in
| most of these cases and this is arguably a much worse
| solution to the basic problem. If you know you're going to
| be landing in this space I don't think there's much purpose
| to pretending you're better off using a GC that you'll be
| trying to avoid anyway. It's far easier to sketch out your
| allocation strategies and do things deliberately.
|
| Fast software allocates and deallocates in bulk, so the
| straw man of individual `malloc` and `free` isn't exactly
| relevant. Arenas, bump allocators, etc. are what is
| actually being discussed as an alternative.
|
| (As a side note I think this makes RAII a somewhat peculiar
| solution to the issue as well. RAII implies objects
| themselves controlling allocation and deallocation and this
| is just not very useful at all if you want to make
| something that behaves properly.)
| kaba0 wrote:
| > Where are we accidentally allocating and ruining
| everything
|
| This is trivial to profile under any platform that has
| remotely sane tooling, and usually it is trivial to fix
| as well.
|
| Object pooling is a very last resort thing to do, I
| really can't think of any project I have worked on where
| there wasn't another solution to performance problems.
| bitwize wrote:
| > There simply is no silver bullet for memory management, you
| can either have high performance or automatic memory
| management, but not both.
|
| RAII is the way.
| [deleted]
| flohofwoe wrote:
| RAII for memory management implies that destructors free
| owned memory, which can quickly cascade out of control for
| complex objects (e.g. you _still_ need to think very
| carefully about memory management).
| gpderetta wrote:
| You are right in the sense that for high performance
| applications you still need to explicitly take into
| consideration memory allocations, allocators,
| indirection, into consideration. RAII helps you implement
| your preferred design, but it doesn't make you ignore the
| details.
| connicpu wrote:
| There's the third option, which is what Rust and C++ do by
| default, where types have destructors that are run when the
| value goes out of scope, but also have mechanisms to be
| activated manually at a precise moment if you know what
| you're doing and have specific needs.
| haberman wrote:
| RAII is not a silver bullet. RAII wants to have neat
| recursive ownership and cleanup of everything, which is
| undoubtedly a nice model, but sometimes in low-level code
| you have to choose between nice recursive ownership and
| performance.
|
| For example, Protocol Buffers are trees of objects.
| Originally they were simple and had recursively-owned,
| heap-allocated nodes. But it turns out that traversing and
| deleting a big graph of heap-allocated objects is
| expensive, and arenas are more efficient. But arenas make
| you give up recursive ownership.
| gpderetta wrote:
| There is no incompatibility between RAII and arenas. RAII
| doesn't require heap allocation.
| kristoff_it wrote:
| That's not really the point. If you're using an arena it
| means that you plan to reset it at some point and erase
| in bulk everything that was stored on it all at once.
| This is the opposite of letting the destructor of every
| object run.
| connicpu wrote:
| Not every object in an RAII language needs a destructor,
| e.g. objects that don't manage their own memory because
| they came from an arena
| connicpu wrote:
| Which is why low level languages like C++ and Rust make
| RAII the default in their standard library (easy,
| simple), but it's still completely possible to manage the
| memory on your own if that's necessary for the task at
| hand. Having easy defaults with the capacity to do
| everything by hand if you need to is the most flexible
| system.
| mcguire wrote:
| The last time I looked (which has been a while, I admit),
| _that_ meant that you had a very hard time using any of
| the standard library types with an arena or whatever form
| of management you used for your specialized code.
|
| What does that look like now?
| tialaramex wrote:
| If you're willing to write Nightly Rust, you can use the
| allocator_api feature to have the types which allocate
| take an allocator parameter so e.g.
|
| Vec::with_capacity_in(10, arena_allocator)
|
| ... obviously user-defined types don't know these
| allocators exist and so may not provide a way to pick
| which allocator is used, whereas in Zig this is "always"
| how it worked.
|
| For stable Rust, until/ unless allocator_api is
| stabilized, you will need to replace the global allocator
| for your code with one that has the desired behaviour.
| That applies to everything using an allocator, but on the
| other hand you lose considerable flexibility.
| kaba0 wrote:
| This is by definition manual memory management.
| connicpu wrote:
| I would argue RAII is still a type of automatic memory
| management, but it has the determinism and ability to
| reason about what's going on the same way fully manual
| management does.
| kaba0 wrote:
| From the Garbage Collector handbook I got a very great
| quote about what automatic memory management really is. I
| will butcher it up, but the basic essence is that
| automatic memory management is above all a software
| design tool -- well designed programs are built from
| components that are highly cohesive but loosely coupled.
| What it means for memory management is that a component
| shouldn't have to care about how other modules handle
| memory for correct working. This is possible with a GC,
| but isn't with manual memory management, and RAII doesn't
| change it -- function signatures leak memory management
| concerns in both Rust and C++.
|
| Ongoing refactoring and maintenance costs are also higher
| in low-level languages due to this reason.
| gavinhoward wrote:
| In addition to the semantics, part of which I tried to understand
| and failed [1], Zig also has a problem with compiler bugs.
|
| In that same post, my very first example ran into a compiler bug.
| This is not reassuring.
|
| (Though to be fair, I've run into more compiler bugs than most
| do: one in GCC, one in Clang. Maybe I'm just unlucky.)
|
| That, combined with the fact that the bug was still not fixed
| last I checked, Zig's security bug policy is to consider them
| non-security bugs until 1.0, and it is _still_ not 1.0 makes me
| wonder why anyone would choose it for a major project to run in
| production. That was TigerBeetle 's first and biggest mistake.
|
| [1]: https://gavinhoward.com/2022/04/i-believe-zig-has-
| function-c...
| henry_viii wrote:
| I think we should take into consideration AI assistants like
| ChatGPT when discussing Zig vs. Rust. Differences between Zig and
| Rust:
|
| 1) Zig is memory-unsafe and thread-unsafe whereas Rust isn't.
|
| 2) Zig is easier to learn whereas Rust isn't.
|
| 3) Zig isn't stable yet whereas Rust is.
|
| ChatGPT can help with Rust:
|
| https://news.ycombinator.com/item?id=33872369
|
| However ChatGPT can't help with Zig since Zig hasn't stabilized
| yet. Features like for-loops (introduced in 2022) aren't familiar
| to ChatGPT since ChatGPT's cut-off date is 2021.
| avgcorrection wrote:
| tl;dr: author finally gradudated to becoming a lone genius
| hacker.
| netbioserror wrote:
| Still not convinced that memory semantics are critical in the
| vast majority of domains. Incredibly fast speeds can be achieved
| with simple GC and RC for short-running programs, and programs
| with sustained runtimes can rely on generational GC. These
| methods have the advantage of nearly eliminating the need for
| memory semantics, leaving only business logic behind.
|
| The best example might be Nim, which drastically reduces GC
| pressure over Java or Go by stack allocating and passing
| immutably by value wherever it can. No gigantic runtime to link
| against! I've been able to make fast, safe programs so quickly
| with Nim that it promptly ended my Rust fascination phase.
| Kernels, realtime software on rockets, and Facebook- or Discord-
| scale backends seem like good fits for Rust, but I'm not
| convinced it should be used almost anywhere else. Looking at the
| sheer volume of memory logic in Zig and Rust, I have to ask: "Why
| do we continue doing this to ourselves?"
| [deleted]
| [deleted]
| DeathArrow wrote:
| The good thing about Nim is that you can chose between several
| garbage collection algorithms, use no garbage collector at all
| and do manual memory management or allocate without freeing if
| the program is short lived and doesn't use much memory.
|
| Also having a C interface is great since you can use any C
| library.
| Yoric wrote:
| Frankly, my reason for using Rust is not memory semantics (I'd
| be happy for most applications with a Gc), it's the type
| system.
|
| I could be writing in Haskell for an even more powerful type
| system, of course, (especially now that Haskell has gained
| linear types) but the language never took hold outside of
| academia.
| ben0x539 wrote:
| I know this is facile, and it's speaking as someone with a
| lot more enthusiasm about than expertise with Haskell, but
| whenever I write some toy Haskell code and have to think
| about "remember to close this file handle before the end of
| this block" or "make sure not to use this file handle outside
| this block (because we just used a combinator to close it)",
| I'm baffled that Rust has mostly figured out that whole class
| of problem before Haskell
| kaba0 wrote:
| Well, "never took hold" is relatively. It is and will likely
| always be a niche language, but one with a quite big audience
| and ecosystem. There are people happily using different
| languages that are much smaller, they just happen to occupy a
| less academic niche -- e.g. I'm guessing but you probably
| don't have such feelings against D, when it might very well
| be smaller than Haskell.
| Yoric wrote:
| To clarify, I have actually coded a bit in Haskell and I
| have actually released open-source code in SML/NJ, a
| commercial application in OCaml and worked (as a very minor
| contributor) on industrial code in Coq.
|
| But if I have to start a new industrial project, I will
| most likely use Rust, because it is easier to hire and
| because there is lots of momentum in the Rust ecosystem,
| which means that there are crates for just about
| everything.
| kaba0 wrote:
| > which means that there are crates for just about
| everything
|
| There is definitely momentum, but it doesn't make Rust's
| ecosystem big relative to the top 5 in any way.
| ibiza wrote:
| That's a a compelling argument: GC/RC w/ stack allocation where
| possible. I associate GC w/ pointer chasing and the unavoidable
| L1, L2, L3 cache trashing that goes w/ it.
|
| To what extent is this possible? Does Nim have LTOs that
| rewrite memory handling across compilation units? I'm guessing
| no, and instead it's local & one-off, rather than something one
| can bank on.
| netbioserror wrote:
| https://zevv.nl/nim-memory/ Local variables
| (also called automatic variables) are the default method by
| which Nim stores your variables and data. Nim will
| reserve space for your variable on the stack, and it will
| stay there as long as it is in scope. In practice, this means
| that the variable will exist as long as the function in which
| it is declared does not return. As soon as the function
| returns the stack unwinds and the variables are gone.
| In Nim, all your data is stored on the stack, unless you
| explicitly request it to go on the heap.
|
| Strings and seqs are allocated on the heap and accessed via a
| stack pointer, but the stack pointer controls their
| lifetimes, and semantically behaves like any other local
| variable.
| sramsay wrote:
| I completely agree with what you're saying here and wonder
| every day why Nim hasn't taken over the world. People seem not
| to realize that Nim not only has a "pluggable" gc system (so
| you can pick the gc that makes sense for your use case), but
| also allows you to _turn the gc off_. As in, no gc (which is
| exactly what you need in certain very narrow situations).
| [deleted]
| netbioserror wrote:
| One of these days I'll be able to try embedded Nim with no
| GC. I want to see what its arena allocation semantics are
| like.
| Decabytes wrote:
| The thing that turns me off to Nim is the issue with it
| getting picked up as malware. I can't even download the
| installer for the language without it getting removed from my
| computer after getting picked up by Windows Defender
|
| It's not Nims fault, but is still a point of friction
| klyrs wrote:
| > Still not convinced that memory semantics are critical in the
| vast majority of domains.
|
| This is okay. Zig is not targeting the vast majority of
| domains. It targets the low-level, performance-critical domain
| that C occupies. It would be a great language to write a
| compiler/interpreter for a higher-level language that has the
| bells and whistles that you want.
| netbioserror wrote:
| It's still bizarre though that Rust is capturing such
| ridiculous mindshare. I suspect it has a lot to do with web
| developers being plugged into Mozilla, and Mozilla spending
| quite a lot on Rust development and marketing. And Zig may be
| being roped into it. It seems to be a temporary low-level
| programming zeitgeist driven by YouTube and Reddit
| recommendation algorithms to an audience that has never done
| it and probably never will.
| kaba0 wrote:
| Rust is the first low-level language that actually solves a
| fundamental problem of low-level programming. I don't see
| why is it surprising that it gains weight.
|
| Zig, while I appreciate many of its design goals and
| definitely has some novel ideas, is "just" a better C.
| netbioserror wrote:
| I think your comment can actually help me clarify what I
| meant. My perception is that there is a rift between what
| domains Rust is targeting versus what audience is
| actually hyped about Rust.
|
| When I look to the C++ world and the embedded/realtime
| systems industry, what I see is lots of discussion about
| Carbon and herb Sutter's CppFront. I don't see as much
| Rust discussion.
|
| When I look to the JavaScript/webdev/fullstack world,
| that is who I see discussing Rust; these are domains
| where GC languages, even those with lots of GC churn like
| Clojure, have already proven their utility. In the
| creator sphere, the same folks talking about JS
| frameworks are the ones covering Rust and, to a lesser
| extent, Zig.
|
| As usual, the C world seems completely disinterested
| towards what is outside of it.
| kaba0 wrote:
| There is definitely a hype among programmers who are
| familiar only with higher level languages, but I think
| the actual core audience is the (ex-)C/C++ community. I
| am definitely not some integral part of the Rust
| community, so my experience there is limited, but based
| on discussions in for example their subreddit, it is
| definitely not made up of beginners who are just learning
| what a pointer is.
|
| There are beginners, but I see mostly veteran
| embedded/systems programmers with very good understanding
| of both low-level systems and the
| advantages/disadvantages of C++ for example, making up
| for very technical and interesting comments.
| wyldfire wrote:
| > It's still bizarre though that Rust is capturing such
| ridiculous mindshare.
|
| I don't think it's that bizarre. The two big headline
| features that bring Rust such popularity are: #1 "70% of
| bugs are memory-safety bugs" [1] and Rust can help solve
| those, and #2 C/C++ have a couple of package manager
| solutions - none of which have critical mass and Rust
| "comes with" cargo.
|
| Those two make me really eager to continue experimenting
| with Rust.
|
| > It seems to be a temporary low-level programming
| zeitgeist driven by YouTube and Reddit recommendation
| algorithms to an audience that has never done it and
| probably never will.
|
| This is some weird gatekeep-y kinda thing. Most of us
| didn't start out with low-level programming. Wouldn't it
| have been odd and frustrating for someone to tell your
| younger self that you have "never written C and probably
| never will"?
|
| [1] https://github.com/microsoft/MSRC-Security-Research
| netbioserror wrote:
| > This is some weird gatekeep-y kinda thing. Most of us
| didn't start out with low-level programming. Wouldn't it
| have been odd and frustrating for someone to tell your
| younger self that you have "never written C and probably
| never will"?
|
| I'm not making any sorts of demands about who should be
| able to program at a low level, but I'm being realistic
| about who will. I have an intuition that I do not think
| is unreasonable that the vast majority of the 20- to
| 30-something crowd that recently learned JavaScript in a
| boot camp would bounce off of systems programming hard,
| while a handful might discover it's what they should've
| been doing all along.
|
| The young are not who I'm thinking of at all. Someone
| with time and neuroplasticity can and should be spending
| that time toying around with C, Haskell, and Lisp to
| expand their understanding as much as possible.
| jackmott42 wrote:
| You can get the idea that a GC has minimal impact on
| performance when you just look at things like how fast the GC
| runs, or what % of time is spent in GC, but that only
| represents a portion of performance implications, there are
| lots of indirect effects:
|
| 1. More memory is used, which means more CPU cache evictions
| happen 2. There will be things the language won't let you do,
| because it is garbage collected 3. There will be extra FFI
| costs, like when making OS calls or calling into other
| languages 4. There will be cultural tendencies, if a language
| uses GC, the people who designed it and used it are less likely
| to be interested in compromising other things for extreme
| performance. Example: If a linq query has overhead in C#, and
| they have to make a breaking change to eliminate it, they will
| not. In Rust if an iterator is slower than what hand coded C
| would be, its a bug, and every effort will be made to fix it if
| possible.
|
| That said, it is still the case that most programs aren't
| penalized by GC much. But people do still work on operating
| systems, games, databases, video editing tools and such where
| getting great performance is really important.
| arc619 wrote:
| Nim uses stack allocated value types by default, and GC (or
| ptr) is an optional tag to the type definition.
|
| GC types use borrow & move analysis like rust (not as good
| yet tho) so it can elide GC work when possible. GC is also
| not stop-the-world, deterministic (assuming no cycles), and
| configurable to soft realtime performance.
|
| So you dont need to use the GC, but it will give you RAII if
| you want without needing to perform the dance of the borrow
| checker.
|
| BTW Nim is also closing in on Rust's borrow checking
| semantics, too!
| [deleted]
| arc619 wrote:
| Also, aside from the fact GC is optional in Nim, what are you
| thinking of that cant be done with a GC?
| elcritch wrote:
| > That said, it is still the case that most programs aren't
| penalized by GC much. But people do still work on operating
| systems, games, databases, video editing tools and such where
| getting great performance is really important.
|
| This statement simply isn't true though, at least in the
| general sense. Sure, for old school atomic RC and compilers
| that didn't do RC elision etc it might've been true. But we
| can and have made smarter compilers, just like Rust has
| gotten smart about life times.
|
| Like @netbioserror I use Nim, but for embedded and real-time
| stuff. There is a minimal overhead (one machine word per
| allocation), but using Nim's ARC "memory management system"
| gives me results comparable to Zig or Rust though with much
| less work. Technically ARC without the cycle collector isn't
| a GC.
|
| There's no reason D and other languages with "memory
| management" couldn't do similar RC based systems. As the
| compilers get smarter it approaches the same result as Rust's
| manual lifetime analysis. In many cases compilers can be
| _smarter_ than human programmers about memory.
|
| Even then, there's occasions where in Nim one can and will
| reach for manual memory allocations. It's easy to do when
| wanted.
|
| > 2. There will be things the language won't let you do,
| because it is garbage collected
|
| There will be things that systems like Rust's lifetimes makes
| harder / less performant as well:
| https://ceronman.com/2021/07/22/my-experience-crafting-an-
| in...
|
| > 3. There will be extra FFI costs, like when making OS calls
| or calling into other languages
|
| For generational GC's this is true, but for RC systems not as
| much.
|
| > There will be cultural tendencies, if a language uses GC,
| the people who designed it and used it are less likely to be
| interested in compromising other things for extreme
| performance.
|
| This is certainly a thing. However, cultures can vary a lot.
| For example Nim provides zero-cost iterators as well as
| minimal-cost "closure" iterators. Now Nim's string libraries
| do a lot of copies by default which makes it easy to ruin
| performance. However, there's an open RFC to provide CoW
| strings to reduce this overhead. There's also the new `lent`
| type too. After all, it's used in games and embedded so
| there's desire for that.
|
| Certainly if your language is tedious about memory
| management, you'll spend more time on it. Though as an end
| user I'm not sure I've noticed a practical difference between
| Go and Rust programs as compared to C#/Java applications. The
| latter I avoid running if possible because of their general
| bloat.
| kaba0 wrote:
| > More memory is used, which means more CPU cache evictions
| happen
|
| The first part is true, and the second part is sort of true,
| but it may or may not matter. The order of magnitude speedups
| that good cache usage can cause only happens when you are
| having a small hot loop working over a huge amount of data
| that has an easy to guess access pattern (e.g. serial). I am
| not convinced that your ordinary program would have too many
| such loops and thus that it would have a huge speed up were
| it rewritten in C from a managed language.
|
| > There will be things the language won't let you do, because
| it is garbage collected
|
| There are always escape hatches
|
| > There will be extra FFI costs, like when making OS calls or
| calling into other languages
|
| Do you mean like GC barriers and such?
|
| But we do agree on your last paragraph, and sure low-level
| languages will always be needed. But the niche where they are
| irreplaceable are very small, if we are pedantic OS and games
| are also not necessarily to be written in them (see
| Microsoft's singularity, the latter has plenty of examples)
| TylerE wrote:
| Malloc isn't free, either.
| 59nadir wrote:
| `malloc` doesn't make up a meaningful percentage of
| performance-oriented software's execution time. Most of
| those programs bulk allocate and manage memory internally,
| so the cost of `malloc` isn't a relevant argument against
| managing memory manually. Indeed it's entirely possible to
| write a program that doesn't ever use `malloc` while still
| using allocations internally, from a stack allocator.
|
| The point isn't to `malloc` every single allocation and
| pair them up with `free` calls; it's to use allocators that
| alleviate that burden while also allowing you to pick an
| allocation pattern that makes sense for the use case (and
| internal use cases).
|
| As an example, if your total memory usage for your program
| could be determined at startup to be 1GB, then you could
| allocate 1GB up front and allocate from that memory in the
| rest of the program, guaranteeing that nothing after
| startup ever goes to the OS for memory.
|
| Overall it's much easier to write obviously efficient
| software in Zig than it is in Rust, IMO, and it's much
| easier to see at a glance that something won't behave
| stupidly when it comes to allocation and deallocation. To
| be fair, this is something Zig has over most other
| languages as well, so it's not exactly specific to Rust.
| lr1970 wrote:
| From the linked article
|
| > When we call malloc, we just hope that we have enough stack
| space for it, we almost never check.
|
| malloc allocates on heap, not stack.
| steveklabnik wrote:
| This comment from the author elaborates on what he meant here:
| https://old.reddit.com/r/Zig/comments/123jpia/blog_post_zig_...
| pron wrote:
| > we don't have a reliability-oriented high-level programming
| language with a good quality of implementation (modern ML, if you
| will)
|
| Java is fairly popular, I hear.
| c-cube wrote:
| Calling Java a modern ML is a bit of a stretch :-). It's
| getting sum types, I hear, but it still has null, and it's not
| really the feeling of a nice expression oriented Hindley-Milner
| language. If anything scala 3 might be a closer candidate.
| kaba0 wrote:
| It already has sum types. Pattern matching on them is not yet
| finalized, but the ADTs itself is.
| childintime wrote:
| Zig appeals to the "lone genius hackers". I'd read this as the
| folks that like to know all the code in their code base, as is
| typical for embedded or moderate size projects. Folks that do not
| need (and resent) the abstractions made for every use case under
| the sun, which to them only ends up making the code harder to
| read and to comprehend.
|
| Though Rust does an admirable job, and things are much better
| than for OOP languages, it's still a behemoth. Take a (any) small
| project, and the amount of dependencies upon dependencies
| explodes. A project easily takes up 1GB on disk, and it is
| impossible to know exactly what has been pulled in, or why. How
| much of this code actually ends up in the binary? It feels like a
| small fraction, like 5% (or even 1%), but that 95% is there and
| causes breakage. Now you have to debug something that's literally
| out of your world. It's not Rust, its the build. No matter how
| small the actual issue is, you are _not_ qualified to find it.
|
| Note that Zig's build system provides the exact opposite
| experience. Errors are always relevant, and can (therefore)
| always be solved.
|
| In summary Rust takes away the helicopter view. Yes, in return it
| provides an unparalleled level of assurances, it really is magic.
| But I find myself returning to the roots, and Zig feels tasty. I
| bet Chatgpt will then handily convert the project, when done, to
| Rust, faster than I ever could.
| kaba0 wrote:
| > Chatgpt will then handily convert the project [..] to Rust
|
| That's more or less impossible if you mean idiomatic Rust
| without chock-full of unsafe blocks. Besides the (probably
| ironic?) overhype of ChatGPT, Rust's lifetime-memory patterns
| are a strict subset of what is expressible with correct Zig/C.
| nindalf wrote:
| You don't need to pull in dependencies if you don't want to.
|
| But if you do, the contracts on ownership enforced by the
| compiler allows the software to compose better.
| childintime wrote:
| You're a Rust zealot? The point still stands: for lots of
| projects 95% of the code pulled in is not actually used, but
| is still cause for breakage. Of the worst kind, because it
| has nothing to do with the problem being solved. Sorry, but
| the build system just gave up, for no good reason at all.
|
| Only total perfection is acceptable to Rust, and that is also
| it's Achilles heel, well exemplified by this case. Now Rust
| could change and be more flexible, and I would have great
| faith in its leadership to find a way, if not for people like
| you, who charge ahead on a straw man and ex-communicate.
| avgcorrection wrote:
| # First rule of zealotry
|
| Whoever is first to throw out the zealot accusation is
| himself/herself the zealot.
| nindalf wrote:
| Really weird that my innocuous comment would prompt such
| a visceral response. Not cool.
| meindnoch wrote:
| Happy to see the tide turning from Rust towards Zig. I think 2023
| is going to be a pivotal year in this space!
| Klonoar wrote:
| Not entirely sure how you got that impression from the article.
| gabereiser wrote:
| I'm learning zig myself after several years of doing rust and
| golang (I still use golang a lot).
|
| I particularly like the quote >"Because even if you and I both
| know how to write memory safe C, it's very hard for us to have an
| interface boundary where we can agree about who does what."
|
| This is still a huge issue in many domains, in many languages. Do
| you throw the contract out the window on responsibility because
| you lean on your GC? Or do you make it explicit on who owns what
| when you don't have a GC. If I allocate a struct as part of my
| ABI to give to you, the application developer, am I clear on
| who's responsible for freeing the struct? Do I provide a function
| for that or do I call it out as gospel for using the library? I
| wish we didn't have to have these fights.
| anonyfox wrote:
| May someone chime in between that and make a quick 3-way
| comparison with Golang?
|
| I already know Rust and shipped nontrivial stuff, but I need
| something simpler that average developers can pickup quickly to
| produce performant+parallel code and be able to crosscompile+ship
| a single binary.
|
| (The last point already ruled out Crystal which has a poor
| crosscompilation story as well as insanely long compile times for
| nontrivial stuff = bad DX)
| eatonphil wrote:
| It takes a while to understand allocations in Go. There are
| obvious ones like `make()` and `new()` and `append()` (though
| this one doesn't always allocate depending on the capacity of
| the thing you pass to append, I think). There are less obvious
| ones (if you don't have experience thinking about it) like
| string appending and "casting" between `string` and `[]byte`. I
| think it's also tricky to figure out when escape analysis goes
| wrong and you're accidentally heap allocating things you didn't
| need to.
|
| You develop an awareness of these aspects if you do
| performance-sensitive code in Go. But in Zig all allocations
| are explicit so you can't really accidentally have allocations.
|
| On the other hand, you have to manually manage memory in Zig.
| Unlike Rust, Zig has no builtin atomic reference counting. So
| memory management in Rust and Go are "easier" if you don't want
| to be aware of memory allocations. Memory management in Zig is
| "easier" if you need to be aware of memory allocations.
|
| And neither Zig nor Go are as strict as Rust about ownership so
| it's "easier" to express internally-mutable datastructures in
| Zig or Go (see "Entirely Way Too Many Linked Lists" [0]).
| Whereas it's easier to be sure you haven't screwed up ownership
| in Rust compared to Zig. In Go you don't have to worry since
| the GC will not let ownership be a problem.
|
| [0] https://rust-unofficial.github.io/too-many-lists/
| kaba0 wrote:
| Go is absolutely nothing like Rust, Zig, C; it is arguably
| closer to JS than those. I really dislike how it is camouflaged
| as a low-level language.
| pizza234 wrote:
| The main topic of the article is about resource management (ie.
| allocation), which is automatic in Golang, so a comparison
| wouldn't make much sense in this context.
|
| Additionally, a requirement of the project is:
|
| > On the engineering side of things, we are building a
| reliable, predictable system. And predictable means really
| predictable. Rather than reigning in sources of non-
| determinism, we build the whole system from the ground up from
| a set of fully deterministic, hand crafted components.
|
| which rules out garbage collected languages (also see the
| design document here: https://github.com/tigerbeetledb/tigerbee
| tle/blob/fe09404d46...).
| MrBuddyCasino wrote:
| > Collections are not parametrized by an allocator, like in C++
| or (future) Rust.
|
| What does he mean by this?
| Georgelemental wrote:
| My understanding is, instead of the allocator being a generic
| parameter of the type, it's a value you pass to the
| constructor.
| tialaramex wrote:
| The crucial trick is that it's _not_ just the constructor, it
| 's everywhere which might allocate.
|
| Rust's proposed allocator API (what the article calls future
| Rust) takes an allocator for constructors, but the effect is
| the type parameter is just inferred during construction, the
| same way if you say OK, make me a Vec of this array of
| Strings, Rust infers the Vec's type Vec<String>.
|
| Zig's standard library provides both conventional compound
| structures like those I described for Rust, and "Unmanaged"
| variants in which you must provide an allocator every time
| you do anything which might allocate, so e.g. addOne on
| ArrayListUnmanaged requires the allocator, which it will only
| actually use if adding a single element to the ArrayList
| exceeded its current capacity. It will assume this is the
| correct allocator to de-allocate the old backing storage
| _and_ allocate new storage, so you can 't use this design to
| move from one allocator to another.
|
| Interestingly Zig's ensureTotalCapacity not only avoids the
| problem of C++ reserve where it destroys the amortized growth
| behaviour, but it actually insists on exponential growth even
| if that considerably outstrips the growth requested.
|
| Say we've got 15 Foozles in an ArrayList with capacity 16 (or
| Rust's Vec or C++ std::vector). We know we want to put 20
| more foozles in, for a total of 35, although maybe more.
|
| Rust's Vec says OK, reserve(20), we were thinking of next
| growing from 16 to 32, but 35 won't fit in 32, so 35 it is.
| Capacity becomes 35.
|
| Popular C++ std::vector implementations likewise will pick 35
| here. But Zig's ArrayList says 16 + 8 + 8 = 32 not big
| enough, try 32 + 16 + 8 = 56. Capacity becomes 56!
| steveklabnik wrote:
| Psuedo-Rust code here, showing off both styles.
|
| Parameterized by an allocator: struct Foo<T, A:
| Allocator> { // ... } impl<T, A>
| Foo<T, A> { fn new() -> Foo<T, A> { //
| do something to make a new foo, calling functions via A
| } }
|
| contrast with "an allocator is passed in explicitly to every
| method which actually needs to allocate."
| struct Foo<T> { // ... } impl<T>
| Foo<T> { fn new<A: Allocator>(a: A) -> Foo<T> {
| // do something to make a new foo, calling functions via A
| } }
|
| (EDIT: "new" was a bad choice for me to pick here, see the
| child comment that uses 'put' instead; I was not trying to
| suggest that the allocator only parameterizes a constructor,
| but any call that would need to allocate.)
| tel wrote:
| I suppose the distinction you're suggesting here is that in
| the Zig-like example, two `Foo<T>` can have the same type and
| different allocators.
|
| Author mostly notes that this is more flexible. I can see it
| being possible in each case to have the system be parametric
| in the allocator, though it'll be a lot more annoying in Rust
| give the need to pipe the types around.
|
| Something between that noisiness and the global default
| _does_ bias Rust toward being uncreative with its choice of
| allocator.
|
| I wonder, too: in this example, the author notes that because
| their init function takes an allocator and their event loop
| doesn't, therefore the event loop does no allocation. But, as
| long as a global allocator could be accessed from somewhere
| besides your entrypoint, you could still be calling it. Does
| Zig offer a capabilities model like that?
|
| All in all, I think this difference is more subtle than
| Matklad is making it out to be, but I in no way doubt that
| he's correct. Especially in today's Rust.
|
| Edit: I did some research on Zig and also noticed
| HashMapUnmanaged which might be more what Matklad was
| referencing. In pseudo-Rust, it has impl<K,
| V> HashMapUnmanaged<K, V> { fn put<A:
| Allocator>(&mut self, key: K, value: V, allocator: A);
| }
|
| This justifies the statement "Rather, an allocator is passed
| in explicitly to every method which actually needs to
| allocate." and makes it much more clear where Zig has gone
| here.
| steveklabnik wrote:
| Ah you are right, choosing "new" was a poor choice for my
| example. I didn't even realize that implied something
| slightly different until you made this comment, I'm going
| to update mine slightly to point this out, thank you.
| MrBuddyCasino wrote:
| Thanks for the example. I wasn't aware this is something that
| was planned for Rust, seems like a pretty large breaking
| change. Interesting!
| steveklabnik wrote:
| Nothing is breaking! The change isn't a move to a zig-like
| style, but instead, that in today's Rust, you have
| struct Foo<T> { // ... }
|
| and not struct Foo<T, A: Allocator> {
| // ... }
|
| This isn't breaking because there is a default type
| provided for A.
|
| The handwave is over "Today's Rust", as this machinery has
| already landed, in a sense, it's just not really possible
| to _use_ with the standard library because the allocator
| API isn 't fully stable.
|
| Here's an actual example: https://doc.rust-
| lang.org/stable/std/vec/struct.Vec.html See that "A =
| Global"?
| throwawaymaths wrote:
| what if you want there to be individual allocators (of
| the same type) that you want to point differently based
| on <X condition>. For example in a M:N greenthreaded
| system perhaps you want each greenthread to have its own
| arena allocator. But you can't use something like
| threadlocal, because at any time a greenthread might move
| to any given OS thread? Is that possible in rust?
| steveklabnik wrote:
| 1. You can do anything you want in Rust, you can make
| your own collections do whatever you want at any time.
|
| 2. These changes are about two things,
|
| 2a. the first of which is a trait that represents the
| concept of an allocator, in case users' code would like
| to be generic over ones that exist in the ecosystem. You
| can of course still paper over this yourself but the
| whole point of a vocabulary trait is so that you don't
| have to do all the work yourself.
|
| 2b. the second of which is how the collections in the
| standard library are customized by allocators.
|
| So, in your own code, absolutely you could do that if you
| wanted to. With this proposal, and trying to do that with
| a standard library provided data structure? I'm not an
| expert on the API that it gives, so I can't really speak
| to its viability here. I would _imagine_ it 's not super
| simple, given what I do know.
| throwawaymaths wrote:
| sorry, I should have been clear: I meant with a standard
| lib provided data structure.
|
| Thanks!
| monocasa wrote:
| Yes, the data structures in std are parameterized over
| the allocator, with Global as the default allocator if
| not specified.
|
| https://doc.rust-lang.org/std/vec/struct.Vec.html
| MrBuddyCasino wrote:
| I see. I'm interested in the motivation and design goals
| behind it, is there something that spells those out? The
| only thing I could find quickly is this [0].
|
| [0] https://internals.rust-lang.org/t/why-bring-your-own-
| allocat...
| steveklabnik wrote:
| https://rust-lang.github.io/rfcs/1974-global-
| allocators.html was the original RFC.
|
| My vague understanding is that there's a working group
| https://github.com/rust-lang/wg-allocators
|
| The further I get from working on Rust day to day, the
| less I know about these things, so that's all I've got
| for you.
| [deleted]
| fweimer wrote:
| I understood the comment to be more about _some way_ to
| parameterize allocators on a per-type basis for standard
| library types, and not a specific mechanism.
|
| C++ nowadays has stateful allocators (e.g., _allocate in this
| specific pool please_ ). With that, even the variant with a
| type parameter on the type benefits from a constructor
| argument that specifies an allocator object explicitly.
|
| And I don't think the type-parameter-on-functions-only
| approach can be made safe for immutable data structures
| because the allocators used for allocation and deallocation
| must match. And the appropriate allocator needs to be known
| at Drop time anyway.
| epage wrote:
| Having dealt with the brittleness of mixed-allocator code in
| C/C++, I much prefer library designs that ensure I'm using
| the right allocator in the right place.
| camdenreslink wrote:
| The rust-analyzer guy now writes Zig full time?
| eatonphil wrote:
| > I now find myself writing Zig full-time
|
| Seemed pretty clear to me. :)
| O_H_E wrote:
| Yeah that made me wow too!
|
| He's gonna have a wild career.
| Ygg2 wrote:
| Yes, he found a job writing Zig.
| nevi-me wrote:
| I think writing a language full-time is a given or necessity if
| you've been hired to work on software that uses it. Unless you've
| had prior experience and can continue tinkering with other
| things. It's cool that matklad's moved to such an interesting
| project.
|
| I saw TigerBeetle a few months back, and thought that it's
| interesting to build a double-entry DB. As an accountant who's
| built double-entry systems into 'normal' SQL DBs, I find this an
| interesting enough concept that I'm now intrigued to try it out.
|
| Perhaps the year is still young enough for me to finally learn
| Zig while I go through their repo. It might also help me with the
| awkward knowledge gap that still exists between Rust FFI (in that
| I seldom know what I'm doing) and C.
| haberman wrote:
| > First, I think Zig's strength lies strictly in the realm of
| writing "perfect" systems software. It is a relatively thin slice
| of the market, but it is important.
|
| This resonates with me. This is exactly why I use C today, and
| why Zig appeals to me.
| mustache_kimono wrote:
| This definition of "perfect" might be counterintuitive for
| those that haven't read the piece.
|
| The idea is there might some ideal memory allocation scenario
| that Rust doesn't do "perfectly" that you can theoretically do
| better in Zig, which I buy. Most particularly, my experience
| with arenas and defer drop is -- they aren't always perfectly
| easy in Rust. But this definition of perfection tends to ignore
| all the manual, boilerplate memory management you have to do in
| the interim, that you may still mess up in some subtle way.
| haberman wrote:
| > Most particularly, my experience with arenas and defer drop
| is -- they aren't always perfectly easy in Rust.
|
| That is my experience also:
| https://blog.reverberate.org/2021/12/19/arenas-and-rust.html
|
| I was hoping the borrow checker would perfectly check arena
| lifetimes. And it does, but it requires that your types have
| lifetime parameters. That makes logical sense, but my
| experience attempting to actually _use_ a type with a
| lifetime parameter is that it is so painful as to not be
| practical in a low-level library.
| WhereIsTheTruth wrote:
| The only advantage Zig has is its ability to consume C/C++ as it
| ships with clang
|
| That's about it, the language is too verbose and sometimes not
| enough verbose with all these .{} you need to always look at the
| documentation to remember what this does, this is time consuming
| and does useless context switches
|
| Last time i tried to build their language server to use in my
| editor, and i was surprised it took an eternity to compile,
| similar to rust here, i was hoping it would do better
|
| I love the build.zig feature, you stick to 1 language, there is
| no json/yaml/toml/xml BS, it's very refreshing to see
|
| Cons:
|
| - erognomics
|
| - slow to compile
|
| - verbose but sometimes not (.{})
|
| Pros:
|
| - builtin C/C++ compiler
|
| - build.zig
|
| - files are structs
|
| - lazy compilation model (you can write platform specific code
| very easily without bloating your project)
| stephc_int13 wrote:
| I tend to agree with most of your remarks.
|
| Zig would clearly be a better choice than Rust to replace C.
|
| Zig is also better than C in some ways, but worse in others,
| this is frustrating.
|
| The trick is that most of the good parts are either transient
| QoL improvements (such as the build system) or guard rails to
| avoid costly mistakes (no macros, explicit memory management)
| but the drawbacks (annoying syntax, peculiarities, probably
| trying to do too much) seems to be long-lasting daily
| annoyances.
|
| I am waiting for 1.0 and also for Jai.
| scythe wrote:
| >Erlang style, where we embrace failability of both hardware and
| software and explicitly design programs to be resilient to
| partial faults.
|
| >SQLite style, where we overcome an unreliable environment at the
| cost of rigorous engineering.
|
| I don't think that the way this contrast is illustrated is nearly
| as helpful as the author intended it to be. Based on my prior
| knowledge of Erlang and SQLite, I can reconstruct the idea that
| the difference is that Erlang tries to build a "reliability
| layer" below the software, while SQLite builds lots of checks and
| self-correction into the software. But if I didn't already know
| that, the quoted lines would leave me hopelessly confused.
| mats852 wrote:
| And also the billions of tests they run against every builds!
|
| https://www.sqlite.org/testing.html
|
| I enjoyed the CoRecursive podcast with Richard Hipp, it's
| fascinating.
|
| https://corecursive.com/066-sqlite-with-richard-hipp/#billio...
| [deleted]
| Ciantic wrote:
| For those reading only the beginning, one could think that Matt
| is endorsing Zig over Rust. It's not that, from the article:
|
| > It's not true that rewriting a Rust program in Zig would make
| it simpler. On the contrary, I expect the result to be
| significantly more complex (and segfaulty). I noticed that a lot
| of Zig code written in "let's replace RAII with defer" style has
| resource-management bugs.
|
| I also have read Matt's "Hard Mode Rust", and I think there needs
| to be a better way. Why can't we have flexible language that can
| span both styles of allocating resources? I also wonder what
| TigerBeetle would look like if it were written in Rust using the
| "Hard Mode".
| fanf2 wrote:
| "Matt" is not his name https://matklad.github.io/about.html
| csnover wrote:
| > Zig forces you to pass the allocator in, so you might as well
| think about the most appropriate one!
|
| I really feel like this is an underappreciated aspect of some of
| the more complained-about constraints that these newer languages
| place on programmers.
|
| Like an i32, the default allocator will do a reasonable thing
| most of the time, but having to think about each allocation (is
| this short-lived or long-lived? is it actually necessary to do a
| heap allocation at all here? do you actually want GC?) makes code
| better and pushes the programmer to improve their ability to
| rationalise about what they're actually doing in ways that
| provide tangible benefits.
|
| By way of comparison, when I started writing Rust I was very
| frustrated by all the explicit conversions, but eventually
| realised that it (a) forces me to actually stop and think about
| what the most natural type is for a given value, and (b) also
| makes it clearer where the natural boundaries are between
| components. In my experience, if there's a lot of conversion
| going on within a function or module, it's usually not because
| the language is 'too verbose'. Instead, it's because the API
| boundaries are in the wrong places, and the language has helped
| to reveal this by making doing the wrong thing harder.
| kaba0 wrote:
| Ad absurdum that would make assembly a better choice -- we can
| just as well reason about better register allocation
| strategies.
|
| I think the fundamental abstraction level is very important to
| get right. Of course it depends on the problem domain, and it
| might just make sense for Zig to expose explicitly allocators
| everywhere, but maybe some implicitly passed allocator when not
| otherwise specified could be a better trade off (correct me if
| it is a thing)
| nindalf wrote:
| This title is almost perfectly designed to do well on HN, but
| it's definitely worth reading in it's entirety.
|
| Some highlights for me:
|
| - The author sees Rust and Zig in different niches. When Rust was
| created it didn't need to specialise because there were no
| languages like Rust. It was free to be a general purpose language
| targeting multiple domains. But that's not the case for Zig. He
| sees Zig shining at writing systems software that requires low
| level control - where unsafe code is a necessity and fine grained
| control over allocation is a blessing.
|
| - The author was the original author of rust-analyzer, the LSP
| for Rust. I remember reading his original proposal for why Rust
| should ditch their existing LSP effort (called Rust Language
| Server) and start afresh with a completely new. And he was 100%
| right. He knows what he's talking about when it comes to IDE
| experiences for languages. I hope the Zig developers listen to
| what he's suggesting here.
|
| - "Rust is a language for building modular software ... the core
| of what Rust is doing: it provides you with a language to
| precisely express the contracts between components, such that
| components can be integrated in a machine-checkable way." That is
| a good description of Rust. Rust allows you to confidently
| assemble a program that works well, even if you have to
| collaborate with hundreds of other programmers to create it.
|
| - "Zig is about perfection. It is a very sharp, dangerous, but,
| ultimately, more flexible tool." Makes sense, but this tells me
| that I probably lack the skill to write correct Zig.
|
| - Comment by the author on reddit
| (https://www.reddit.com/r/rust/comments/123jpry/comment/jdv9x...)
| about advantages that Zig has is illuminating. Again, none of
| these appeal to me, but these are great to have in the right use
| case.
|
| - In a different comment on reddit
| (https://reddit.com/r/Zig/comments/123jpia/blog_post_zig_and_...)
| he said "Until release-safe guarantees the absence of UB, I
| wouldn't be ready to recommend Zig as a general-purpose
| language." Which is fair, but it's still early days for Zig,
| years to go before 1.0. It's entirely possible that this
| behaviour could come to be.
|
| I think the author's article makes a compelling case that Rust
| and Zig can both co-exist and succeed.
| rektide wrote:
| > _I remember reading his original proposal for why Rust should
| ditch their existing LSP effort (called Rust Language Server)
| and start afresh with a completely new. And he was 100% right._
|
| Where can I read more about this? What ended up happening?
| steveklabnik wrote:
| https://blog.rust-lang.org/2022/07/01/RLS-deprecation.html
| was the announcement of the replacement, and talks about it a
| little bit:
|
| > RLS was introduced by RFC 1317 and development was very
| active from 2016 through 2019. However, the architecture of
| RLS has several limitations that can make it difficult to
| provide low-latency and high-quality responses needed for an
| interactive environment.
|
| > rust-analyzer uses a fundamentally different approach that
| does not rely on using rustc. In RFC 2912 rust-analyzer was
| adopted as the official replacement for RLS.
|
| These RFCs provide some more color.
|
| The long and short of it is, the RLS relied on a process
| where rustc would sort of pre-process your codebase, and spit
| out a "save analysis" file. RLS would read this file, and do
| its thing. rust-analyzer, on the other hand, doesn't use
| rustc at all(*), and instead analyzes your code on-demand, in
| an incremental style. The latter has many advantages in an
| IDE context.
|
| The * is there because part of the original idea is that
| rustc would end up producing some libraries that rust-
| analyzer would also use, allowing them to share code. Given
| that rustc has also been moving towards an incremental, on-
| demand architecture, this would be easier. I am out of the
| loop these days, but from the relative outside, this effort
| seemed to stall out. I don't really know why. Maybe it has
| been happening and just isn't really visible.
|
| Regardless of those details, rust-analyzer is very good. It's
| a shame the transition took so long, in retrospect!
| rektide wrote:
| Very cool. Thanks for the links & write up!
| nindalf wrote:
| I can't find the original link to his proposal, but I did
| send him a message on reddit asking if still had a link to
| it.
|
| The gist of it was, he felt the first attempt to make a Rust
| LSP (RLS) had the wrong architecture. It was basically
| running the Rust compiler in check mode and relaying the
| errors back. In his opinion an IDE needed a different,
| incremental architecture that stored state. It also needed to
| be much more tolerant of errors.
|
| He had already made a Rust IDE plugin in Java for JetBrain's
| IntelliJ-Rust plugin, and wanted to make a similar one in
| Rust.
|
| So he started the rust-analyzer project and it succeeded.
| Last year it became the official LSP of the Rust project.
| (https://blog.rust-lang.org/2022/02/21/rust-analyzer-joins-
| ru...)
| yawaramin wrote:
| > He sees Zig shining at writing systems software that requires
| low level control.
|
| Honestly don't see why we would need to specialize this use
| case to a different language altogether when Rust already has
| `unsafe`.
| kristoff_it wrote:
| Some arguments about how Rust `unsafe` is not the same as
| Zig:
|
| https://zackoverflow.dev/writing/unsafe-rust-vs-zig/
| trh0awayman wrote:
| My general understanding is that Zig was made to make video
| games and Rust was made to make system software, and everything
| falls out from there.
| alpaca128 wrote:
| Did you mean Jai, which indeed is made with game development
| in mind? Because I've never heard anyone talk about games
| with Zig, and iirc one of the original motivations for the
| language was audio software.
| formerly_proven wrote:
| Zig feels like a good match for replacing C on microcontrollers
| because it permits "hold my beer" shenanigans and memory
| management is less of an issue. Zig metaprogramming also seems
| like a better match for these environments - think about how
| much nicer you could do stuff like qmk -, the Rust embedded
| stuff seems quite painful in comparison.
|
| Haven't tried this yet, it's on my perennial todo list and when
| I touch this stuff I usually want to get something done. I also
| imagine you'll have to do everything yourself with Zig here,
| while Rust does have a lot of HAL crates.
| grawp wrote:
| I have the exactly opposite experience. Rust move semantics,
| borrowing, Send&Sync types and checks and type based compile
| time state-machines is exactly what I was missing
| _specifically on embedded systems_ in C /C++ and what I'm
| sorely missing in Zig.
|
| In Rust you start by splitting peripheries to blocks, then to
| registers, then to register parts and distributes these
| (these are zero cost operations!) into irq handlers and tasks
| and the type systems will check that everything that need
| exclusive access has it .. that you do not use read-modify-
| write operation on a same register from two interrupts where
| one can preempt the other without using some guard as mutex..
| while it perfectly allow you to do this with write-only
| registers without guard etc... it is just so nice to work
| with.
|
| People who find it complicated and/or not worth it are
| usually doing either some rudimentary super duper easy stuff
| on architectures or OSes which does not have or utilize
| nested interrupts or they do it on some IOT like noncritical
| stuff where they don't give a s** (vs industrial machinery,
| drones, other vehicles..).
| kristoff_it wrote:
| > Zig feels like a good match for replacing C on
| microcontrollers because it permits "hold my beer"
| shenanigans
|
| People who have used Zig to do embedded work have reported
| the opposite: they like Zig because it helps keep simple
| things simple and not more unsafe than they have to be.
|
| https://kevinlynagh.com/rust-zig/
| lr1970 wrote:
| > - The author was the original author of rust-analyzer, the
| LSP for Rust
|
| Not only this. matklad is also original author of IntelliJ Rust
| - another popular IDE.
| EVa5I7bHFq9mnYK wrote:
| >> When we call malloc, we just hope that we have enough stack
| space for it, we almost never check.
|
| Does Rust or Zig's malloc allocate on stack? Those millennials.
| kristoff_it wrote:
| It's a function, when you call it, it allocates a frame on the
| stack.
| infogulch wrote:
| > That's the core of what Rust is doing: it provides you with a
| language to precisely express the contracts between components,
| such that components can be integrated in a machine-checkable
| way.
|
| That's a nice description of rust.
| legerdemain wrote:
| Not a particularly deep comment, but... matklad (the author)
| created, essentially, the entirety of the modern Rust developer
| experience. He is the original author and biggest contributor to
| both rust-analyzer and Intellij Rust. If someone this central to
| the Rust world has switched to writing Zig full time, and not for
| boring, pragmatic reasons either, a little seed of doubt about
| the long-term stability of Rust as a professional community
| begins to grow in my heart.
___________________________________________________________________
(page generated 2023-03-27 23:02 UTC)