HNHacker News
TopNewBestAskShowJobs

shepmaster

1,167 karma · joined February 6, 2011

Cofounder of the world's first Rust consultancy[1] — we are available to help you and your company with any and everything related to Rust! We also produce the Rust in Motion video series[2] for Manning.

[1]: http://integer32.com/ [2]: https://www.manning.com/livevideo/rust-in-motion?a_aid=jgoulding&a_bid=6a993c2e

submissionscomments
shepmaster··on Apple caught off guard by AI demand for Mac Mini and Mac Studio
> What makes you think that?

Here's a leaked / rumor image of Apple servers themselves.

https://www.macrumors.com/2026/08/26/leaked-images-of-apple-...

shepmaster··on The Git history command deserves more attention
You can thank ASCIIFlow for that ;)

https://asciiflow.com/

shepmaster··on The git history command
> Haven't used --update-refs, but reading it, it should result in your third graph.

I don't think it does. I tried locally:

  mkdir test; cd test; git init
  touch a; git add a; git commit -m 'a'
  touch b; git add b; git commit -m 'b'
  touch c; git add c; git commit -m 'c'
  git checkout -b branched-feature HEAD~
  touch d; git add d; git commit -m 'd'
  git checkout main
  echo 'change' > b; git add b; git commit -m 'fix b'
  git rebase -i --root --update-refs
And ended up with this graph (`git log --graph --all`)

  * commit (HEAD -> main)
  |
  |     c
  |
  * commit 
  |
  |     b
  |
  | * commit (branched-feature)
  | |
  | |     d
  | |
  | * commit
  |/  
  |       b
  |
  * commit 
  
        a
Replacing the `git commit -m 'fix b'; git rebase -i --root --update-refs` with `git history fixup HEAD~` produces what I'd like:

  * commit (branched-feature)
  |
  |     d
  |
  | * commit (HEAD -> main)
  |/
  |       c
  |
  * commit
  |
  |     b
  |
  * commit 
  
        a
shepmaster··on The Git history command deserves more attention
I'm not sure that answers my question. That shows a linear set of branches (my-feature-v3 depends on my-feature-v2 depends on my-feature-v1 depends on main). I'm asking about the case where two or more branches fork from a common ancestor and you want to fix the common ancestor.
shepmaster··on The Git history command deserves more attention
Ah, good catch. That's more of a graphic issue and not what I was trying to express. Updated the OP.
shepmaster··on The git history command
> That last part goes further than git rebase --update-refs, which only moves refs sitting inside the range you’re actively rebasing. git history instead finds and rewrites every local branch descended from the commit (while also having an option to limit it to only the current branch).

I'm reading that to mean that when I use `git rebase --update-refs` in this situation, where I've currently checked out `D` and update `B` to `B'`:

  A ──► B ──► C ──► D  
        │              
        └───► E        
I'll end up with this state, where `E` remains untouched?

  A ──► B' ─► C' ─► D'  
  │                   
  └───► B ──► E        
