My attempt at GNU echo in rust

Hi everybody!

This is my first post. I am trying to learn Rust and I recently finished reading the Rust Book.

For further learning i decided to try to reimplement some GNU core utilities in Rust.

This is my approach to echo.

I tried to incorporate feedback of other reimplementations of echo. So for my version i tried:

  • not use crates
  • to not allocate the data to a vector, and to not consume the Iterator until the output.
  • still implement option flag, although this gave me substantial headache with borrowing rules.

My questions:

  • i am sure the Overhead of using a vector is minimal in this case, still i wanted to learn about the functional programming approaches rust has to offer with Iterator

  • At any Point in my code? Do i allocate data that is not needed? for example by defining the content variable?

  • is there a more elegant solution to using the boolean variable backslash_escapes, which i capture in the closure of the find_flags method?

  • if i read the book correctly RefCell has an overhead in enforcing the ownership rules at runtime. Is this CPU overhead? Is it still worth not collecting the Iterator in a Vector?

  • Am i overcomplicating things? Or is an approach like this useful when working with larger amounts of data?

i appreciate every roast, criticism and comment!

1 Like

I'm not sure that's a realistic expectation. A lot of useful functionality in Rust is in external crates, which are intentionally not part of std so that they can evolve freely, without the pressure of maintaining backwards compatibility with potentially subpar APIs forever.

In particular, you would most definitely be better off using clap derive macros for parsing command line arguments, instead of the current, hand-rolled, ad-hoc one (which isn't even correct, e.g., it doesn't handle the -En case).

That doesn't heap-allocate, and defining a variable is merely a syntactic thing. Unnamed temporaries occupy just as much stack space as named variables. You can't save any memory by not giving names to values.

For a simple utility such as echo, it's completely pointless to worry about this level of optimality. RefCell's overhead is checking a reference count, which entails loading a single integer and a single branch, practically on the order of 2 CPU instructions. Performing I/O to standard output easily dominates any such "overhead".

You certainly are. I don't get what the RefCells are for, for example. They don't seem to be necessary at all. Trying to avoid allocations is weird, too: your operating system will already perform allocation in order to pass the arguments, so if your content doesn't fit into memory when allocated by Rust, then neither will it fit when allocated by the OS in the first place.

Your code can be re-implemented in 70 lines.

5 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.