[HN Gopher] Roc rewrites the compiler in Zig
___________________________________________________________________
Roc rewrites the compiler in Zig
Author : todsacerdoti
Score : 333 points
Date : 2025-02-04 17:21 UTC (1 days ago)
(HTM) web link (gist.github.com)
(TXT) w3m dump (gist.github.com)
| cma256 wrote:
| It will be interesting to compare compile times afterwards. I'm
| also interested if there's any Rust features that are 'taken for
| granted' which will make the Zig version less pleasant to read or
| write. Hopefully the old Rust repo is archived so I can reference
| it a year from now!
| badfishblues wrote:
| It will be impossible to ever truly do a one-to-one comparison.
| First, there may be a ton of code in the existing
| implementation that gets cut out by a mass rewrite due to
| better, more informed, architecture decisions. On the other
| hand, it may be possible that new features find their way into
| the rewrite that cause the fully Zig implementation to be
| larger than the original Rust-Zig implementation. I don't think
| any comparison will be fully "fair". A smaller implementation
| could be argued as only being possible in Rust or Zig because
| of its advantages over the other language. I expect results to
| be controversial.
| bhansconnect wrote:
| Yeah, the rewrite will clean up a ton of technical debt for
| us. So it will very much be a bad comparison.
| gauge_field wrote:
| I am also curios about at least some benchmark even if it is
| not one-to-one perfect comparison. There should be at least
| one case-study where they have shorter feedback loop with Zig
| than with Rust. It would be interesting to see that.
| hassleblad23 wrote:
| Zig seems to be a good choice here.
| UncleOxidant wrote:
| > Rust's compile times are slow. Zig's compile times are fast.
| This is not the only reason, but it's a big reason.
|
| So why not something like OCaml that has fast compile times and
| a lot of nice features for writing compilers? (pattern
| matching, etc.)
| whytevuhuni wrote:
| Because, like he said, compile times matter.
|
| This includes the Roc compiler too. Zig is significantly
| faster than OCaml.
| LAC-Tech wrote:
| The Ocaml compiler is significantly faster than the Zig
| one. It's one of the fastest I've seen.
| whytevuhuni wrote:
| Ah, sorry, I was referring to the speed of the resulting
| Roc compiler.
|
| A Roc compiler written in Zig would compile Roc code
| significantly faster than a Roc compiler written in
| OCaml.
| LAC-Tech wrote:
| Ah! That makes sense.
| platinumrad wrote:
| The same reason why they're not self-hosting. They want
| compiler performance to be in the top C, C++, Rust, Zig tier.
| OCaml isn't slow, but at best it's in the second Java, C#,
| etc. tier.
| henning wrote:
| Zig's union enums get you something kind of like pattern
| matching. https://zig.guide/language-basics/unions/
| theLiminator wrote:
| I guess if you want to never limit yourself in terms of
| performance, you're kinda stuck with either
| C/C++/Zig/Rust/etc.
|
| GCed languages can be fast, probably even as fast as any of
| the aforementioned languages with enough engineering effort,
| but in terms of high performance, it's actually easier to
| write high performance code in the aforementioned languages
| rather than in a GCed language.
| pjmlp wrote:
| OCaml is fast enough for writing hypervisors, unikernels,
| networking drivers, powering all Jane Street's business.
| UncleOxidant wrote:
| What is Roc? Here it is: https://www.roc-lang.org/
| pjmlp wrote:
| The way compile times are stressed all over the place is a very
| good point.
|
| Papercuts like this do make or break adoption.
|
| Even C++ is improving on that front.
| nurettin wrote:
| ccache made C++ usable for me.
| Cyph0n wrote:
| https://github.com/mozilla/sccache
| pjmlp wrote:
| It has been mostly usable to me with binary libraries,
| precompiled headers, incremental compiling and linking, and
| now modules.
|
| Although ClearMake object sharing was quite neat experience
| back in the day.
| pcwalton wrote:
| As is Rust. And the C++ compiler performance improvements in
| LLVM apply to Rust.
| pjmlp wrote:
| I was talking about C++ 20 modules and C++23 modularised
| standard library, and that has little to do with LLVM, rather
| clang.
|
| LLVM improvements will do little to improve Rust, because the
| major issue is the lack of parallelism and massive amount of
| LLVM IR that the fronted gives to the backend to handle.
| pcwalton wrote:
| > LLVM improvements will do little to improve Rust
|
| Falsified many times during Rust's development.
| pjmlp wrote:
| Not to the extent C++ modules have improved compile
| times, as already visible in VC++ and clang/cmake/ninja
| latest.
|
| Yes, Rust compile times have improved a lot, still I get
| better ones in C++, without having to reach out external
| tools.
|
| Bevy's tutorial for compile times shouldn't be needed in
| first place.
| rubenvanwyk wrote:
| After watching YT talks on Roc using Rust and Zig, I always
| wondered they didn't just opt for Zig only. Interesting to see
| this.
| bhansconnect wrote:
| Yeah, the compiler was started in 2019 when zig wasn't nearly
| as viable of an option. On top of that, you don't necessarily
| know what you want until you build something.
|
| I'm part of the core team, and I'm honestly still a bit
| surprised we're switching to zig. I think it makes sense, it
| just kinda finally aligned and was decided now. I guess enough
| technical debt piled up and the core of the language was
| clearly discovered. So we really know what we want now.
| bmacho wrote:
| Strangely they don't mention that (allegedly? According to them
| at least) they already use Zig for the standard library[0]. Which
| was also started to be written in Rust, then it got rewritten in
| Zig:
|
| [0] : https://www.roc-lang.org/faq#rust-and-zig
| laserbeam wrote:
| > (and to unblock updating to the latest Zig version, which
| we've use for our stdlib for years)
|
| It's somewhere in the middle of the list of the "Why now?"
| section.
| thegeekpirate wrote:
| They do mention it but there's only 10k lines of Zig, so it's
| hardly a blip in the grand scheme of things.
| baq wrote:
| A very good discussion and hard to disagree with conclusions.
| Also, educational.
| cardanome wrote:
| Richard Feldman is an amazing educator. He got me into Elm back
| in the days.
|
| I am a bit sad that Roc is following similar pitfalls as Elm in
| its quest to be simple by rejecting to have more advanced type
| system features. That just does not work. In dynamic languages
| you can opt for minimalism because everything goes by default
| but in fully statically typed languages things can painful
| quickly. Even golang had to add generics.
|
| Still many amazing ideas in the language. The platform concept
| is pretty neat. Not doing implicit currying is a good move.
| Hasnep wrote:
| But Roc already has generics, Go has managed to become very
| successful despite having a simpler type system than Roc.
| bbkane wrote:
| What particular type system featured do you miss? I think Elm
| proved that a restricted type system DOES WORK for large
| amounts of software. It's been a few years since I've written
| Elm, so I don't recall specific painful memories I've had
| with the type system.
|
| One thing that makes Go's restrictive type system more
| bearable is a fantastic stlib package for analyzing and
| generating Go code. I wonder if Roc will get anything
| similar.
| forgotmypass1 wrote:
| What kind of advanced type system features?
| 1-more wrote:
| If you're talking about typeclasses, Roc calls them
| "abilities" https://www.roc-lang.org/abilities
| greener_grass wrote:
| > While we're at it, we also want to convert it to use recursive
| descent; it was originally written using parser combinators
| because that was what I was comfortable with at the time
|
| Aren't parser combinators just one way to do recursive descent?
| jjk7 wrote:
| Explicitly hand-writing the parsing logic allows you to get
| more specific in error states and messages that a combinator
| can't.
| Lyngbakr wrote:
| The rationale given makes perfect sense, but isn't it risky to
| rewrite in a language that is yet to hit 1.0?
| stevage wrote:
| Much better before than after!
| Lyngbakr wrote:
| Why? There's the possibility that Zig will introduce breaking
| changes and the Roc compiler will have to be revised in light
| of those changes.
| brokencode wrote:
| I'm assuming the previous commenter thought you were
| referring to Roc being pre v1 and not Zig.
|
| There are probably some risks to it. And I think that you
| wouldn't want to release a Roc v1 before Zig v1 as well.
|
| But if things are working well now, you could always stay
| on an older version of Zig while you rewrite things for
| breaking changes in a newer version.
|
| Still potentially a pain, but Rust is post v1 and they
| ended up deciding to rewrite anyway, so there are no
| guarantees in any approach.
| bhansconnect wrote:
| For sure, but we have a really good relationship with the zig
| folks and they are willing to help us out.
|
| On top of that, zig has gotten a lot more robust and stable of
| the last few releases. Upgrading is getting smoother.
|
| But yeah, it is a risk.
| IshKebab wrote:
| This is the first justification of not using Rust that I actually
| agree with. Well written.
|
| I recommend reading Roc's FAQ too - it's got some really great
| points. E.g. I'm internally screaming YESSS! to this:
| https://www.roc-lang.org/faq.html#curried-functions
|
| But then it has other weird features too, like they seem to be
| really emphasising "friendliness" (great!) but then it has weird
| syntax like `\\` for anonymous functions (I dunno where that dumb
| syntax came from by Nix also uses it and it's pretty awful).
| Omitting brackets and commas for function calls is also a bad
| decision if you care about friendliness. I have yet to find a
| language where that doesn't make the code harder to read and
| understand.
| Skinney wrote:
| The syntax came from Elm, which got it's syntax from Haskell
| (where Nix also got it from) which got its syntax from ML.
|
| It's a syntax that's several decades old at this point.
|
| It's different, but not harder. If you learned ML first, you'd
| found Algol/C-like syntax equally strange.
| wk_end wrote:
| (ETA: speaking strictly about anonymous functions; on
| rereading you might be talking about the absence of parens
| and commas for function application.)
|
| That's not ML syntax. Haskell got it from Miranda, I guess?
|
| In SML you use the `fn` keyword to create an anonymous
| function; in Ocaml, it's `fun` instead.
| throwaway17_17 wrote:
| I believe the `\\` character for functions is original to
| Haskell. Miranda does not have anonymous functions as a
| part of the language.
| pezezin wrote:
| The \ is a simplified lambda, because most programmers
| can't type l easily.
| needlesslygrim wrote:
| Well, ML (or at least the first versions of it) used a lx *
| x syntax [1] for l-abstractions, the same (excluding the
| use of * over .) notation as used with the Lambda Calculus,
| and I've always assumed \ was an ASCII stand in.
|
| [1]: https://homepages.inf.ed.ac.uk/wadler/papers/papers-
| we-love/... (can be spotted on page 353)
| wk_end wrote:
| That paper isn't showing real ML syntax itself; it's a
| mathematical presentation to demonstrate how the type
| system algorithm works. The actual original LCF/ML syntax
| would differ. I don't believe it used an actual lambda
| character, although for the life of me I can't find any
| evidence one way or another, not even in the LCF source
| code (https://github.com/theoremprover-museum/LCF77)
|
| But yes, the slash is just an ASCII stand-in for a
| lambda.
|
| ETA: I tracked down a copy of the Edinburgh LCF text and
| I have to eat crow. It doesn't use a lambda, but it
| _does_ use a slash rather than a reserved word. The
| syntax, per page 22, is in fact, `\x. e`. Similar to
| Haskell 's, but with a dot instead of an arrow.
|
| https://archive.org/details/edinburghlcfmech0000gord
| needlesslygrim wrote:
| Well if you're going to eat crow, I may as well eat
| pigeon, for I didn't realise that paper wasn't showing
| real source.
|
| Thanks for the link to the LCF text though :^)
| xiaodai wrote:
| R has that too.
| Iwan-Zotow wrote:
| really? thought it just function(x)
| mrkeen wrote:
| It's the closest you get to 'l' on a US keyboard.
| LAC-Tech wrote:
| I believe Haskell uses it as well.
| nemo1618 wrote:
| my hot take: the language should accept \, but formatters
| should replace it with l
| IshKebab wrote:
| Lean does symbols very well. You can just type \r and it
| will replace it with a right arrow as you type.
| fuzztester wrote:
| IIRC, Richard explain that in one of his videos about Roc. I
| have seen at least a handful of them.
| IshKebab wrote:
| So this assumes knowledge of an obscure theoretical
| programming language, _and_ a dubious symbol replacement.
| Yeah...
| postepowanieadm wrote:
| ^\
| hillcapital wrote:
| They recently changed the syntax to add parens, commas and use
| `|arg|` for closures :)
|
| https://github.com/roc-lang/roc/releases/tag/0.0.0-alpha2-ro...
| anacrolix wrote:
| Boooo
| masijo wrote:
| Jesus, why? This is a bummer.
| hajile wrote:
| Pretty much all of those changes look bad to me.
| trescenzi wrote:
| oh wow it went from being a very clear language to looking
| more like a hodgepodge of a few different languages.
| IshKebab wrote:
| Ah great improvements! I don't know why the sibling comments
| are so negative; this is clearly better.
| tasuki wrote:
| Why? I'm used to \ meaning lambda. I understand you aren't,
| and that's fine. But it's just your weird opinion
| determined by what programming languages you've learned.
|
| Ultimately, it's just syntax and not so important.
| Semantics are important.
| IshKebab wrote:
| > Why? I'm used to \ meaning lambda.
|
| 1. I know what lambda calculus is, and I didn't even make
| the connection between \ and lambda. It's pretty tenuous.
|
| 2. Most programmers do not know what lambda calculus is.
| This is supposed to be a friendly language, not an
| obscure academic one.
|
| 3. It's not even the same lambda as in lambda calculus,
| e.g. it takes multiple arguments.
|
| 4. Lambda was a reasonable choice in lambda calculus
| since it's a very "mathsy" language, and it's pretty much
| the only symbol in the language. It's a pretty awful
| choice for a practical programming language though -
| there's a reason 99% of languages use something like `fn`
| or `fun` or `function` or `def` instead of lambda to
| define top-level functions.
|
| I'm not a _huge_ fan of `|foo|` either to be honest - I
| don 't see why you can't simply use the same syntax for
| anonymous and named functions - but it is at least a
| little better.
|
| If it were up to me I'd go with something like
| fn double(a: list[int]) -> list[int] {
| a.map(fn(i) { i * 2 }) }
|
| Same syntax; just allow omitting the name and inferring
| the types. I can't recall any languages that do that
| though so maybe there's some tricky reason it can't work?
| Hasnep wrote:
| Roc does use the same syntax for anonymous and named
| functions, both before and after the recent syntax
| changes.
| trescenzi wrote:
| Right now I'm in between liking Gleam or Roc for a hobby
| functional language. The syntax you wrote is Gleam[1],
| well aside from it being List(). It's very approachable,
| very consistent and that's a core goal.
|
| Roc was appealing because it was slightly more distinct
| and more unique. Plus it was more focused on speed. I
| appreciate them wanting to become more approachable. The
| new syntax seems less approachable to me because it's now
| a half step between approachable Haskell and what feels
| like a combination of Ruby and Python.
|
| [1]: https://gleam.run/
| pmarreck wrote:
| > Most programmers do not know what lambda calculus is
|
| I would frankly be shocked if a 4 year syllabus in CS
| these days just _skipped_ any mention of Alonzo Church,
| especially considering that it 's fundamental to
| functional programming and theoretical computer
| science...
|
| Maybe it's not taught in "CS" programs that are actually
| just "practical software engineering" bootcamps with
| extra steps. The real nerds know about lambdas. They're
| even literally called that in Ruby (and possibly other
| languages).
| akkad33 wrote:
| There can't be a more democratized language than Python
| and in Python closures are defined literally using lambda
| keyword
| akkad33 wrote:
| I think because a closure is not a function as a closure
| can capture its environment, in a way that functions
| can't, so using the same syntax for closures and
| functions can be misleading (even though languages like
| JS do it)
| LAC-Tech wrote:
| Opposite effect one, lost interest in Roc after reading that.
|
| If anything I don't think Haskell goes far enough the automatic
| currying, points free stuff. If you're going to be declarative,
| don't half ass it.
| hajile wrote:
| I feel that he got a lot of pressure from the FP community and
| wrote a bunch of nonsense instead of being straightforward with
| them.
|
| The only relevant reason he lists is point-free, but he doesn't
| go far enough. Point-free very often turns into write-only
| balls of unmaintainable nastiness. Wanting to discourage this
| behavior is a perfectly reasonable position. Unfortunately,
| this one true argument is given the most tepid treatment of all
| the reasons.
|
| Everything else doesn't hold water.
|
| As he knows way better than most, Elm has auto-curry and has
| been the inspiration for several other languages getting better
| error messages.
|
| Any language with higher-order functions can give a function as
| a result and if you haven't read the docs or checked the type,
| you won't expect it. He left higher-order function in, so even
| he doesn't really believe this complaint.
|
| The argument about currying and pipe isn't really true. The
| pipe is static syntax known to the compiler at compile time.
| You could just decide that the left argument is applied/curried
| to the function before the right argument.
|
| I particularly hate the learning curve argument. Lots of great
| and necessary things are hard to learn. The only question is a
| value judgement about if the learning is worth the payoff. I'd
| guess that most of the Roc users already learned about currying
| with a more popular FP language before every looking at Roc, so
| I don't think this argument really applies here (though I
| wouldn't really care if he still believed it wasn't worth the
| learning payoff for the fraction of remaining users).
|
| To reiterate, I agree with his conclusion to exclude currying,
| but I wish he were more straightforward with his one good
| answer that would tick off a lot of FP users rather than
| resorting to a ton of strawman arguments.
| throwaway2037 wrote:
| No trolling/nitpicking from me: You wrote <<The only relevant
| reason he lists is point-free>>. What do you mean by "point-
| free"... or did you write "point three" and it was auto-
| corrected on a mobile phone?
|
| I also tried Googling for that term (never heard before), and
| I found these:
| https://stackoverflow.com/questions/944446/what-is-point-
| free-style-in-functional-programming
| https://en.wikipedia.org/wiki/Tacit_programming
|
| If you really meant "point-free", can you tell me where in
| his post he mentions it? I would like to learn more.
| syockit wrote:
| It's in the FAQ. Someone else posted a link to it in the
| comments, check it out. And yes, it is about tacit
| programming.
| hajile wrote:
| Point-free is a functional programming style where you
| avoid assignments and prefer to do everything as a group of
| nested, mapped, and composed functions. It relies heavily
| on partial application. Like everything, it can be good
| when used in moderation.
|
| Here's a made-up JS example. I've attempted to be fair to
| both approaches doing it how I personally would with each.
| //typical implementation const howManyAdults =
| (data) => { const adults = data
| .flatMap(obj => obj.type === 'parent' ? [obj,
| ...obj.children] : obj) .filter(obj => typeof
| obj.age === 'number') .filter(obj => obj.age >=
| 18 && obj.age < 150) adults.forEach(adult =>
| console.log(`${adult.name} is an adult age ${adult.age}`)
| ) return adults.length }
| //nice "point-free" implementation using helper functions
| const transformData = obj => obj.type === 'parent' ? [obj,
| ...obj.children] : [obj] const isAdult = obj =>
| obj.age >= 18 && obj.age < 130 const
| howManyAdults = pipe( flatMap(transformData),
| filter(hasTypeOf('age', 'number'),
| filter(isAdult), logEach`${pick('name')} is an
| adult age ${pick('age')}`, len, )
| //completely point-free gets crazy const
| howManyAdults = pipe( flatMap(ifElse(
| compose(eq('parent'), pick('type')),
| juxt([identity, pick('children']), identity,
| ), []), filter(hasTypeOf('age', 'number'),
| filter(both(gte(pick('age',18), lt(pick('age'), 130)))),
| logEach`${pick('name')} is an adult age ${pick('age')}`,
| len, )
|
| I went through a point-free phase early in my career, but
| even with lots of practice, I can't believe that most devs
| ever find the third example as readable as the first or
| second. I'd also note that this is a trivial example and
| doesn't require you to track any monad wrappers either.
|
| Personally, I rather like reading the moderate middle
| example because it removes the boilerplate and allows me to
| easily follow the overall flow without getting caught up in
| the details. But I'll take the first example every time if
| it means never dealing with the third example.
| zozbot234 wrote:
| inb4 pointless programming is pointless
| msla wrote:
| > `\\` for anonymous functions
|
| A one-character ASCII rendering of the Greek lowercase letter
| lambda: l
|
| lx - x + 5
|
| \x -> x + 5
| pmarreck wrote:
| > \ for anonymous functions
|
| this didn't faze me in the least because it's just a more
| easily typed l, the lambda character, which has for a long time
| now (many decades) been used to describe anonymous functions
| (i.e. "lambdas")
|
| did you never take any formal CS education? if not, that might
| explain it
|
| so before you jump to calling it "dumb", maybe next time lean
| on Chesterton's Fence for a bit.
|
| https://sproutsschools.com/chesterton-fence-dont-destroy-wha...
|
| That said, granted, the fact that it's also the escape
| character is problematic. Maybe /\ might have been better but
| that's even _harder_ to type.
| rtfeldman wrote:
| We recently changed Roc's lambda syntax from the syntax that
| languages like Elm and Haskell use... foo =
| \arg1, arg2 -> body
|
| ...to this: foo = |arg1, arg2|
| body
|
| The reason for this change was that we have a new and extremely
| well-received language feature (landed but not yet formally
| announced) which results in `->` and `=>` having different
| meanings in the type system. This made it confusing to have
| `->` in the syntax for anonymous functions, because it seemed
| to suggest a connection with the type-level `->` that wasn't
| actually there.
|
| The most popular syntax that mainstream languages use today for
| anonymous functions is something like `(arg1, arg2) => body`
| but of course that has the same problem with having an arrow in
| it, so changing to that wouldn't have solved the problem.
|
| Rust uses `|arg1, arg2| body` (and Ruby kinda uses it too for
| blocks), and we'd all had fine experiences using that syntax in
| Rust, so we chose it as the new lambda syntax. You can see the
| new syntax in the code example at the top of roc-lang.org.
| HackerThemAll wrote:
| Yeah Rust compiles slowly, so we need two more half-baked
| languages - Zig and Roc, both of which I couldn't care less.
|
| Rust's slow compilation comes from lots of features and an
| excellent generated machine code quality. Both Zig and Roc will
| be equally slow or slower if they match what Rust offers.
|
| If all they want is fast compilation, they can just try Pascal.
| greener_grass wrote:
| I can't help but feel like the Roc team has an attitude of
| "imperative programming for me, but not for thee".
|
| And now they are doubling down on that by moving from "OCaml
| meets C++" to "C, the good parts"!
|
| If FP isn't good for writing a compiler, what _is_ it good for?
| btreecat wrote:
| > If FP isn't good for writing a compiler, what _is_ it good
| for?
|
| Summing the Fibonacci sequence I guess.
| agumonkey wrote:
| other FP languages bootstrapped onto themselves IIRC
| incrudible wrote:
| FP is _bad_ for computing the Fibonacci series unless you
| have the compiler optimization to turn it into a loop (as
| seen in imperative languages).
|
| To be fair, most practical FP languages have that, but I
| never saw the appeal for a strictly functional _general
| purpose_ language. The situations where I wished one could
| not use imperative constructs are very domain specific.
| whlr wrote:
| According to [1], they want to use a systems-level language for
| performance.
|
| [1] https://www.roc-lang.org/faq#self-hosted-compiler
| tialaramex wrote:
| "The split of Rust for the compiler and Zig for the standard
| library has worked well so far, and there are no plans to
| change it."
|
| I assume that statement will need updating.
| WD-42 wrote:
| At this point it feel like the are just playing with
| languages.
| munificent wrote:
| I mean, the language doesn't even have a version number
| yet. We should expect them to still be exploring the
| design space.
| pjmlp wrote:
| "Unix system programming in OCaml"
|
| https://ocaml.github.io/ocamlunix/ocamlunix.html
| munchler wrote:
| As an FP fan, I agree. This is disappointing.
| kristoff_it wrote:
| Huh? The whole point of Roc is to let you easily put both
| imperative and functional code in the same project through
| Roc's platform system.
|
| You get to decide what part of your code should be imperative,
| and which should be functional.
| greener_grass wrote:
| So why is it a non-goal of Roc to be implemented with this
| approach?
| coffeeaddict1 wrote:
| Have you not read the post? Because compile times. Rust has
| awful compile times. If it didn't, I'm sure the Roc team
| would have stayed with Rust.
| greener_grass wrote:
| Yes, I read the post.
|
| I don't understand why the goal is not to (eventually)
| implement Roc in Roc, maybe with a dash of something else
| for the "platform".
|
| Roc is pitched as a general purpose functional
| programming language with great performance.
|
| How does a compiler not fall under this category?
| Hasnep wrote:
| Roc is pitched as having great performance _for a GC 'd
| language_, that is, on par with Java, Go, C# instead of
| Ruby, Python, JS. The Roc compiler team are looking for
| C, C++, Rust, Zig kind of performance. Roc will, by
| design, never reach that kind of speed.
| greener_grass wrote:
| We already have many great GC'd functional languages at
| that performance level.
|
| I first learned about Roc from this talk:
|
| https://www.youtube.com/watch?v=vzfy4EKwG_Y
|
| That's a niche that is not currently filled (well, maybe
| MLTon) and that has me very excited! I'm sure I'm not
| alone here.
| bhansconnect wrote:
| https://www.roc-lang.org/faq.html#self-hosted-compiler
| chubot wrote:
| That's an interesting point, and something I thought of when
| reading the parser combinator vs. recursive descent point
|
| Around 2014, I did some experiments with OCaml, and liked it
| very much
|
| Then I went to do lexing and parsing in OCaml, and my
| experience was that Python/C++ are actually better for that.
|
| Lexing and parsing are inherently stateful, it's natural to
| express those algorithms imperatively. I never found parser
| combinators compelling, and I don't think there are many big /
| "real" language implementations that uses them, if any. They
| are probably OK for small languages and DSLs
|
| I use regular expressions as much as possible, so it's more
| declarative/functional. But you still need imperative logic
| around them IME [1], even in the lexer, and also in the parser.
|
| ---
|
| So yeah I think that functional languages ARE good for writing
| or at least prototyping compilers -- there are a lots of
| examples I've seen, and sometimes I'm jealous of the
| expressiveness
|
| But as far as writing lexers and parsers, they don't seem like
| an improvement, and are probably a little worse
|
| [1] e.g. lexer modes -
| https://www.oilshell.org/blog/2017/12/17.html
| greener_grass wrote:
| OCaml allows mutation via reference cells.
| chubot wrote:
| I know that, and obviously you can write a recursive
| descent parser in OCaml
|
| But I'm saying there's nothing better about it than doing
| it in OCaml vs. C++ or Python -- it's the same or a little
| worse
|
| IMW it's natural to express the interface to a lexer and
| parser as classes -- e.g. you peek(), eat(), lookahead(),
| etc.
|
| Classes being things that control mutation
|
| But objects in OCaml seem to be a little separate dialect:
| https://dev.realworldocaml.org/objects.html
|
| When I debug a parser, I just printf the state too, and
| that is a little more awkward in OCaml as well. You can
| certainly argue it's not worse, but I have never seen
| anyone argue it's better.
|
| ---
|
| Culturally, I see a lot of discussions like this, which
| don't really seem focused on helping people finish their
| parsers:
|
| https://discuss.ocaml.org/t/why-a-handwritten-parser/7282/7
|
| https://discuss.ocaml.org/t/good-example-of-handwritten-
| lexe...
|
| I also use lexer/parser generators, and I like that there
| are more tools/choices available in C/Python than in OCaml.
| isaacvando wrote:
| Roc couldn't be optimized for writing the Roc compiler without
| sacrificing some of its own goals. For example, Roc is
| completely memory-safe, but the compiler needs to do memory-
| unsafe things. Introducing memory-unsafety into Roc would just
| make it worse. Roc has excellent performance, but it will never
| be as fast as a systems language that allows you to do manual
| memory management. This is by design and is what you want for
| the vast majority of applications.
|
| There are a number of new imperative features that have been
| (or will be) added to the language that capture a lot of the
| convenience of imperative languages without losing functional
| guarantees. Richard gave a talk about it here:
| https://youtu.be/42TUAKhzlRI?feature=shared.
| Muromec wrote:
| >but the compiler needs to do memory-unsafe things
|
| sorry, but why?
| isaacvando wrote:
| I believe the main reason is for achieving the best
| possible performance. Someone closer to the compiler could
| give more detail.
| vitiral wrote:
| It's not just the lang but the std lib too
|
| https://www.roc-lang.org/faq#rust-and-zig
| mrkeen wrote:
| I am also skeptical.
|
| A compiler is a function from source code strings to binary
| bytes. Writing out instructions to do memory-unsafe things
| is not in itself a memory-unsafe activity.
| int_19h wrote:
| It still feels kinda weird. Parsers, compilers etc are
| traditionally considered one of the "natural" applications
| for functional programming languages.
| pjmlp wrote:
| There are plenty of compilers written in memory safe
| languages, including the list of self hosted ones linked from
| the gist describing the rewrite.
| chambers wrote:
| This decisions looks well-reasoned. It acknowledges the strengths
| of their current implementation, and explains why another
| language may serve their goals even better. I can follow along as
| someone interested in general software decision-making, even
| though I'm not particularly invested in either language.
|
| One specific thing I like is that the motivation for this rewrite
| is organic, i.e., not driven by an external pressure campaign.
| It's refreshing to see a drama-free rewrite.
| debugnik wrote:
| > we also want to convert [the parser] to use recursive descent;
| it was originally written using parser combinators
|
| Almost all parser combinators _are_ recursive descent with
| backtracking, they just add higher-order plumbing.
|
| I have a feeling that whatever issue they've encountered with the
| combinator approach could have been worked around by handwriting
| only a few pieces.
| wirrbel wrote:
| When I used parser combinations in rust years ago the compile
| times were really long. In also think it's a strange reason to
| move away from rust as a language.
| bhansconnect wrote:
| This is more about simplicity, maintainability, and possiblity
| for new contributors to easily jump in and fix things. Our
| current parser is not fun for new contributors to learn. Also,
| I think parser combinators obsficate a lot of the tracking
| required for robust error messages.
|
| Personally, I find parser combinators nice for small things but
| painful for large and robust things.
| flooow wrote:
| From listening to Feldman's podcast, this doesn't really come as
| a surprise to me. The rigor that Rust demands seems not to jibe
| with his 'worse is better' approach. That coupled with the fact
| they already switched the stdlib from Rust to Zig. The real
| question I have is why he chose Rust in the first place.
| bhansconnect wrote:
| Zig was not ready or nearly as popular back in 2019 when the
| compiler was started.
|
| Not to mention, Richard has a background mostly doing higher
| level programming. So jumping all the way to something like C
| or Zig would have been a very big step.
|
| Sometimes you need a stepping stone to learn and figure out
| what you really want.
| christophilus wrote:
| It's covered in TFA, but the tldr is they started when Zig was
| immature.
| norman784 wrote:
| > The real question I have is why he chose Rust in the first
| place.
|
| If you read the linked post carefully you will know.
|
| > Compile times aside, the strengths and weaknesses of Rust and
| Zig today are much different than they were when I wrote the
| first line of code in Roc's Rust compiler in 2019. Back then,
| Rust was relatively mature and Zig was far from where it is
| today.
| zoogeny wrote:
| It's nice to see Zig continuing to gain support. I have no idea
| why I've ended up siding with Zig in the lower languages wars.
|
| I used to root for the D programming language but it seems to
| have got stuck and never gained a good ecosystem. I've disliked
| Rust from the first time I saw it and have never warmed up to
| it's particular trade offs. C feels unergonomic these days and
| C++ is overfull with complexity. Zig feels like a nice pragmatic
| middle ground.
|
| I actually think Rust is probably perfectly suited to a number of
| tasks, but I feel I would default to choosing Zig unless I was
| certain beyond doubt that I needed specific Rust safety features.
| bornfreddy wrote:
| I wanted to like Rust (memory safety and performance - what's
| not to like?) but both of my experiments with it ended in
| frustration. It seemed a way too complex language for what I
| needed.
|
| Recently, a coworker of mine made a great observation that made
| everything clear to me. I was looking for a replacement for C,
| but Rust is actually a replacement for C++. Totally different
| beast - powerful but complex. I need to see if Zig is any
| closer to C in spirit.
| fc417fc802 wrote:
| Somewhat related, even when I work with C++ I use it as "C
| with RAII". What I _actually_ want is a scheme (R5RS) with
| manual memory management and a borrow checker. I don 't know
| how well such a monstrosity would actually work in practice,
| but it's what I've convinced myself that I want.
| valorzard wrote:
| https://github.com/carp-lang/Carp
| throwawaymaths wrote:
| posted yesterday:
|
| https://news.ycombinator.com/item?id=42923829
| pcwalton wrote:
| > I was looking for a replacement for C, but Rust is actually
| a replacement for C++. Totally different beast - powerful but
| complex.
|
| I've seen this sentiment a lot, and I have to say it's always
| puzzled me. The difference between Rust and basically any
| other popular language is that the former has memory safety
| without GC+. The difference between C++ and C is that the
| former is a large multi-paradigm language, while the latter
| is a minimalist language. These are completely different
| axes.
|
| There is no corresponding popular replacement for C that's
| more minimalist than Rust and memory safe.
|
| + Reference counting is a form of garbage collection.
| zamalek wrote:
| > + Reference counting is a form of garbage collection.
|
| I agree with Raymond Chen's take on the academic definition
| of GCs[1], and therefore Rust is certainly a GC'd language
| (because your code behaves as though memory is infinite...
| usually). It's probably one of the first examples of
| "static garbage collection" - though I'm sure someone will
| point out a prior example.
|
| [1]: https://devblogs.microsoft.com/oldnewthing/20100809-00
| /?p=13...
| jonahx wrote:
| This feels like deliberate misdirection, because in most
| practical cases what people mean is "some memory
| management process that will slow my program down non-
| trivially". By this definition Rust does not have GC
| whereas Go, eg, does.
|
| The "simulates infinite RAM" is an interesting
| perspective but simply not the subject of most
| conversations.
| zozbot234 wrote:
| Manual heap allocation can slow the program down non-
| trivially compared to using an arena which is cleaned up
| all at once; hence, manual heap allocation is a kind of
| GC. Checkmate atheists.
| caspper69 wrote:
| I went down a path researching the viability of region
| based memory management (a form of arenas).
|
| A language based on such a paradigm can be provably
| memory safe, and regions can have their own allocators
| and optionally provide locking when the regions are
| shared.
|
| This approach obviates the need for reference counting
| individual allocations (since regions are tracked as a
| whole), but it suffers from excess memory usage in the
| event of many short-lived allocations (i.e. they leak
| until the entire region's allocations go out of scope).
| But those types of memory accesses can be problematic in
| every systems language as they can eventually cause
| memory fragmentation.
|
| That problem can be minimized using per-allocation
| reference counting, but that can incur a heavy
| performance hit. Although not having to use it everywhere
| could minimize the impact.
|
| The plus side is you don't have to worry about borrow
| checking, so such a language can be more flexible than
| Rust, while still maintaining the memory safety aspect.
|
| The question, as always, is: is the juice worth the
| squeeze?
|
| Truthfully, I suspect no. The Rust train has left the
| station and has a decade head start. Even if it is a pain
| in the ass, lol.
| zozbot234 wrote:
| You may be interested in Rust language proposals for
| local memory allocators and "storages"; they may be
| enough for something very much like this. The lifetime
| concept in Rust is quite close already to that of a
| "region", i.e. an area of memory that the lifetime can
| pertain to.
| caspper69 wrote:
| Depending on the semantics of the implementation,
| something like that would go a long way toward
| eliminating one of my biggest issues with Rust. For a
| low-level systems language, it is imperative to offer 2
| things, which are currently a pain in Rust: (1) you must
| be able to "materialize" a struct at an arbitrary
| location; why? Because hardware tables _exist_ at a
| specified location and are provided by hardware- they are
| not created or instantiated in the host language; and (2)
| be able to reference structs from other structs, which
| immediately triggers lifetime annotations, which begin to
| color everything they touch, must like async does to
| functions.
|
| And I admit, I loathe the borrow checker. Ironically, I
| never really have problems with it, because I do
| understand it, it's just that I find it too _limiting_.
| Not everything I want to do is unsafe, and I hate the way
| it has made people think that if you really do know
| better than the borrow checker, you must clearly be doing
| something wrong and you should re-architect your code. It
| 's insulting.
| steveklabnik wrote:
| What's old is new again. Cyclone, one of the influences
| on Rust, is a systems language using regions for memory
| management.
| another2another wrote:
| >Manual heap allocation can slow the program down non-
| trivially compared to using an arena
|
| But GC has nothing to do with whether heap allocations
| 'slow the program down', it's who owns the lifetime of
| the allocated object - for GC not the programmer, but the
| runtime.
|
| If I create a an object, and then then soon after deref
| it [MyObj release], then I _know_ it will dealloc
| immediately after. I 'm basically in control of its
| lifetime, even though it's ref counted.
|
| If I call [MyObj free] and it's still owned by another
| object (e.g. I added it to some collection), _that 's OK_
| because the object is still useful and has a lifetime
| outside of my control, and its destruction will be
| deferred until it doesn't.
|
| But, with a GC object, if I call new MyObj() and then
| soon after try my best to destroy it, I can't because I'm
| not in control of its lifetime, the runtime is.
|
| That's what I see the distinction between GC and ref
| counted (not GC), and why I mostly don't agree with so
| many people here insisting that ref counting is garbage
| collection. How can it be when I can easily be explicitly
| in control of an objects lifetime? I create it, then I
| destroy it, and it happens exactly in the sequence that I
| dictate.
|
| For sure, ARC makes it a bit more subtle, but even then,
| I can reliably predict when an object will be destroyed
| and factor that into the sequence of events in my
| program.
|
| -An Atheist.
| nemetroid wrote:
| By that definition, a C++ program with heavy usage of
| std::shared_ptr has GC.
| cmrdporcupine wrote:
| And it does. Reference counting is garbage collection.
| And std::shared_ptr, or Rust's Rc/Arc are basically
| lightweight GC runtimes inside your program.
| coldtea wrote:
| Isn't that the point?
| nemetroid wrote:
| I don't think it's the point of the comment I replied to,
| no.
| imtringued wrote:
| By this logic you're writing the garbage collector by
| hand in C.
| hansvm wrote:
| It's not a perfect analogy, but if you want to put yourself
| in the shoes of the people making it:
|
| 1. Rust is an immensely complicated language, and it's not
| very composable (see the async debacle and whatnot). On the
| simple<->complex slider, it's smack dab on the right of the
| scale.
|
| 2. Ignoring any nitpicking [0], Zig is memory-safe enough
| in practice, placing it much closer to Rust than to C/C++
| on the memory safety axis. My teammates have been using Zig
| for nearly a year, and the only memory safety bug was (a)
| caught before prod and (b) not something Rust's features
| would have prevented [1]. The `defer` and `errdefer`
| statements are excellent, and much like how you closely
| audit the use of `unsafe` in Rust there is only a small
| subset of Zig where you actually need to pull your
| magnifying glass out to figure out if the code has any
| major issues. In terms of memory issues I've cared about
| (not all conforming to Rust's narrow definition of memory
| safety), I've personally seen many more problems in Rust
| projects I contribute toward (only the one in Zig, plus a
| misunderstanding of async as I was learning the language a
| few years ago, many of varying severity in Rust, at this
| point probably more code written in Zig than Rust, 10yoe
| before starting with either).
|
| With that in mind, you have C/C++ on the unsafe axis and
| Zig/Rust on the safe axis. The complexity axis is self-
| explanatory, fleshing out the analogy.
|
| Is Zig memory-safe? No, absolutely not. Does that mean that
| Rust will win out for some domains? Absolutely. In
| practical terms though, your average senior developer will
| have many memory safety bugs in C/C++ and few in Zig/Rust.
| It's a reasonable way to compare and contrast languages.
|
| Is it a perfect description? No, the map is not the
| territory. It's an analogy that helps a lot of people
| understand the world around them though.
|
| [0] Even Python is simpler than Rust, and it's memory-safe.
| If we're limiting ourselves to systems languages, you still
| have a number of options like Ada and Coq. Rust is popular
| because it offers a certain tradeoff in the
| safety/performance/devex Pareto curve, and because it's had
| a lot of marketing. It's unique in that niche, by
| definition, but it's far from the only language to offer
| the features you explicitly stated.
|
| [1] It was just an object pool, and the (aggregate)
| resetting logic wasn't solid. The objects would have passed
| through the borrow checker with flying colors though.
|
| Edit: To your GC point, many parts of Rust look closer to
| GC than not under the hood. You don't have a GC pause, but
| you have object pools (sometimes falling back to kernel
| object pools) and a variety of allocation data structures.
| If RC is a GC tactic, the extra pointer increment/decrement
| is negligible compared to what Rust actually does to handle
| its objects (RC is everything Rust does, plus a counter).
| That's one of my primary performance complaints with the
| language, that interacting with a churn of small objects is
| both expensive and the easiest way to code. I can't trust
| code I see in the wild to behave reasonably by default.
| pcwalton wrote:
| I've been seeing C++ fans talk about how they never see
| memory safety issues in practice in C++ for a decade and
| a half. I even believed it sometimes. But if there's ever
| been a common story over those 15 years, it's that these
| anecdotes mean little, and the actual memory safety
| property means a lot.
|
| The only time I've seen "almost memory safe" actually
| work is in Go and Swift, which have memory safety
| problems with concurrency, but they're actually rare
| enough not to matter too much (though in Go's case it
| would have been easy to design interfaces and slices not
| to have the problem, and I wish they had). I simply don't
| believe that Zig is meaningfully more memory safe than
| C++.
| fweimer wrote:
| I think it's possible to retrofit race-safe slices and
| interfaces into Go, and I expect it to happen one day
| once some actually relevant code execution exploit shows
| up.
|
| There's going to be some impact and low-level libraries
| that manipulate directly the words that constitute slices
| and interfaces, and there will some slight performance
| impact and increase in memory usage, but hopefully
| nothing drastic.
| zozbot234 wrote:
| I think slices and interfaces in Go are both 2xusize
| width, in which case you just need double-width CAS to
| make them safe from data races - which most modern
| architectures support.
| fweimer wrote:
| Slices are base pointer, length, and capacity, so three
| words. But there's a garbage collector, so you can
| install a thunk if the slice is updated in a way that
| torn reads cause problems. It makes reads slightly
| slower, of course.
|
| Two-word loads could be used for interface values
| (assuming that alignment is increased), except if support
| older x86-64 is needed. There are implementations that
| require using CMPXCHG16B, which is a really slow way to
| load two words. Both Intel and AMD updated their ISA
| manuals that using VMOVDQA etc. is fine (once the CPU
| supports AVX and the memory is cacheable).
| AndyKelley wrote:
| I don't see any Zig repositories under
| https://github.com/pcwalton
|
| Is your opinion based on anything other than pure
| speculation?
|
| I think it makes more sense to form an opinion after
| actually having tried Rust, C++, and Zig in earnest.
|
| There are lots of us out there who've done it. Join us!
| FpUser wrote:
| >"I've been seeing C++ fans talk about how they never see
| memory safety issues in practice in C++ for a decade and
| a half. I even believed it sometimes. But if there's ever
| been a common story over those 15 years, it's that these
| anecdotes mean little, and the actual memory safety
| property means a lot."
|
| While I use C++ a lot I am not a fan. It is just one of
| many languages I use. But from my personal experience it
| is true. I frankly forgot when was the last time I hit
| memory problem, years for sure. And my code is often a
| stateful multithreaded backends with high request rate.
| imtringued wrote:
| Are you properly trying to exploit your own software?
|
| If you're not looking, how would you know?
|
| You could have a blatant SQL injection in your code and
| you can always pretend that it doesn't matter, since you
| haven't been attacked so far.
| jeremyjh wrote:
| Memory safety issues show up all the time outside of
| security exploits. Industry began pursuing memory safety
| long before anyone cared much about security, simply
| because of the productivity impact of chasing down memory
| leaks and use-after-free bugs. So if they've used C++ for
| years without having to do that, its pretty meaningful.
| It also matches my experience working on a large C++
| application that had ubiquitous use of smart pointers. I
| wouldn't want to do that again, but RAII takes you a long
| way.
| zozbot234 wrote:
| > see the async debacle and whatnot
|
| The async featureset in Rust is far from complete, but
| async is also somewhat of a niche. You're not necessarily
| expected to use it, often you can just use threads.
|
| > Zig is memory-safe enough in practice
|
| Temporal safety is a huge deal, especially for the
| "programming in the large" case. Where unstated
| assumptions that are relied upon for the safety of some
| piece of code can be broken as some other part of the
| code evolves. The Rust borrow checker is great for
| surfacing these issues, and has very few practical
| alternatives.
|
| > If we're limiting ourselves to systems languages, you
| still have a number of options like Ada and Coq.
|
| It's easy to be "safe" if the equivalent to free() is
| marked as part of the unsafe subset, as with Ada. Coq is
| not very relevant on its own, though I suppose it could
| be part of a solution for proving the memory safety of C
| code. But this is known to be quite hard unless you do
| take your care to write the program in the "idiomatically
| safe" style that a language like Rust points you to.
| rastignack wrote:
| > The async featureset in Rust is far from complete, but
| async is also somewhat of a niche. You're not necessarily
| expected to use it, often you can just use threads.
|
| I'm sorry but it's not true. You lose access to most of
| the ecosystem.
| Ygg2 wrote:
| > On the simple<->complex slider, it's smack dab on the
| right of the scale.
|
| Sure, but now you snuck in an Artifact of Death (in
| TvTropes sense) into your codebase. It won't kill your
| code base immediately and with proper handling it might
| work, but all it takes is one mistake, one oversight, for
| it to cause issues.
| hansvm wrote:
| I agreed with you either way, but I'm currently at a loss
| as to whether this is a for/against take on rust.
| Ygg2 wrote:
| You traded ease of writing for ease of long term ease of
| debugging, I don't think we agree.
| throwawaymaths wrote:
| even so it seems like it would eventually be possible to
| do more safety analysis for zig, if not in the compiler
| itself:
|
| https://github.com/ityonemo/clr
| emporas wrote:
| > 1. Rust is an immensely complicated language, and it's
| not very composable.
|
| It is a procedural language and as such, composition of
| functions is not implemented easily, if at all possible.
| It is a shame for sure that such powerful techniques are
| not possible in Rust, but for some people it is worth the
| trade off.
| zozbot234 wrote:
| It is implemented. But it requires quite a bit of
| boilerplate if you want to compose arbitrary closures at
| runtime (as you would in most FP languages), because that
| involves non-trivial overhead and Rust surfaces it in the
| code (see "dyn Fn trait objects" for how that works in
| detail).
| emporas wrote:
| Yes i know, i have wrote some FnMut closures muself. I
| meant, function composition should work like Lisp or
| Haskell, it should be very easy and intuitive, no
| boilerplate also. Closures in Rust, feel a lot like a
| hack compared to functional languages.
|
| The way i put it, is that Haskell is a language with very
| strict type system, while Rust has very strict type
| system, and strict scoping. Strict scopes mean that an Fn
| closure has to be different from a FnMut closure, which
| also means several other complications when it comes to
| async.
|
| This trade off is fine with me, but for several other
| people it doesn't worth it.
| zozbot234 wrote:
| There's additional boilerplate involved if you want your
| closures to keep their captured variables around beyond
| their original scope in the program; in Rust, that's
| implemented as a kind of shared ownership which involves
| Rc<> or Arc<>. FP languages rely on program-wide GC for
| this, which of course has significant overhead of its
| own.
| emporas wrote:
| Closures are definitely cumbersome in Rust, and
| Lisp/Haskell/Scala programmers use them all the time. In
| SICP for example, they translate several math equations
| to code using higher order functions and closures, and it
| is wonderful how clean the code is, and how close to the
| actual mathematics.
|
| That's what i meant it is impossible to do in Rust. From
| that point of view, Rust is a low level procedural
| language, but expressing any kind of business logic it is
| almost as high level as Haskell or Java.
|
| But if we focus on error detection, then Rust is the
| highest level of any other PL. For example Java or Python
| are too low level when an error occurs. That high level
| of error detection is paid of course, and that is by
| longer compilation times.
|
| If i had a wish though, i would wish Rust had as good
| closures as Haskell or Lisp.
| zozbot234 wrote:
| In principle you could fix any lack of syntactic sugar
| (which is what leads to the "clean code" feel in Scheme
| or Haskell - but even Swift has custom sugar of its own
| for refcounting and copy-on-write) with a custom macro -
| which would be entirely optional, triggered by a custom
| attribute such as #[sloppy_code]. But that still requires
| a lot of fiddly implementation work.
| tialaramex wrote:
| Today all of the code I'm not paid to write is in Rust. I
| spent many happy years previously getting paid to write C
| (I have also been paid to write Java, PHP, Go and C#, and I
| have written probably a dozen more languages for one reason
| or another over the years but never as specifically a thing
| people were paying me to do)
|
| I always thought C++ was a terrible idea, from way before
| C++ 98, I own Stroustrup's terrible book about his
| language, which I picked up at the same time as the revised
| K&R and it did nothing to change that belief, nor have
| subsequent standards.
|
| However, I do have some sympathy for this sentiment about
| Rust being a better C++. Even though Rust and C++ have an
| entirely different approach to many important problems the
| syntax often looks similar and I think Zig manages to be
| less intimidating than Rust for that reason if you don't
| want that complexity.
|
| Personally I had no interest in C+++ and I have no serious
| interest in Zig.
|
| + Ironically I ended up caring a lot more about C++ _after_
| I learned Rust, and most specifically when understanding
| how Rust 's HashMap type works, but I didn't end up liking
| C++ I just ended up much better informed about it.
| munificent wrote:
| Board games and craft beers are utterly unrelated objects
| who have commonality on essentially no axes (except sitting
| on tables, I guess). And, yet, if you like one, there's a
| very good chance you like the other.
|
| I think that's where the sentiment comes from. It's not
| that Rust is similar to C++ in terms of the actual
| languages and their features. It's that people who like C++
| are morely likely to like Rust than people who like C are.
|
| I would argue that C is not a minimalistic language either.
| There is a _lot_ under the hood in C. But it _feels_ small
| in a way that Rust and C++ don 't.
|
| I think Rust and C++ appeal to programmers who are OK with
| a large investment in wrapping their head around a big
| complex language with the expectation that they will be
| able to amortize that investment by being very productive
| in large projects over a large period of time. Maybe
| sometimes the language feels like trying to keep a piece of
| heavy duty machinery from killing you, but they're willing
| to wrestle with it for the power you get in return.
|
| The people who are excited about Zig and C wants something
| that feels more like a hand tool that doesn't demand a lot
| of their attention and lets them focus on writing their
| code, even if the writing process is a little more manual
| labor in return.
| estebank wrote:
| > Maybe sometimes the language feels like trying to keep
| a piece of heavy duty machinery from killing you, but
| they're willing to wrestle with it for the power you get
| in return.
|
| It's funny because to me there's an analogy with heavy
| machinery but materially different: there are some
| industrial machines that have _two_ buttons that need to
| be actuated to activate the mechanism, separated by arm
| length in order to _ensure_ that the operator 's arms are
| out of the way when the limb crunching bits are moving. I
| see Rust that way, engineering the safe way to do things
| as the path of least resistance, at the cost of some
| convenience when trying to do something "unsafe".
| incrudible wrote:
| Okay, but now imagine a kitchen appliance that did the
| same thing. It would not be a big seller. Of course a
| kitchen appliance can injure and even kill you, but it
| probably wouldn't unless you try really hard.
|
| Most of programming is like that, but in the few cases
| where there literally are lives at stake, memory safety
| by itself will not do much for you and performance is
| going to be a secondary concern.
|
| Zig does have safety features that C/C++ do not have, but
| also one should not underestimate the security
| implications of language complexity by itself.
| pcwalton wrote:
| The reason I focus on the memory safety difference is
| precisely to not minimize its importance. It's far more
| salient of a difference than whether a language "feels
| big" or not. Talking about whether Zig requires "a little
| more manual labor" than Rust is missing the enormous
| elephant in the room.
| platinumrad wrote:
| > It's far more salient of a difference than whether a
| language "feels big" or not.
|
| You clearly don't like it, but it seems many people
| disagree.
| throwawaymaths wrote:
| pcwalton is responsible for a lot of the rust borrow
| checker, so, not a neutral opinion. ive posted it too
| many times on this thread but it seems borrow checking
| analysis may be possible for zig (if the zig team should
| want to)
| pcwalton wrote:
| I highly suspect it won't be feasible for the same reason
| it isn't feasible in C++: you could technically implement
| it, but tons of existing patterns in the ecosystem would
| become impossible to express, so in practice it would end
| up creating a different language. From a skim, the CLR
| project you linked to claims that metadata will probably
| be needed in order to enforce aliasable xor mutable, and
| I agree.
| zozbot234 wrote:
| > tons of existing patterns in the [C/C++] ecosystem
| would become impossible to express
|
| Well, the really harsh way of putting this is that the
| patterns break for a reason; they rely on global claims
| about the program, so they aren't genuinely robust in the
| context of code that sits within a large, constantly
| evolving codebase that can't be practically surveyed in
| its entirety. Rust is very good at picking patterns that
| can be verified with a comparatively straightforward,
| "local" analysis that broadly follows the same structure
| as the actual program syntax. Safety claims that rely on
| "global" properties which cannot be kept within a self-
| contained, module-like portion of the code are
| essentially what the unsafe marker is intended for. And
| this is exactly what idiomatic C/C++ code often gives
| you.
|
| This is actually why I think that proposals like Safe C++
| should get a lot more attention that they do at present.
| Yes, Safe C++ changes what's idiomatic in the language
| but it does so in a way that's broadly sensible (given
| our increased attention to memory safety) especially in a
| context of "programming in the large".
| throwawaymaths wrote:
| you can go a long way before getting to aliasable xor
| mutable, and the metadata doesn't require a language
| change, theres an example in there on how to bind
| metadata with no language changes.
| munificent wrote:
| I think the people who like Rust are in a room where they
| perceive that elephant to be enormous and people who like
| Zig are in a room where they perceive it to be much
| smaller.
|
| You can certainly argue whether or not their perceptions
| are correct, but I generally believe that people are
| entitled to their priorities.
|
| Either way, you initially stated confusion about why
| people stated certain opinions about Rust, C++, and C. I
| tried to explain why people might hold those opinins. You
| are then arguing that they _shouldn 't_ hold those
| opinions. Whether or not that's true, a prescriptive
| claim is orthogonal to understanding what's actually in
| their heads.
| imtringued wrote:
| The elephant is enormous, because the C crowd is not
| living up to what they need to do to actually make the
| lack of memory unsafety unimportant. C is like ruby in
| the sense that the untyped nature of ruby might initially
| buy you a productivity win, but in the long run it
| requires you to dilligently write impeccable unit tests,
| since even the most basic correctness checks can only be
| done at runtime.
|
| Actually that's wrong. In C you will need exhaustive
| formal verification, because UB doesn't cause minor
| miscompilation anymore. Formal verification is far more
| onerous than whatever Rust is demanding.
| tialaramex wrote:
| > And, yet, if you like one, there's a very good chance
| you like the other.
|
| Among my friends I know several people who are very
| enthusiastic about board games and several who are very
| enthusiastic about craft beer, but there's not a
| particular noticeable overlap. Personally of course I am
| very into board games and I don't drink at all.
|
| > I would argue that C is not a minimalistic language
| either. There is a lot under the hood in C.
|
| Nah, C actually is small, that's why K&R is such a short
| book. It makes enormous compromises to pull that off, but
| presumably on a machine where 64kB of RAM is
| extraordinary these compromises made lots of sense. C23
| is quite a bit bigger, for example "bool" is now an
| actual type (albeit implicitly convertible) but still
| small by modern standards.
|
| There really isn't that much "under the hood", it's often
| just the least possible moving parts that could possibly
| have worked.
|
| a[b] in C++ is a call to a member function
| a.operator[](b) -- arbitrary user code
|
| a[b] in Rust is a call to core::ops::Index::index(a, b)
| or, in context IndexMut::index_mut -- again, arbitrary
| user code
|
| a[b] in C is just a pointer addition of a and b - one of
| them will be converted to a pointer if necessary, and
| then the other one is added to the pointer using normal
| pointer arithmetic rules
| hajile wrote:
| > Nah, C actually is small,
|
| I'd argue that C is much bigger than K&R, but that isn't
| immediately visible to a new programmer because it's all
| undefined behaviors.
| pjmlp wrote:
| C23 + compiler extensions versus K&R C, is a little more
| than only UB.
| pjmlp wrote:
| Except C in 2025 isn't K&R C, rather C23.
|
| Also even between C89 and C23, many folks wrongly count
| "whatever my compiler does" as C, and there are endless
| amounts of extensions to be aware of.
| voidhorse wrote:
| Exactly. There are two kinds of programmers, those who
| enjoy spending a bunch of time thinking about problems
| and decisions the language has foisted upon you
| (subtyping hierarchies, lifetime annotations, visibility,
| design patterns) and there are those that like spending
| that time thinking about the actual problem they want to
| solve instead.
|
| I jest, but only a tiny bit. The features of heavy OOP
| and feature-rich languages tend to show their value only
| in really large codebases being worked on by several
| different people--precisely because many of their
| features are just guardrails to make it hard for people
| to code incorrectly against another's understanding or
| assumptions, when shared understanding is more difficult
| to establish. Contrarily, any solo programmer or really
| small team is almost invariably better served by a
| language like go, C, scheme, or Zig.
| pcwalton wrote:
| The idea that memory safety is only, or primarily, a
| problem in large codebases written by a sizable team is
| an interesting theory (sort of an inverse Linus' Law?)
| Unfortunately, it's contradicted by decades of
| experience.
| bornfreddy wrote:
| Just to be clear, I liked memory handling in Rust. It was
| the sheer size of the language that made it... not fun.
| But borrow checker made sense.
| lenkite wrote:
| Go is pretty good for large, shared projects too - thanks
| to its tooling, formalized best-practices and
| comprehensive batteries-included standard library.
| gens wrote:
| It is not about memory safety or anything like that. It is
| about simplicity.
|
| If you say "you can't do x with y in C++" you will get an
| "yes you can, you just use
| asd::dsadasd::asdadqwreqsdwerig_hfdoigbhiohrf() with
| weaorgoiawr flag". From what I have seen from Rust, it is
| similar. I don't want to fill my brain with vim bindings..
| cough.. Rust ways of doing something. I just want to code
| my hobby game engine v7.
|
| That said, I am happy to use software written in it. Even
| though the evangelists can be really annoying.
| coldtea wrote:
| The similarity between C++ and Rust is that both bust your
| balls with complexity for programming at large. And the
| inverse goes for C and Zig.
|
| Those are the axes relevant to the parent in the context of
| their comment - not specific language semantics or core
| features.
| defen wrote:
| > There is no corresponding popular replacement for C
| that's more minimalist than Rust and memory safe.
|
| In the real world, memory safety is not all-or-nothing
| (unless you're willing to concede that Rust is not safe
| either, since unsafe Rust exists). I'm working on an
| embedded project in Rust and I'd MUCH rather be using Zig.
| The only safety thing that Rust would give me that Zig does
| not is protection from returning pointers to stack-
| allocated objects (there are no dynamic allocations and no
| concurrency outside of extremely simple ISRs that push
| events onto a statically allocated queue). But in exchange
| I have to deal with the presence of _unsafe_ Rust, which
| feels like a gigantic minefield even compared to C.
| zozbot234 wrote:
| > But in exchange I have to deal with the presence of
| unsafe Rust, which feels like a gigantic minefield even
| compared to C.
|
| I think idiomatic coding norms for unsafe Rust are still
| a bit half-baked, and this is where something like Zig
| can have an advantage of sorts. You can see this also,
| e.g. in the ongoing proposals for a Pin<> alternative.
| throwawaymaths wrote:
| protection from returning stack pointers seems to be
| detectable with static analysis of zig AIR.
|
| https://github.com/ityonemo/clr
| sesm wrote:
| > There is no corresponding popular replacement for C
| that's more minimalist than Rust and memory safe.
|
| There is Objective-C, it fits your definition of memory
| safety.
| pcwalton wrote:
| Objective-C and Swift are the reason why I added the
| footnote. (Also Objective-C is very, very much not memory
| safe.)
| vitiral wrote:
| From what I understand that language is Zig, no?
|
| Also, there's FORTH!
| wtetzner wrote:
| I don't think Zig is memory safe?
| vitiral wrote:
| I was replying to this bit
|
| > difference between C++ and C is that the former is a
| large multi-paradigm language, while the latter is a
| minimalist language. These are completely different axes.
| > There is no corresponding popular replacement for C
| that's more minimalist than Rust and memory safe.
|
| Edit: oh, I never read the last bit "and memory safe" --
| well ya, that's kind of rust's major advantage.
| bmacho wrote:
| > > I was looking for a replacement for C, but Rust is
| actually a replacement for C++. Totally different beast -
| powerful but complex.
|
| > The difference between Rust and basically any other
| popular language is that the former has memory safety
| without GC+. The difference between C++ and C is that the
| former is a large multi-paradigm language, while the latter
| is a minimalist language. These are completely different
| axes.
|
| Indeed. Let one axis be the simple/multi paradigm. Let the
| other axis be no memory management / automatic memory
| management without GC / GC. This divides the plane into 6.
| In the simple + no memory management sits C and Zig, and in
| the multiparadigm + memory safe without GC segment sits C++
| and Rust.
|
| > There is no corresponding popular replacement for C
| that's more minimalist than Rust and memory safe.
|
| Those are some weird requirements for "being a
| replacement", but it is obviously true, as you picked them
| such.
| huijzer wrote:
| I read a blog that called Rust a language that was aimed to
| be high-level but without GC.
| anacrolix wrote:
| This is actually accurate. While Rust is a great replacement
| for C, so is C++. But Rust has tons of extra features that C
| doesn't have, just like C++. Moving from C++ to Rust is a
| sideways move. Moving from C to Rust is definitely an
| increase in complexity and abstraction.
|
| Rust is a great replacement for C++ as it fits into the same
| place in the stack of tools.
|
| Go is not a C or Python replacement.
|
| Zig _is_ a good replacement for C.
| zozbot234 wrote:
| > But Rust has tons of extra features that C doesn't have,
| just like C++.
|
| C++ has tons of extra features over C because it's a
| kitchen sink language. Rust has _some_ extra features over
| C because in order to support static analysis for memory
| safety in a practically usable manner, you _need_ those
| features. In practice, there are lots of C++ features that
| Rust doesn 't bother with, especially around templates.
| (Rust just has a more general macro feature instead. The
| C++ folks are now on track to adding a clunky "metaclass"
| feature which is a lot like Rust macros.)
| pjmlp wrote:
| Every language becomes a kitchen sink with enough time on
| the market, even C, people really should learn about the
| standard and the myriad of compiler extensions, K&R C was
| almost 60 years ago.
|
| C++ already has almost Rust macros, with a mix of compile
| time execution, concepts and traits, without requiring
| another mini-language, or an external crate (syn).
| bmacho wrote:
| > Every language becomes a kitchen sink with enough time
| on the market,
|
| Sometimes they remove stuff, and then everything written
| before a specific date stop working.
| tialaramex wrote:
| > Go is not a C or Python replacement.
|
| Google stopped writing new Python, because they found that
| the same engineers would produce software with similar
| defect rates, at a similar price and in similar time, with
| Go, but it would have markedly better performance, so, no
| more Python.
|
| Go manages to have a nice sharp start, which means there
| are going to be a bunch of cases where you didn't need all
| the perf from C, but you did need a prompt start, so, Java
| was not an option but Go is fine.
|
| In my own practice, Rust entirely replaces C, which has
| previously been my preferred language for many use cases.
| xedrac wrote:
| > Moving from C++ to Rust is a sideways move.
|
| In what sense? Features or complexity? From a
| productivity/correctness perspective, Rust is a huge step
| up over C++.
| pjmlp wrote:
| While I agree, that isn't much the case for those using
| static analysis, and hardened runtimes, which provide
| much of the same safety improvements, granted without
| lifetimes tracking.
|
| Use more xcode, Clion, Visual Studio, C++ Builder, and
| less vi and Emacs for C and C++.
|
| Not everyone has the RIIR luxury for what we do.
| xedrac wrote:
| Those things certainly help, but as someone who actively
| maintains a lot of C++, I'll stand by my claim that even
| with those added tools, Rust is a very large upgrade in
| both productivity and correctness. I'm not claiming all
| C++ should be RIIR. But you won't find me starting any
| new projects in C++, unless compelled to do so.
| pjmlp wrote:
| It is, provided there are crates available for what the
| assignment is supposed to be.
|
| However C++ folks aren't standing still, and anyone
| pointing out to cargo, and not using conan/vcpkg,
| alongside a C++ aware IDE, is doing themselves a
| disservice, better be 85% there than none at all.
| pjmlp wrote:
| Go has plenty of bad design decisions, but not being a
| safer C isn't one of them.
|
| TinyGo and TamaGo folks enjoy writing their bare metal
| applications on embedded and firmware.
| superlopuh wrote:
| My experience with Zig is that it's also a plausible
| replacement for C++
| fuzztester wrote:
| explanation needed, bro.
|
| nerdy langnoob or noobie langnerd here. not sure which is
| which, cuz my parsing skills are nearly zilch. ;)
| infamouscow wrote:
| C programmers have long suffered the cumbersome ritual of
| struct manipulation--resorting to C++ merely to dress up
| structs as classes.
|
| Zig shatters that with comptime and the 'type' type.
| chongli wrote:
| Zig's comptime feature gives a lot of the power of C++
| templates. This makes it easier to implement a lot of
| libraries which are just a pain to do in plain C. Even
| seemingly simple things like a generic vector are
| annoying to do in C, unless you abandon type safety and
| just start passing pointers to void.
|
| I believe Zig even has some libraries for doing more
| exotic things easily, such as converting between an array
| of structs and a struct of arrays (and back).
| fuzztester wrote:
| >Zig's comptime feature gives a lot of the power of C++
| templates. This makes it easier to implement a lot of
| libraries which are just a pain to do in plain C. Even
| seemingly simple things like a generic vector are
| annoying to do in C, unless you abandon type safety and
| just start passing pointers to void.
|
| I get it, thanks. in C you have to cast everything to
| (void *) to do things like a generic vector.
|
| >I believe Zig even has some libraries for doing more
| exotic things easily, such as converting between an array
| of structs and a struct of arrays (and back).
|
| yes, iirc, there was a zig thread about this on hn
| recently.
| pjmlp wrote:
| Depends on which C++ version you're talking about.
| FpUser wrote:
| >"but Rust is actually a replacement for C++. "
|
| I would disagree. C++ provides way more features than Rust
| and to me Rust feels way more constrained comparatively.
| tialaramex wrote:
| Sure, in the sense that in C++ they've got the Head Of
| Vecna: https://rpgmuseum.fandom.com/wiki/The_Head_of_Vecna
|
| Many of my favourite Rust features aren't in C++. For
| example they don't have real Sum types, they don't have the
| correct move semantic, they are statement oriented rather
| than expression oriented and their language lacks decent
| built-in tooling.
|
| But also, some of the things C++ does have are just bad and
| won't get fixed/ removed because they're popular. And
| there's no sign of it slowing down.
|
| I think that _in practice_ you should use Rust in most
| places that C++ is used today, while some of the remainder
| should be WUFFS, or something entirely different.
| FpUser wrote:
| >"I think that in practice you should use Rust"
|
| I am doing fine. Thank you. Also I am not a language
| warrior. I do have my preferences but use many since I am
| an independent and work with many clients.
| pjmlp wrote:
| The biggest issue for me, is that Rust isn't used where I
| care about, mainstream language runtimes, compiler
| toolchains, and GPU ecosystem standards.
|
| No one from them would accept a patch in Rust instead of
| C or C++.
|
| Yes I know about Deno, but even them haven't rewriten V8,
| and wgpu or Rust CUDA aren't the same as what Khronos,
| NVidia, AMD, Microsoft put out in C++.
| krona wrote:
| > Rust is actually a replacement for C++
|
| Last I checked, rust touted itself as a _systems_ programming
| language, which C++ kinda is but mostly isn 't (many C++
| features just aren't appropriate or are poorly suited for
| systems programming).
|
| I would never choose Rust over C++ for scientific
| programming, because Rust metaprogramming features are so
| poor.
|
| However I'd probably choose Rust over C in many areas where C
| is best suited.
|
| So to me the venn diagram of utility shows Rust to overlap
| with C far more than C++.
| smartmic wrote:
| From what you describe, you might also like Odin.
| zoogeny wrote:
| Interestingly enough, it is one of the only "talked about"
| languages I have almost no experience with. Even Roc I've
| watched a few YouTube videos on. I've only really seen Odin
| mentioned on X, not even a HN post.
|
| I suppose there is also Jai in a similar space as well,
| although I'm not a devotee to Jonathan Blow and I don't share
| much of the excitement his followers seem to have.
|
| I do feel Zig has the current trend moving in its favor, with
| projects like Ghostty and Bun gaining prominence. I think
| Odin would need something like that to really capture
| attention.
| dismalaf wrote:
| Odin has commercial applications, basically all the JangaFX
| apps... But yeah, it's missing a killer open source app.
| Positive is it has a decent amount of batteries included.
| smartmic wrote:
| > I've only really seen Odin mentioned on X, not even a HN
| post.
|
| But there are some: https://hn.algolia.com/?q=Odin
| johnisgood wrote:
| I'm not a devotee to the creator of Odin. Odin may be fine,
| but I'm hesitant when it comes to contributing to it. Welp.
| Life goes on.
| christophilus wrote:
| I've played with Hare, Zig, and Odin. Odin is my favorite. It's
| a fair bit faster to compile (similar to Hare), and has the
| nicest syntax (subjectively speaking). I wish it would get more
| traction. Looking forward to trying Jai if it ever makes it to
| GA.
| wolfspaw wrote:
| Odin is the best (followed by Zig)
|
| Odin has the best approach for "standard library" by
| blessing/vendoring immensely useful libraries
|
| Odin also has the best approach for Vector Math with native
| Vector and Matrix types
| tialaramex wrote:
| The swizzling is pretty cool, rather special purpose but it
| makes sense that Ginger Bill wanted this and it's Ginger
| Bill's language.
|
| Odin's "standard library" stuff is very silly, it still
| feels like we were just copy-pasted the lead developer's
| "useful stuff" directory. Bill doesn't feel there's a value
| to actual standard libraries, so instead here's...
| whatever. He insists that's not what's going on here, but
| that doesn't change how it feels.
| LAC-Tech wrote:
| I don't say the "lower language wars" as being between zig and
| rust. I see it as being between old and new. And I'm on team
| new.
| gregwebs wrote:
| Go was built while waiting for C++ to compile- fast compilation
| was an implicit design goal.
|
| Rust on the other hand didn't prioritize compile times and ended
| up making design decisions that make faster compilation difficult
| to achieve. To me it's the biggest pain point with Rust for a
| large code base and that seems to be the sentiment here as well.
| pcwalton wrote:
| Rust always cared about compile times. Much of the motivation
| to switch from rustboot to rustc was compile times.
|
| (Source: I wrote much of the Rust compiler.)
| eximius wrote:
| But were any _language_ decisions discarded due to compile
| time concerns? I don't think anyone would claim the folks
| working on the rust compiler don't care.
|
| On that note, thank you for your part! I sure enjoy your
| work! :)
| LegionMammal978 wrote:
| Since at least 2018, there's been a planned upgrade to the
| borrow checker to permit certain patterns that it currently
| rejects [0]. Also since 2018, there's been an
| implementation of the new version (called Polonius) that
| can be enabled with an unstable compiler flag [1].
|
| But now it's 2025, and the new version still hasn't been
| enabled on stable Rust, since the Polonius implementation
| is seen as far too slow for larger programs. (I'm not
| exactly sure how horrible it really is, I haven't looked at
| the numbers.) A big goal of the types team since last year
| has been to reimplement a faster version within rustc [2].
|
| I'd count this as a language feature (albeit a relatively
| minor one) that's been greatly deferred in favor of shorter
| compile times.
|
| [0] https://blog.rust-lang.org/inside-
| rust/2023/10/06/polonius-u...
|
| [1] https://github.com/rust-lang/rust/pull/51133
|
| [2] https://rust-lang.github.io/rust-project-
| goals/2024h2/Poloni...
| gregwebs wrote:
| That's useful information and we are all glad that
| performance regressions aren't allowed now and there is
| work to make things faster. But that seems to be
| implementations of existing language design decisions
| rather than making language design decisions for the sake
| of compile times.
| o11c wrote:
| Yet, the whole crate model giving up on ABI stability as a
| goal hurts a lot, both for performance and for sanity.
|
| Why aren't people designing modern languages to make it
| _easier_ to keep a stable ABI, rather than giving up
| entirely?
| pcwalton wrote:
| ABI stability is one of those things that seems obvious
| ("sane"), until you try to implement ABI-stable unboxed
| generics and discover that the amount of complexity you
| incur, as well as the performance tax, is absurd. The code
| bloat with the resulting "intensional type analysis"
| actually makes the compile time worse (and the runtime far
| worse) than just specializing generics in many cases.
| zozbot234 wrote:
| The Swift folks seem to manage just fine.
| pcwalton wrote:
| The amount of complexity that Swift has to deal with in
| order to make ABI stability work is exactly what I'm
| talking about. It's astronomical. Furthermore, it's only
| partial: there are some generics in which they couldn't
| afford the price of ABI stability, so they're marked
| inline and aren't ABI stable.
| kldx wrote:
| I like Aria's writing about this
| https://faultlore.com/blah/swift-abi/.
| throwaway17_17 wrote:
| In this case (i.e. Rust specifically) what do unboxed
| generics mean. Without actually knowing Rust I don't
| think I can analogize to either type theory or another
| language. I assume if I can figure out what they are I
| infer why they are difficult to compile.
| zozbot234 wrote:
| It means ABI-stable interfaces (i.e. interfaces between
| separately-compiled "crates"/libraries, including dylibs
| and shared objects) can involve arbitrarily complex types
| with possibly nested generics, and these are implemented
| behind a _single_ pointer dereference at most. This
| requires something a lot like dyn trait object vtables in
| Rust ( "witness tables") except quite a bit more complex.
| bhansconnect wrote:
| Thank you for your work! Rust is still a great language.
|
| I think a significant portion of our pain with rust compile
| times is self inflicted due to the natural growth of our
| crate organization and stages.
|
| I still think the rewrite in zig is the right choice for us
| for various reasons, but I think at least a chunk of our
| compile times issues are self inflicted (though this happens
| to any software project that grows organically and is 300k
| LOC)
| kettlecorn wrote:
| The Rust ecosystem has long downplayed the importance of
| compile times.
|
| Many foundational crates, serde for example, contribute much
| more to compile times than they need to.
|
| I spent a long time reinventing many foundational rust crates
| for my game engine, and I proved its possible to attain
| similar features in a fraction of the compile time, but it's
| a losing battle to forgo most of the ecosystem.
| betimsl wrote:
| I think Go would have been a better choice.
| anacrolix wrote:
| absolutely not. both because it's awful for implementing
| parsers, but also it introduces lots of extra hoops for
| interop.
|
| its build system is also terrible for targeting lots of varying
| platforms and feature sets.
|
| it has a custom IR that isn't helpful interacting with other
| systems.
|
| its runtime is really nice but it's a black box and not
| suitable for interop.
| wiz21c wrote:
| I use rust a lot but, Roc is right: compilation times are not
| proportional to the safety you gain. At least in my project.
| Gibbon1 wrote:
| I had an issue where the corporate spyware thought my cross
| compiler was potential malware and running scans on every file
| access. My compile times went from a few seconds to 2 minutes.
| And my codebase has a dozen targets. Where building, fixing,
| running tests, checking in would take half and hour it now took
| the whole afternoon.
|
| I think I'd rather stick with C and run static analysis tools
| on my code when generating release candidates than have to deal
| with that.
| airstrike wrote:
| That's hardly the language's fault
| stevage wrote:
| If author is reading this, maybe worth a paragraph saying why
| you're not rewriting in Roc.
| anacrolix wrote:
| because that's hard. also it's one choice I respect them for
| not making: don't self host until you have actual users and
| momentum (unless you want to to prove a point). if Roc intends
| to have industry usage, keeping it in another language for now
| is a good move.
| bhansconnect wrote:
| Roc never plans to self host. We want roc the compiler in the
| long term to be as nice as possible for end users. A big part
| of that is as fast as possible. While roc can be fast, it
| can't compete with all the techniques that can be done in
| rust/zig/c/c++. It fundamentally is a higher level language
| to increase developer joy and reduce bugs. So it isn't the
| right tool when you are trying to reach the limits of
| hardware like this.
| teo_zero wrote:
| Like this one?
|
| > Roc's compiler has always been written in Rust, and we do not
| plan to self-host. We have a FAQ entry explaining why, and none
| of our reasoning has changed on that subject.
| bhansconnect wrote:
| https://www.roc-lang.org/faq.html#self-hosted-compiler
| mr_00ff00 wrote:
| I remember reading the HN thread when Fish rewrote to Rust. A big
| reason because "they wanted to stay current" so they rewrote from
| C++ to Rust.
|
| Someone made a joke comment how in a few years there would be
| tons of HN threads about rewriting Rust to Zig.
| sweeter wrote:
| Yay for Zig! I'm a big Zig fan. It's seemless interop with C
| makes it super fun. I really enjoy writing code in a C-style way.
| Its still got some rough edges, but its definitely super fun and
| enjoyable to write imo.
| marxisttemp wrote:
| I've been reading a lot about comptime in Zig and it's really
| cool, it unifies and simplifies a lot of metaprogramming concepts
| that normally end up being the ugliest and clunkiest parts of
| most languages.
|
| I've been immersed in Swift for a couple years after working as a
| Go programmer, and I find myself pining for a language that's
| more expressive than the latter and more concise than the former.
| nialv7 wrote:
| Whenever I see <language A> rewrites its compiler in <language
| B>, and A != B, I lose a bit of interest in language A.
| Hasnep wrote:
| Why? Roc has good reasons for not self hosting the compiler.
| nialv7 wrote:
| Well their main reason is a compiler written in Roc won't be
| performant. (And their tag line is "Roc: A _fast_, friendly,
| functional language.")
|
| So yeah, I am not interested. Plus I feel in general not
| dogfooding your own language is a bad sign.
| Hasnep wrote:
| That excludes all languages that want to write the compiler
| in a lower level language than the target language itself.
| You can easily imagine a high level language with a fast
| compiler written in C where if you rewrote the compiler to
| be self hosted the performance would drop 10-100x.
|
| Dog-fooding is important, but it can be done outside of
| compiler development. If the only code the compiler team
| writes is the compiler, they end up designing a language
| that's great for implementing compilers at the expense of
| other use cases.
| petabyt wrote:
| Fast compile times in Zig? Last time I tried it was super slow.
| Has anything changed in recent years?
| pverghese wrote:
| Compared to Rust its blazingly fast. Compared to Go compilation
| its slower.
| metaltyphoon wrote:
| Non it's not. I known its not a benchmark but just try a zig
| init and build their hello world. It takes significantly
| longer
| sweeter wrote:
| ```sh
|
| sweet@nadeko ~ $ mkcd test
|
| sweet@nadeko ~/test $ zig init
|
| info: created build.zig
|
| info: created build.zig.zon
|
| info: created src/main.zig
|
| info: created src/root.zig
|
| info: see `zig build --help` for a menu of options
|
| sweet@nadeko ~/test $ time zig build
|
| zig build 5.08s user 0.58s system 119% cpu 4.745 total
|
| # cached
|
| sweet@nadeko ~/test $ time zig build
|
| zig build 0.01s user 0.03s system 132% cpu 0.026 total
|
| # after rewriting the main function to call a function that
| takes a pointer to another function
|
| sweet@nadeko ~/test $ time zig build
|
| zig build 0.02s user 0.03s system 136% cpu 0.032 total
|
| ```
| baazaa wrote:
| think this has something to do with zig building part of
| the std which other languages ship as binaries. incremental
| compilation will remove this small overhead.
| jedisct1 wrote:
| The first time you run the toolchain for a given target, it
| compiles stuff that is then stored in a global cache.
| rererereferred wrote:
| Their x86 backend seems to be more complete, bypassing LLVM and
| allowing for fast debug builds.
| zozbot234 wrote:
| Rust has a Cranelift-based backend that you can use for that.
| bhansconnect wrote:
| It sadly helps a lot less than you would hope. A true dev
| backend can be many times faster than llvm to compile code.
| Crane lift is more like a 1.5x or 2x. Not to mention a lot
| of time is spent in the rust frontend.
| modernerd wrote:
| Last time I tried it was missing both speed and incremental
| compilation. That still looks to be the case due to no linker
| support.
|
| https://github.com/ziglang/zig/issues/21165
| sweeter wrote:
| Its honestly pretty dang good now. I can bootstrap Zig from C
| in about 3-5 minutes, and then use the self-hosted stage3
| compiler to compile Zig very quickly (under 1 minute iirc) Once
| the cache kicks in, its even faster. I guess my overall gauge
| on this is the impression I get. Zig build times never annoy me
| and I never think about it... especially compared to clang, gcc
| and Rust.
| kreelman wrote:
| The ROC webpage talks about ROC doing web servers via Rust
| libs... Behind the scenes, it uses Rust's high-
| performance hyper and tokio libraries to execute your Roc
| function on incoming requests.
|
| Will these be replaced with Zig networking libs?
| isaacvando wrote:
| Not necessarily! Each Roc app runs on a particular platform
| which is built in a host language for a specific domain. That
| host language could be Rust, Zig, C, C++, Go, Swift, etc. It's
| possible the basic-webserver platform will be rewritten to Zig
| but it doesn't need to be.
| einpoklum wrote:
| It is interesting to note an intentional choice to go from a
| "safe" language to an "unsafe" language for a program whose use
| is not without security implications (even if it's not network-
| facing).
| 3836293648 wrote:
| Maybe I need to give it another shot, but Zig was a terribly
| unpleasant language last I tried to use it.
|
| Their motivation seems to justify the decision, but I'm pretty
| sure this will scare away potential contributors. I've been
| following Roc personally, and probably will continue to do so,
| but this definitely has killed a lot of interest for me.
| 5- wrote:
| > _Zig came up with a way around this: compile directly to LLVM
| bitcode (LLVM has strong backwards-compatibility on its bitcode
| but not on its public-facing API) and then upgrades become
| trivial because we can keep our existing code generation the
| same._
|
| i'm glad that zig helps offset what i find a rather worrying
| trend -- replacing protocols with libraries (and as a consequence
| designing new underlying protocols in view of their only being
| used through the vendor library).
|
| protocols are traditionally designed to facilitate an independent
| implementation; in fact, many standards ratification processes
| require several independent implementations as a prerequisite.
|
| libraries (or worse, frameworks) intermingle the actual api with
| their own design, and necessitate a single implementation.
|
| just the other day i wanted to display a notification a linux
| desktop where it wasn't convenient to depend on a library (it was
| a game, so not a traditional application expected to have many
| dependencies). the protocol (there is one, wrapped by the
| library) is very unpleasant, but i got it working out of spite.
|
| and of course, when there is a perfectly nice protocol available
| (llvm ir, in either the bitcode or text representation) why not
| choose it? at least on unix, where starting processes and
| interprocess communication is cheap. (and as an added bonus, you
| won't crash when llvm does.)
| steveklabnik wrote:
| LLVM IR is not stable, which is a prerequisite for a good
| protocol.
| poulpy123 wrote:
| I'm not educated enough to give an opinion but I find it weird to
| rewrite in a language that is so new
___________________________________________________________________
(page generated 2025-02-05 23:02 UTC)