Kudos though, and great work! I can tell you put a lot of thought and effort into it.
The ubiquitousness of bash is among the few reasons why it continues to endure. It will be eternal if nobody tries to replace it.
Bash maintainer actually implemented the library feature I suggested and it's already dramatically cut down the amount of unsightly bash code I need to keep around and maintain.
I'm getting pretty tired of coping with old stuff just because it's there though. Went through this phase with GNU make too.
Doubt. I'm up to my neck in bashisms, and I require the very latest bash on top of that.
import() {
local f
for f in "$@"; do
[[ -v loaded[$f] ]] && continue
loaded[$f]=1
source -p "${HOME}/.local/lib/bash" "${f}"
done
}
import arguments terminal
The -p flag for source landed in bash 5.3.mixing shells is not as hard as some people claim. it's like switching programming languages. i do that all the time. but then, i avoid bash scripting as much as i can (or shell scripting in general). if you actually enjoy bash scripting then switching may be harder.
Fish scripting is limited to functions/aliases and this works out well since they're easy to read and tweak over time.
before fish basically noone dared to break bash compatibility. zsh is bash on steroids and other incompatible shells like csh, tcsh, ksh, etc were dead ends in that they kept a niche status.
fish was the first shell to break out of that and actually get noticed and gain a following. i believe that all other alternative shells after fish were encouraged only because of fish's popularity.
I went the same way with simply bumping up my bash skills.
Part of me feels like I'd prefer pry loaded with a library that provides shell like methods for doing ruby-esque things.
A random example:
https://github.com/amatsuda/rubish/blob/master/lib/rubish/pa...
Where are the interface boundaries? Why are there methods that are 200 lines long? This is not a dis at the author, and it's not really about "code quality" per se, whatever that means. It's just that if someone would like to study the code and be able to improve it or add features, how would one go about it? Does this mean you have to use a coding agent in order to contribute? I felt the same about the recent Ruby compiler from matz [1]. The code looks impenetrable. What does this bode for the future of OSS?
Tbh that sounds like quite a lot of codebases from single developers rather than teams I've tried to look at over the years long before LLMs were a thing, and not specifically just for one language (although when it's in a dynamically-typed language it certainly increases the difficulty). Probably quite a lot of training code for LLMs was like this (the people who trained it have access to basically the entire set of code that I did, after all), and the way to avoid it is basically the same: someone has to just care enough to either not write it like this in the first place or take the time to fix it.
As someone who's for a while been a hardline "both developers and users of open source owe each other nothing" advocate (other than the basic human respect that I believe we all owe each other, and that's not specific to open source), I don't really see LLMs as fundamentally changing that calculus. People will create open source, other people will decide to use it or not, maybe to try to contribute back or not, and the maintainers will decide to include those contributions or not, maybe someone decides to fork it, or write a replacement for it because they can't stand the choices or the code of the original, and all of that is basically how things are supposed to work. The system isn't perfect, but I'm not sure what the alternative would be, because putting any further obligations on either side would create worse problems than the ones they solve.
(Some people will choose not to release the source code for their projects instead, and that's fine too, even if in the long run I'm sometimes sad at the result of "this thing that I'd like to run doesn't really support being run in the way I want, and the author is long gone and probably wouldn't even be inconvenienced by my own personal modifications that I don't have any need to distribute". Lots of people will make choices that I wouldn't personally make, but that doesn't inherently make them bad, because other people understanding the rationale is not a particularly good measure of whether something should be allowed or not compared to, like, whether you're actually hurting anyone by doing it).
In my day - I think it was around 2000 – I was handed a 5000 line perl script that both responded to CGI bin requests to run a store and kicked off fulfillment of the orders. Inside that script, it had two 1500 line long subroutines that sometimes navigated internally via goto.
We refactored, and added new features while a profitable business ran on top of the code. You don’t get quite the velocity you do on good code, but it’s manageable.
I’m usually trying to find the smallest practical change to accomplish my goal: giving them less to review / consider, and keeping the architecture close to their preferred style.
Maybe that changes in the AI coded future
This is a language that explicitly sacrifices important stuff like the strength of automatic checks possible and performance in lieu of developer ergonomics. Even if you support that particular choice, chosing the language when you won't be writing or reading most of the code is a pretty poor tradeoff.
I actually find, for some reason, that LLMs seem to be able to be more "creative" when it comes to Ruby (having used LLMs across 4-5 languages). I don't mean hallucinating, but crafting solutions I would not have thought of, even if I've ensured that I've inserted my original thinking at the beginning.
I wonder if there is something about the combination of the expressiveness of Ruby and the way LLMs are closely tied to human language that brings that out. Of course, usual caveat: n of 1 on my own experience, and a dose of bias.
There are indeed so many compelling arguments against using Ruby these days (e.g. performance, type safety, an increasingly small user base), & yet I continue to reach for it because of this effortless expressiveness (& the maturity of the ecosystem).
I know the bot's not sophisticated enough to metaprogram anything, it writes straightforward code that's easy enough on the eyes, if not to my standards of style.
The idea is eventually I want to build the tooling to where I can actually start writing code again. That code will be ruby.
Testing anything in Ruby is dead simple, and agents are very good at writing the tests.
The REPL is also a big win for agents. Reproducing a bug, or exploring how to build a feature, agents can get a lot of mileage out of a rails console.
A lot of the developer ergonomics are just as helpful to agents.
The performance of Ruby sucks, though.
I think this will improve, but I also think your comment is important for people using agents to read. Speaking for myself, I want people like you to be able to read/understand/contribute to my projects should you desire, so this is a great reminder for me.
I would love to see more interpreted languages offer shells with native constructs for operating as daily drivers shells (not just REPLs). When I first started learning Ruby I used `rush`[0] as my main shell. Being immersed in the language, even if there were a few helpers for shell operations, really helped me reason better about Ruby and think in the language. `scsh`[1] was enlightening as well. Ultimately the ergonomics of both pushed me back to more conventional variant but they were really helpful learning mechanisms.
0: https://github.com/adamwiggins/rush 1: https://github.com/scheme/scsh
Think about what it would take to write this in Python right now:
for wmv_file in $(find $1 -name '*.wmv'); do
echo -n "${wmv_file} "
ffmpeg -i $wmv_file ${wmv_file%.wmv}.mpg 2>&1 | grep kb/s: || echo "ERROR $?"
done
With a few handy variables and functions predefined, this could be something like: for wmv_file in find(argv[1], glob="\*.wmv"):
print(wmv_file, end=" ")
result = do("ffmpeg", "-i", wmv_file, basename(wmv_file, ".wmv") + ".mpg")
if result: print(grep(str(result), "kb/s:"))
else: print("ERROR", result.status) for wmv in Path(sys.argv[1]).rglob("\*.wmv"):
print(wmv, end=" ")
r = subprocess.run(
["ffmpeg", "-i", wmv, wmv.with_suffix(".mpg")],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
)
lines = [l for l in r.stdout.decode().splitlines() if "kb/s:" in l]
print("\n".join(lines) if lines else f"ERROR {r.returncode}")
?If you go outside stdlib you can use the sh library instead of subprocess.run.
Isn't it generally expected for a feature-packed interpreted language to be slower than a minimal compiled language?
The "scripting" languages should of course not try to be slow, but people rarely use them for speed-reasons; they use these languages for gains in productivity and ease of writing code, adding features and so forth. That should be the primary focus point.
In the future we may no longer have such a speed penalty anyway.
subset Even of Int where * %% 2;
subset Odd of Int where * !%% 2;
multi foo(Even $i) { ‘fizz’ }
multi foo(Odd $i) { ‘buzz’ }
say foo for ^9;I wouldn't use Ruby for high performance computing. But for scripting (where runtime is not critical), web services (where transport latency will usually far outstrip the few milliseconds your handler takes) or shell use (where humans aren't fast enough to issue a new command every millisecond anyway), Ruby is more than fast enough.
This is probably even slower than bash
Great name though
But, you can write an optimised pipe in ruby too. I actually did that, because I could not want to be bothered to be restricted via ruby's syntax for pipe-like operations.
Even aside from that, the original claim was about pipes versus method chaining. To me these are not orthogonal to one another; they are very similar. Just with the pipe focusing on tying together different programs and focusing on input-output functionality. Method chaining in ruby is a bit more flexible, we have blocks, and usually the methods chained occur in one class/object or the toplevel namespace (less frequently though, usually). Even the pipe comparison is not ideal, because traditional UNIX pipes don't support e. g. data manipulation via an object-oriented focus. And I want that (see avisynth, but extend the idea there via a) nicer syntax and b) data manipulation for EVERYTHING).
I don't see pipe as being exclusive over method chaining or reverse.
One interesting idea was to add |> elixir's pipe-like operator to ruby. I like that, but indeed, the net-gain in ruby is quite minimal since method-chaining + blocks already offer a ton of flexibility, so I am not sure how |> would fit into ruby 1:1. Still I like the idea, but anyone proposing |> needs to come up with really convincing ideas to matz here. Because people WILL ask what the real difference is to method chaining. Even fail-safe method chaining in ruby though I absolutely hate the syntax via ? there ... it reads like garbage to me. Example:
https://github.com/ruby/ruby/blob/trunk/test/ruby/test_threa...
t1&.kill&.join
(It has moved since then, so the above link no longer works,
been some years since I first saw it. Upon seeing it my brain
instantly cancelled any use of "&.", even though I understand
the rationale. It is just ugly to no ends. I still like the
|> syntax in Elixir though, even though I can not really see
what this should do in ruby.)although that line could move again, so here is a permalink: https://github.com/ruby/ruby/blob/6c6df00bbcefe/test/ruby/te...
Apparently a number of people disagree with me, or the way I initially expressed myself, judging from the amount of downvotes I've had. Weird how that happens; tabs and spaces.
Just for fun, looking at code count as a rough measure of complexity.
rubish: 26,842
rc (plan9 shell): 5,888
To be fair, rubish does a lot more than rc. rc is pretty minimal.
rc source:
https://github.com/9front/9front/tree/front/sys/src/cmd/rc
Measures below:
$ wc -l `find . -name '*.rb'`
1124 ./rubish/execution_context.rb
43 ./rubish/frontend.rb
260 ./rubish/builtins/hash_directories.rb
510 ./rubish/builtins/echo_printf.rb
834 ./rubish/builtins/bind_readline.rb
182 ./rubish/builtins/directory_stack.rb
299 ./rubish/builtins/read.rb
324 ./rubish/builtins/trap.rb
129 ./rubish/builtins/arithmetic.rb
862 ./rubish/completion.rb
988 ./rubish/expansion.rb
431 ./rubish/completions/git.rb
114 ./rubish/completions/ssh.rb
530 ./rubish/completions/bash_helpers.rb
453 ./rubish/completions/help_parser.rb
167 ./rubish/ast.rb
46 ./rubish/frontend/tty.rb
1179 ./rubish/runtime.rb
127 ./rubish/lazy_loader.rb
63 ./rubish/data_define.rb
1163 ./rubish/runtime/command.rb
153 ./rubish/runtime/job.rb
7270 ./rubish/runtime/builtins.rb
306 ./rubish/config.rb
2442 ./rubish/repl.rb
1316 ./rubish/codegen.rb
1180 ./rubish/lexer.rb
742 ./rubish/history.rb
1169 ./rubish/parser.rb
67 ./rubish/startup_profiler.rb
848 ./rubish/prompt.rb
47 ./rubish/data/readline_config.rb
716 ./rubish/data/builtin_help.rb
251 ./rubish/data/shell_options.rb
53 ./rubish/data/completion_data.rb
5 ./rubish/version.rb
248 ./rubish/shell_state.rb
140 ./rubish/arithmetic.rb
61 ./rubish.rb
26842 total
rc: $ wc -l *.c *.h *.y
547 code.c
1173 exec.c
234 getflags.c
259 glob.c
240 havefork.c
137 here.c
301 io.c
436 lex.c
169 pcmd.c
78 pfnc.c
494 plan9.c
539 simple.c
74 subr.c
37 trap.c
190 tree.c
420 unix.c
109 var.c
85 exec.h
72 fns.h
7 getflags.h
28 io.h
167 rc.h
92 syn.y
5888 totalA few years ago irb got a facelift, so rubish probably represents a more modern take on the shell concept. I tested it and it works too. I wonder how much the everything-is-an-object idea is extended here. Many years ago I learned avisynth + virtualdub and I always liked how they approached filtering. Ffmpeg is great, but I absolutely hate the filter system it uses and the ABSOLUTELY horrible syntax. The ffmpeg devs do not seem to know avisynth, or any alternatives here - so I want object manipulation with a convenient syntax at all times, not just for audio/video data but literally for any data. Naturally ruby would be a good fit by default, but I am unaware of many ruby developers even wanting to go that route. If there are still any ruby developers left that is - ruby has been tanking hard in the last few years, approaching extinction level, just like perl did before.
There has to be a better influx of new users; the old +50 years generation isn't going to keep languages alive really.
Edit: Also I forgot: the idea and implementation is fine, I just think we need much more of that in general. Ruby is kind of in a patchy patchwork situation. Where are the epic projects? Rails is also ancient already.
I think Rails both boosted Ruby and killed it. When I ask people about why they dislike Ruby it's usually due to something specific to Rails (plus some comments around syntax which are easily dismissed or accepted).
I used to be a pretty heavy Ruby user and I still love the language, though I have only used Rails sparsely and not by choice.
I had the opportunity to work on a Ruby project for a couple weeks a few years ago and it was such a pleasure to read through the code and interpret it! It was unfortunately another project that was being replaced with something else because Ruby skills were harder to find.
can't find ruby skills? they are searching for the wrong thing. they should hire an experienced programmer who could learn ruby in a week and not expect someone who has been working exclusively with ruby for the past few years. those people already have jobs.