(EDIT: Originally I had `E` point to `B'`, which doesn't make sense)

If I use `git history fixup`, it would also update `E` and end up with this?

  A ──► B' ─► C' ─► D'  
        │              
        └───► E'        
If that's the case, is there a way to get `git rebase` to have the same behavior? I've got decades of `git rebase` burned into my fingers at this point.
shepmaster··on The One Dollar Counterfeiter
At a Pittsburgher, I assumed it was a misspelling of “nebby”.

https://www.urbandictionary.com/define.php?term=Nebby

shepmaster··on Futurelock: A subtle risk in async Rust
> But it's not natural to do so.

I tend to write most of my async Rust following the actor model and I find it natural. Alice Rhyl, a prominent Tokio contributor, has written about the specific patterns:

https://ryhl.io/blog/actors-with-tokio/

shepmaster··on Crates.io phishing attempt
An official post about this is at

https://blog.rust-lang.org/2025/09/12/crates-io-phishing-cam...

shepmaster··on Error handling in Rust
You are quite welcome; thanks for the kind words!
shepmaster··on Error handling in Rust
You certainly can use thiserror to accomplish the same goals! However, your example does a little subtle slight-of-hand that you probably didn't mean to and leaves off the enum name (or the `use` statement):

    low_level_result.context(ErrorWithContextSnafu { context })?;
    low_level_result.map_err(|err| CustomError::ErrorWithContext { err, context })?;
Other small details:

- You don't need to move the inner error yourself.

- You don't need to use a closure, which saves a few characters. This is even true in cases where you have a reference and want to store the owned value in the error:

    #[derive(Debug, Snafu)]
    struct DemoError { source: std::io::Error, filename: PathBuf }

    let filename: &Path = todo!();
    result.context(OpenFileSnafu { filename })?; // `context` will change `&Path` to `PathBuf`
- You can choose to capture certain values implicitly, such as a source file location, a backtrace, or your own custom data (the current time, a global-ish request ID, etc.)

----

As an aside:

    #[error("failed to open a: {0}")]
It is now discouraged to include the text of the inner error in the `Display` of the wrapping error. Including it leads to duplicated data when printing out chains of errors in a nicer / structured manner. SNAFU has a few types that work to undo this duplication, but it's better to avoid it in the first place.
shepmaster··on Error handling in Rust
In addition to the sibling comment mentioning thiserror, I also submit my crate SNAFU (linked in my ancestor comment). Reducing some of the boilerplate is a big reason I enjoy using it.
shepmaster··on Error handling in Rust
> I create one error type per function/action

I do too! I've been debating whether I should update SNAFU's philosophy page [1] to mention this explicitly, and I think your comment is the one that put me over the edge for "yes" (along with a few child comments). Right now, it simply says "error types that are scoped to that module", but I no longer think that's strong enough.

[1]: https://docs.rs/snafu/latest/snafu/guide/philosophy/index.ht...

shepmaster··on Error handling in Rust
Thanks for using SNAFU! Any feedback you'd like to share?
shepmaster··on Compiler Explorer and the promise of URLs that last forever
As we all know, Cool URIs don't change [1]. I greatly appreciate the care taken to keep these Compiler Explorer links working as long as possible.

The Rust playground uses GitHub Gists as the primary storage location for shared data. I'm dreading the day that I need to migrate everything away from there to something self-maintained.

[1]: https://www.w3.org/Provider/Style/URI

shepmaster··on Show HN: Stack Error – ergonomic error handling for Rust
I hope to read through your crate and examples later, but if you have a chance, I’d be curious to hear your take on how Stack Error differs from my library, SNAFU [1]!

[1]: https://docs.rs/snafu/latest/snafu/index.html

shepmaster··on A Rust Documentation Ecosystem Review
SNAFU author here, thanks for including my crate! I’ll try to give your review a thorough read through later and incorporate feedback that makes sense.

I do have https://diataxis.fr/ and related stuff open in another tab and keep meaning to figure out how to best apply it for SNAFU.

Out of curiosity, do you recall if you also read the top-level docs[1]? That’s intended to be the main introduction, I actually don’t expect most people to read the user’s guide, unfortunately.

[1]: https://docs.rs/snafu/latest/snafu/index.html

shepmaster··on Rust’s dependencies are starting to worry me
I agree. Unfortunately, I think that a lot of the people who ask for a bigger standard library really just want (a) someone else to do the work (b) someone they can trust.

The people working on Rust are a finite (probably overextended!) set of people and you can't just add more work to their plate. "Just" making the standard library bigger is probably a non-starter.

I think it'd be great if some group of people took up the very hard work to curate a set of crates that everyone would use and provide a nice façade to them, completely outside of the Rust team umbrella. Then people can start using this Katamari crate to prove out the usefulness of it.

However, many people wouldn't use it. I wouldn't because I simply don't care and am happy adding my dependencies one-by-one with minimal feature sets. Others wouldn't because it doesn't have the mystical blessing/seal-of-approval of the Rust team.

shepmaster··on Rust’s dependencies are starting to worry me
I agree with your general point, but for this specific functionality, I’ll point out that setting environment variables of the current process is unsafe. It took us a long time to realize it so the function wasn’t actually marked as unsafe until the Rust 2024 edition.

What this means in practice is that the call to invoke dotenv should also be marked as unsafe so that the invoker can ensure safety by placing it at the right place.

If no one is maintaining the crate, that won’t happen and someone might try to load environment variables at a bad time.

shepmaster··on Matt Godbolt sold me on Rust by showing me C++
Yeah, with SNAFU I try to encourage people going all-in on very fine-grained error types. I love it (unsurprisingly).
shepmaster··on Writing C for Curl
> [Rust and C++] encourages creating a library of types with inheritance

You'll want to expand on and clarify your meaning here, as Rust does not have inheritance.

shepmaster··on My Browser WASM't Prepared for This. Using DuckDB, Apache Arrow and Web Workers
Yep, as the sibling said, it’s to prove the point in a snarky manner. The yellow-on-white color, the wobbling, upside down path of text, the font choice, the unrelated image; all of these serve to make the concept actively hard to process.

Hopefully this sparks a little “wow I wonder if my image of text was also hard to read like I just experienced” moment.

shepmaster··on My Browser WASM't Prepared for This. Using DuckDB, Apache Arrow and Web Workers
We made this to be used as a reply when pictures are misused where text would be better:

https://fewer.pics/

shepmaster··on Just write a test for it
Agree with simonw’s sibling comment. To add to it, I’m the primary maintainer of the Rust playground and basically self-review every single commit.

The rust-lang/rust repository has higher scrutiny (in part driven by tools like bors, the subject of the article).

shepmaster··on Muons used to test the condition of a road bridge in Estonia
That is a use of https://en.wikipedia.org/wiki/Weathering_steel, actually!
shepmaster··on Cot: The Rust web framework for lazy developers
Discussed three days ago:

- https://news.ycombinator.com/item?id=43089468

shepmaster··on Error Stacking in Rust
This is one of the things I like about SNAFU: it makes this preferred pattern the default and makes it nicer to use. For example, your usage would look something like this with SNAFU:

    create_dir(path).context(CreateStagingDirectorySnafu { path })?;
Note a few points:

1. No need to use the closure

2. No need to carry the source error over yourself (`context` does this for you)

3. No need to explicitly call `clone` on the path (`context` does this for you)

shepmaster··on Error Stacking in Rust
When presented with a bug from the field, I also care about finding the path through my code where it occurred, but rarely do I need to know that `foo` called `foo_with_caching` called `foo_with_caching_recursive`. When reading a backtrace, I skip over amounts of "implementation details" to get a big picture. For me, the exact functions / files / line numbers are not relevant, doubly so if I'm working in a situation where the error message isn't tied to a specific git commit and the functions/files/lines have moved over time.

To reiterate my point from above though, my error stacks are all unique — seeing the stack will point me to an exact line in my code where the error occurred, even though I don't include function/file/line as-is.

shepmaster··on Error Stacking in Rust
I don't think you need a lint. When you define the error type returned by `handle_request`, you decide how the error type returned by `handle_request` will be incorporated. If you've decided to implement `From` then you've decided you don't want/need to add context. Otherwise, the compiler will give you an error when you use `?`.

The time I can think this won't work is when you are reusing error types across places. Recently, I've been experimenting with creating a lot of error types, so far as one unique error type per function. I haven't done this for long enough to have a real report, but I haven't hated it so far.

shepmaster··on Error Stacking in Rust
Without deeply looking into it, I'd expect that to integrate with SNAFU, you could basically write something like this:

    struct SpanTraceWrapper(tracing_error::SpanTrace);
    
    impl snafu::GenerateImplicitData for SpanTraceWrapper {
        fn generate() -> Self {
            Self(tracing_error::SpanTrace::capture())
        }
    }
And then you can use it as

    #[derive(Debug, Snafu)]
    struct SomeError {
        #[snafu(implicit)]
        span_trace: SpanTraceWrapper,
    }
This will capture the `SpanTrace` whenever `SomeError` is constructed (e.g. `thing().context(SomeSnafu)` or `SomeSnafu.fail()`.
Page 1 of 9Next →