Discussed on HN here - https://news.ycombinator.com/item?id=42535217 (906 points, 198 comments).
Highlights of the rewrite
- 1155 files changed, 110247 insertions(+), 88941 deletions(-) (excluding translations)
- 2604 commits by over 200 authors
- 498 issues
- Almost 2 years of work
- 57K Lines of C++ to 75K Lines of Rust 5 (plus 400 lines of C 6)
- C++–
> A lot of the increase in line count can be explained by rustfmt’s formatting, as it likes to spread code out over multiple lines [...] The rest is additional features. Also note that our Rust code is in some places a straight translation of the C++, and fully idiomatic Rust might be shorter.
Since there are quite many contributors, it can be difficult to introduce some advanced macro requirements for the project, which could reduce the code.
Having to handle every case of every branch also probably balloons line count.
Efficient LOC is not a goal of rust at all anyway.
I do plan to add something similar to Clojure's spec though, so the compiler can at least be advised about things and warning if stuff is missing.
But I do agree, any statically typed language should have that check and not just warn about it. It should be a hard error, no questions asked. And I love that Rust didn't relegate it to a warning that could be turned be into an error.
Also, here's a code size tracker that counts tokens not lines, which is a better measure: https://github.com/rrethy/tcount
I am no rust programmer though, and I don't think the rust code was very idiomatic.
But then again I apparently write c++ like a common lisp programmer...
Stylo was tried twice in C++ before the Rust attempt, and it never worked out, because the threading was too hard to get right. In theory you could have done it. But in theory, theory and practice are the same, but in practice, they’re different.
But for the end product, I err on the safety side for sure.
("a few" might be off by pre-pandemic amount of years, my memory is a bit fuzzy there)
It's progressed in the sense of like, the Unsafe Code Guidelines and opsem teams are hammering down the exact semantics still, and have made a lot of progress. I'm not aware of any actual optimization work taking place off of it yet, which would make sense given that it's not all fully hammered out yet.
I also might have been handwaving towards how restrict kept having to be turned off because it was broken, meaning very few C or C++ codebases seem to use it at all, whereas virtually every Rust reference has it on. It's been back on for a while now.
Thank for the general update! I might not write any Rust code myself, but I do enjoy quite a few programs written in it, so I was hoping to hear there was more progress for the sake of the developers behind those programs. But I can also imagine that these kind of things take time to figure out properly, to avoid repeating mistakes of previous languages (and that's before we even get to the task of implementing anything).
Wish the people working on these issues all the best, and looking forward (from the sidelines) to what eventually comes out of it!
For example, most Rust projects use clap which provides really nice command line help menus and also have relatively good performance in general.
Well, actually, it was the OP who said, literally, that "the most interesting thing about Fish (...) will be that it is now written in Rust"
It’s true that dependencies from a repository only supports git right now.
Part of the issue there is just like, the VCS integration wasn’t don’t in a principled way (it happens!) and so it’s not simple. See here for more: https://github.com/rust-lang/cargo/issues/12102
and this is why i really loathe language package managers, because they're prone to this kind of thing. assuming one has no problems with the opinions made in a language itself, when it has a tightly bound package manager embedded into it's ecosystem (using rust without cargo is like pulling teeth) you have an entire extra hurdle of far more rigid and controversial opinions to deal with.
package managers are maybe next to shells with "it's several orders of magnitude harder to make a good one than it is to write a compiler." with the dozens, possibly hundreds of package managers i've touched over the years, there's only been one that i'd call "good". the absolute worst ones have always been language package managers. at this point i've basically written off the concept, even system package managers.
i don't think it's reasonable to assert that my own quirks and tastes are explicitly tended to. and that's why ideally you just give the programmer space to do whatever, hence why it's so hard. vcs is just one single point of contention. this isn't unique to rust by the way. cargo is arguably a bit better than the dune experience, it's a bit more flexible and feels simpler.
arguably system package managers are better here, since they're effectively opt-in by choosing what distribution of what operating system you use. language package managers don't have that luxury.
So the lack of darcs isn’t because the Cargo folks think it’s bad or something. Just that things don’t get added just because.
Re quirks, sure, that’s why rustc and cargo are different. You don’t have to use Cargo. Meta does not, the Linux kernel does not.
ideally it'd just have an interface you can write a module against. maybe they've added that? i sure hope they didn't have to hardcode the options of that new vcs switch ;)
> that’s why rustc and cargo are different
indeed. but rust analyzer really likes you to use cargo. i know it provides facilities for specifying a json in place of cargo.toml, which is great, but my limited experience with that saw me running into some weird issues (maybe they've been fixed, maybe it was just a skill issue.)
also i will say cargo does at least let you specify local paths as dependencies relatively painlessly, so it gets points for that escape hatch.
Maybe! This is how Meta uses RA, and they sponsor development, and I know at least one of the people working on it and he really cares about getting things right, so if you run into it again, you should open up an issue.
I find this quite impressive, that they rewrote the whole Fish core, but everything keeps working exactly in the same way (except very few minor things which change in only minor ways, which they list).
Basically, the terminal will replace each line of the pasted text that match (start with)
$ rest
with pbash 'rest_escaped'
or more elegantly \$ 'rest_escaped'
We will then define a function with either of these names in fish.This function will start (if not exists) a persistent background bash instance connected on both ends to FIFOs, with the same lifetime as your fish session. We then pass the `rest_escaped` to one FIFO, capture the output from the other FIFO, and echo it.
Because its a persistent session, stuff you copy that makes use of variables or bash aliases all Just Work. Being able to blindly copy-paste the entire bash codefence from a github readme.md is especially nice.
It all happens automatically after a one-time setup, and overall works pretty well for me. Here is a demo: https://i.imgur.com/HdqGkRk.png
This is the fish function
function \$
if not test -f /tmp/bash_daemon.pid; or not kill -0 (cat /tmp/bash_daemon.pid) 2>/dev/null
echo "Starting bash daemon..."
bash ~/scripts/bash_daemon.sh &
sleep 0.5
end
echo "$argv" > /tmp/bash_daemon_pipe &
while read -l line
if test "$line" = "###DONE###"
break
end
echo $line
end < /tmp/bash_daemon_out
end
And this is the bash script `~/scripts/bash_daemon.sh` #! /usr/bin/env bash
rm -f /tmp/bash_daemon_pipe /tmp/bash_daemon_out
mkfifo /tmp/bash_daemon_pipe
mkfifo /tmp/bash_daemon_out
echo $$ > /tmp/bash_daemon.pid
while true; do
read cmd < /tmp/bash_daemon_pipe
{ eval "$cmd"; echo "###DONE###"; } > /tmp/bash_daemon_out
done
Biggest drawbacks for me is mixing up a few bits of syntax and some software doesn't ship Fish completion scripts, although I never write scripts in Fish which reduces the syntax I actually use.
In my opinion Fish is worth it just for the auto complete suggestions alone, but I also really like the way it handles editing config, it's sane default config, understandable error messages, and plug-ins.
Nushell is very nice, but I find it doesn't match the usability of Fish for interactive shells. Love it for scripts though.
I switched to fish because for most interactive use case it’s so much better, without requiring any new muscle memory. I tried zsh at first but it winds up slow to get even close to where fish is out of the box. I still end up scripting in bash or sh for portability.
nu-shell won’t be available in as many places, and it looks to me like it would change paradigm in a way that would hinder working with bash or zsh over time. That’s just my 2c though as I have only briefly glanced at it and haven’t truly considered using it.
I also prefer fish's scripting syntax (and built-in utilities) over bash, and some people don't like installing fish to run my scripts.
Nushell is far from fish in terms of interactive usage, and I find the scripting language to be too unstable for writing scripts you want to keep in the medium term.
> warning: Could not set up terminal for $TERM 'xterm-ghostty'. Falling back to hardcoded xterm-256color values
Everyone wanted something better and each person had an idea of what better was.
bash became quite common because it's a superset and its' offered by GNU whose other tools made up for many other deficiencies in the various commercial UNIX implementations.
Then FreeBSD and Linux made GNU stuff the default and that was a big boost.
I tried fish couldn't really be bothered to persevere. A lot of the things I didn't like about bash were because I hadn't understood various bits and the more I know the more I find it fairly powerful and it has a kind of consistency. I don't love it but I found myself suddenly disempowered with things like fish.
If you experience the `shell` of FoxPro DOS or other tools you will see how poor are the ones we tolerate now. Is like we still live in the age of `ed`.
(I even remember one of this projects have the joke that is finally a `terminal for the 90s!` or something like. Shells in common use a very poor things!)
Have you read Jef Raskin's The Humane Interface? It's an explainer and retrospective for his Canon Cat.
I want more of that foundation, vision, concept.
With the recent renewed interest textual user interfaces (TUIs), maybe this cycle we'll tact a little closer to that utopian future perfect omni-shell.
https://en.wikipedia.org/wiki/The_Humane_Interface
https://en.wikipedia.org/wiki/Canon_Cat
https://en.wikipedia.org/wiki/Jef_Raskin#Pioneering_the_info...
--
And another thing (I say curmudgeonly)...
bash (and csh), the progenator of all modern shells, is just one realization.
Iteration and refinement are double awesome. We're seeing crazy awesome new variants, like Warp.app, oil shell, fish, and so forth. Yea for evolution!
But I would also hope today's youngsters take a moment to review the genesis of all the modern ideas we now take for granted. From memory, in no particular order:
Engelbart's Mother of All Demos
Raskin's original vision for Macintosh
Nelson's Xanadu
Higgins art philosophy of "intermedia"
Xerox PARC
cybernetics
Atkinson's HyperCard
etc.
The founders had motivations, insights, and ideas. Necessarily limited or ignored by feasibility. It's worth understand their ideas directly, for better or worse, not just thru subsequent intepretations.With 60+ years of progress and gestation, surely there are even more tangents worth exploring.
The rest of Fish features that are not bash-compatible are rather a pain, particularly environment variable management. In principle these features have a better design than in bash, but not that much better, and their use is infrequent enough to have to re-learn them every time. Unfortunately, they just end up being a minor inconvenience when you try to copy-paste setup instructions from docs, and I don't interact with these features otherwise.
If you only want to use Fish for the autocompletion though, you can! Bash is always still there alongside Fish, you can just open a Bash shell when you're copypasting instructions, or `bash $SCRIPT` any scripts.
It's just that I never find myself needing to do anything fancy in the command line. I just want it to be fast, ergonomic, beautiful and unobtrusive.
And I wouldn't say it's because my workload is any simpler, I'm a relatively senior computer engineer working on large-scale data engineering, LLMs, non-trivial webdev and some systems programming in Rust. And it's not because I use UIs more often either, I use the command-line as much as anyone.
I guess that I have more of a "RISC" approach to the command-line.
It's also much easier to write your own completion scripts than for bash. The syntax is relatively sane, although fish completion scripts are much cleaner than bash or ZSH.
Stick to plain ZSH to avoid losing performance on bloated mess like oh-my-zsh, add fzf to quickly dig through history and find files/directories, and it's really the best option we have.
I've been using fish as my primary shell for a couple years, primarily for the autocompletion. I started off with some zsh plugins that made the shell TOO fancy (and slow). I'd really like to see it be compatible but with some compelling improvements, rather than having them be just incompatible. Every time I can't do $() or fi... But for anything slightly complex I'll drop back down to bash rather than figure out the fish way to do it, because those things are rare enough that I have a hard time keeping them in my head.
I guess I could ask an LLM how to do it in fish, but for things that I already have stuck in my head it's just easier to drop to bash.
It's a hard sell.
I'll take the better syntax, thanks.
I'm not saying these are hard things, to figure out. I just agree that they're hard to remember when you don't use them all the time.
https://github.com/ookiineko-cygport/rust
There have been discussions about adding the target to Rust, but they have not been pursued:
I'll have to check later today what now the default `cancel-commandline` is set to.
The C++ version (3.7.1) has 55k lines of C++, builds in 1m8s, and the binary is 2.4 MB.
Both were built with CMake with default settings on a MacBook with M1 Pro.
So, the new binary is 1.8x in size and takes 1.4x of the time to build.
- fish 4.0.0 / Rust: (cargo build): 16 seconds
- fish 4.0.0 / Rust: (cargo build --release): 37 seconds
- fish 3.7.1 / C++: cmake ..: 10 seconds + make -j8: 13 seconds = 23 seconds
So yeah, C++ was slightly faster in release mode, but slower in non-release. I'd say this is yet another win for Rust, frankly.
Apparently no one around here has a sense of humor, though, since my original post was heavily downvoted. I greatly prefer Rust over C++, but "rewrite it in Rust" has become kind of a meme. And if you can't laugh at yourself, who can you laugh at?