1,872 karma · joined December 2, 2015
Building CAD at Zoo.dev. Previously Cloudflare (Tunnel, Zero Trust, Data Loss Prevention).
https://blog.adamchalmers.com
https://twitter.com/adam_chal @adamchalmers.com on Bluesky
EDIT: Actually I'm guessing a lot of it comes down to encoding the HTTP responses, now that I think about it.
This is much easier than trying to design the entire parser on a whiteboard/paper and implement it in one big go, I think.
I think Nom might be more useful as the format gets more complicated... the combinators can really save you quite a bit of time. Having things like many0, or delimited_pair, or length_count already tested and documented saves time compared to implementing + testing it yourself. It's cool seeing how many different approaches you can use to solve the same problem :)
I am the sole engineer on a new team at Cloudflare, and I'm looking for a coworker! It'll be 90% Rust, 10% Go. Prior experience with Rust, distributed systems or network protocols is a big plus, as is working in a US timezone (currently both myself and my manager are based in the US). We're building ambitious software that will keep customers' data safe at high scale.
Full-time work only, no part-time/casual unfortunately.
JD: https://boards.greenhouse.io/cloudflare/jobs/3812886?gh_jid=... Please email achalmers@cloudflare.com
Nom is good for protocols where you need to know the schema in advance. E.g. a binary key-value store, where the binary in the key and value has to be deserialised into some special rules.
Nom can also handle bit-level parsers very easily. It's easier to use the parsers in nom::bits than remembering all the bit-shifting tricks I haven't used in five years.
But I'm not an expert on Serde, I suspect it can do bit-level too. I've never written my own Serde library, I just use crates like serde-json.
Someone used Nom for Advent of Code last year and found "The regex approach benchmarked at about 1ms while the parser approach benchmarked at 145 nanoseconds." [2] Maybe I'll try benchmarking Nom vs. regex for a follow-up post.
I find regexes are easier than parser combinators for simple tasks. If the problem is small, parser combinators are overkill. But if the problem gets complicated, I think parser combinators are more readable. You can break a parser combinator into small, well-documented, well-tested parts more easily than a big regex. But I still use regex more in my work, because most complex parsing I just throw into serde.
[1] https://github.com/Geal/nom
[2] https://www.christopherbiscardi.com/advent-of-code-2020-in-r...
If you're interested in some concrete examples of using const generics to write faster code, my post on them is here: https://blog.adamchalmers.com/grids-2/
In some languages and frameworks, I might need to share an object between threads to do this efficiently. In Rust there are other options, e.g. using Arc or a reference or moving the object into a task. In my years of programming Rust I've never wanted to share some object on a thread, because there are frameworks and libraries (Actix-Web, Tokio, Rayon, async-std, others) that give me a higher-level abstraction for doing this.
I can understand using this as a point of comparison if you're not very familiar with the language. But I have to confess that in my three years of working with Rust, I've neer had to worry about threads. I've been able to use a library to solve my concurrency or parallelism problems so that I can go back to worrying about design or reliability concerns.
This won't be everyone's perspective, after all, someone has to write those libraries. But it is mine, and I think users of such libraries far outnumber authors of such libraries.
The problems the author is describing might apply more to library authors, but for the many Rust programmers like me who are trying to solve problems, not write a framework, async is easy and practical.
I write Rust code for my day job, and I frequently use map/reduce/filter. IMO if I can write all my collection-processing code using primitives like that, it's got first-class functions.
I feel like this is a classic case of "tree falls in a forest, does anyone hear it?" where the confusion relies on the word "hear" being used in two ways (objective sound waves travelling through air, vs subjective perception). Is the word "own" being used in two ways here?
ripgre's source code files appear to be between 1/3 and 1/2 unit tests, in the few samples I checked. For example, https://github.com/BurntSushi/ripgrep/blob/master/crates/sea...
I've basically traded away some nice abstractions (functors, monoids etc) for the ability to debug error messages more easily, and not have to convince people to learn/support an obscure language. Good deal IMO.
At a more specific level, I think this is very useful for thinking about programming language communities and how they affect behaviour.