Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

  trait Handler {
    fn handle<'a>(&self, input: &'a str) -> Result<&'a str, HandlerError>;
  }

  fn process_handler<'a>(
    handler: Box<dyn Handler + 'a>,
    input: &'a str,
  ) -> Result<&'a str, HandlerError> {
    handler.handle(input)
  }




That's just a weird and unrealistic example, though. Like, why is process_handler taking an owned, boxed reference to something it only needs shared access to? Why is there an unnecessary 'a bound on handler?

In the places where you need to add lifetime annotations, it's certainly useful to be able to see them in the types, rather than relegate them to the documentation like in C++; cf. all the places where C++'s STL has to mention iterator and reference invalidation.


LLMs LOVE to write Rust like this. They add smart pointers, options and lifetimes everywhere when none of those things are necessary. I don’t know what it is, but they love over-engineering it.

As a first guess, they're trained on lots of social media and Q&A content. The former has lots of complaints about "look how complex rust is!" while the latter has lots of "help I've written very complex rust".

I agree that the signature for process_handler is weird, but you could steelman it to take a borrowed trait object instead, which would have an extra sigil.

The handler function isn't actually unnecessary, or at least, it isn't superfluous: by default, the signature would include 'a on self as well, and that's probably not what you actually want.

I do think that the example basically boils down to the lifetime syntax though, and yes, while it's a bit odd at first, every other thing that was tried was worse.


> The handler function isn't actually unnecessary, or at least, it isn't superfluous: by default, the signature would include 'a on self as well, and that's probably not what you actually want.

To clarify, I meant the 'a in `Box<dyn Handler + 'a>` in the definition of `process_handler` is unnecessary. I'm not saying that the <'a> parameter in the definition of Handler::handle is unnecessary, which seems to be what you think I said, unless I misunderstood.


Ah yes, I misunderstood you in exactly that way, my apologies.

Lifetimes really only come into play if you are doing something really obscure. Often times when I’m about to add lifetimes to my code I re-think it and realize there is a better way to architect it that doesn’t involve them at all. They are a warning sign.

now show me an alternative syntax encoding the same information


There's a deeper connection there: lifetimes are a form of type variable, just like in OCaml.

While I don’t disagree that this is at first blush quite complex, using it as an example also obscures a few additional details that aren’t present in something like python, namely monads and lifetimes. I think in absence of these, this code is a bit easier to read. However, if you had prior exposure to these concepts, I think that this is more approachable. I guess what I’m getting at here is that rust doesn’t seem to be syntactic spaghetti as much as it is a confluence of several lesser-used concepts not typically used in other “simpler” languages.

Could have thrown a few uses of macros with the # and ! which threw me off completely while trying to read a Rust codebase as a non-Rust programmer.

> > really extreme use cases with lots of lifetime annotations and generic bounds

You choose as your example a pretty advanced use case.


Yeah, because if you exclude the bits that make Rust look like Perl then it won't look like Perl!

Which is the exact use case someone would choose rust for over other languages

No, the use cases of Rust are pretty much the same as the use cases of C++. Most Rust code shouldn't have objects with complicated lifetimes, just like most code in any language should avoid objects with complicated lifetimes.



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

Search: