I'm pleasantly surprised to see this improvement:
Tempfile.create(anonymous: true) removes the created temporary file
immediately. So applications don’t need to remove the file.
[Feature #20497]
I use a similar pattern a lot: file = Tempfile.new.tap(&:unlink)
file << "... some really large data to pipe"
system("md5sum", in: file.tap(&:rewind))
It's a neat trick to leverage the filesystem for large amounts of data (e.g. "psql \copy" generation), without littering tempfiles everywhere. Once the last fd disappears, the filesystem releases the data; so you don't have to "trap" signals and add cleanup routines. (Hint: you can also use these unlinked-tempfiles for command output, e.g. huge grep output, etc.)On Linux systems, `open(..., O_TMPFILE)` is typically used, which provides additional safety. The created file is initially unnamed (no race condition between `open` and `unlink`).
When I needed safety, my non-portable solution was to use Ruby's syscall feature. (Btw, I love that you can do this.)
require "fcntl"
SYS_OPEN = 2
O_TMPFILE = 0x00410000
O_RDWR = Fcntl::O_RDWR
def tmpfile
mode = O_RDWR | O_TMPFILE
fd = syscall(SYS_OPEN, "/dev/shm", mode, 0644)
IO.for_fd(fd)
end
But... Another pleasant surprise from the PR (https://bugs.ruby-lang.org/issues/20497). Linux 3.11 has O_TMPFILE to create an unnamed file.
The current implementation uses it.
Excellent to see :)
Makes the PR even better!This is available in older Ruby versions by using the upstream `tempfile` gem version.
The default block parameter name seems small, but I feel like I'm gonna use it all the time, especially when I'm in the Rails console just trying to debug data
Kotlin also has it, I can tell you that it's really useful
Ruby has had this in the same form as "_1" for a while (and the obvious other indexes in the case of multiple params), but I agree Kotlin's "it" reads much better.
Groovy has had “it” for a while. I suspect it predates Kotlin’s usage.
Also matches Groovy
Similar ish but equally cool is Nim's `result` keyword for functions. https://nim-by-example.github.io/variables/result/
Also damn Nim needs to do a much better job with their docs and site. `nim result` returns this very outdated third-party link first and nothing else official.
I constantly run into situations where I need to nest an iterator computation, and things like "it" get confusing.
I'm all for adding language features to avoid boilerplate, and it's clearly useful. I just want to call out that anonymous typing can be polarizing in large codebases and maybe only use it sparingly.
I doubt I'll use it in committed code very often at all, this feels more like something that's very useful when hacking at something in the REPL
nested_example = [1, 2, 3, 4, 5].map do
[it, (1..it).map { it * it }]
endHas an ambiguity, so you just add |x| to one of them..
nested_example = [1, 2, 3, 4, 5].map do |x|
[x, (1..x).map { x * it }]
endSeems like a mental over complication of a non-issue to me.
Implicit `it` shadows in other languages like Kotlin just like any other variable scope, and I really can’t say I’ve ever had it be a problem (implicit receivers, on the other hand, can be a right pain in the ass in poorly designed libraries and can I just say Gradle can go right to hell for it).
It’s a nonissue in small projects, but I’m not sure I agree that `{ x * it }` is easy to reason about when coming back to this block in 6 months. It’s mostly something that I’ve seen bite engineers during refactoring.
Being ruby you can monkey patch block to add an additional t to every nested block’s `it`
(This is terrible please don’t)
I've not been tracking ruby core discussions for ages now, but I could have sworn that exactly this was discussed and rejected a decade or so ago.
I think I remember that as well. If you read the changelog, it goes through a good deal of edge cases behaviors that they probably ironed out in the intervening time, like captured variables with the same name and nested blocks with it parameters.
I was disappointed that "block parameter name" wasn't the ability to give a block an actual name that will show up in a stack trace. It's been an endless source of frustration when your stack trace is just a bunch of anonymous blocks and procs. I assume JS devs feel a similar pain with anonymous functions.
We already had "_1", "_2", etc., for inline block arguments. Adding "it" increases the surface area of the language without adding any new functionality. I think the underscored names are actually better for readability. They jump out at me, while "it" looks like every other variable name.
items.map { foo(_1) }
items.map { foo(it) }
I like “it” but it’s a shame it works only in single line blocks.
I know Shopify has a great site on comparing Ruby vs YJIT perf.
But does anyone have current numbers on how Ruby/YJIT compares to something like Python/PHP/LuaJIT?
The Computer Language Benchmarks Game has some compared benchmarks:
Ruby+YJIT vs Python: https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
Ruby+YJIT vs PHP: https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
Ruby+YJIT vs Lua: https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
And for an appearance of comparability the "#8" programs are un-optimised single-thread transliterated lowest-common-denominator style into different programming languages from the same original.
https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
> In Ruby 3.4, it has been added as a default name for the first parameter passed to a block. Rather than specifying a name in trivial cases like the one above, you can now write:
> [
> "beige chinos",
> "blue jorts",
> "rainbow jorts",
> ].filter { it =~ /jorts/ }
> # => ["blue jorts", "rainbow jorts"]
This reminds me of Perl's $_ (which in Ruby is last line read from STDIN).
I am familiar with ‘it’ as a default closure input from Kotlin. From a quick search, that in turns seems to be inspired by Groovy.
This goes at least as far back as anaphoric macros: https://en.m.wikipedia.org/wiki/Anaphoric_macro.
shame about that example, since
ary.grep /(j|sh)orts/
already exists, and therefore sells the standard library short. try this: terms = %w(foo? bar q**x)
Regexp.new "\\b(#{terms.map { Regexp.escape it }.join ?|})\\b"
#=> /\b(foo\?|bar|q\*\*x)\b/
and observe that it's at the margins of instant comprehension where syntax shorthands like "it" add value.The author also forgot to mention that the new error output doesn't mix ` and ' anymore.
Ruby 3.3
> 'asd' + 1 (sitar-report):1:in `+': no implicit conversion ...
Ruby 3.4
> 'asd' + 1 (sitar-report):1:in 'String#+': no implicit conversion...
This has bothered me for decades, why was this ever the case to begin with?
I'd presume it's the same motivation behind quotes in TeX (`foo' and ``bar'')—maybe typewriters didn't use to have true curly quotes, or something?
EDIT: https://en.wikipedia.org/wiki/Backtick#As_surrogate_of_apost... seems relevant
Is the stack trace in the section "Clearer exception backtraces" actually from 3.4? It has mixed backticks and single quotes.
Fixed! I grabbed that example from the bug tracker issue where the change was discussed and that wasn’t based on a version where the backtick change had been made.
I happen to be reading the latest edition of the pickaxe book, as I'll soon be using Ruby at work (first experience) and this 'it' update sounds so much better than the _1 described in the book.
I remember thinking it clashed a bit with the idea of trying to make the code read like natural language.
_1 is also a bit of a footgun. It becomes an array of all block params IF the block has an arity > 1 AND no other block param (e.g. _2) is referenced anywhere within the block.
It's an unusually half-baked feature by Ruby's standards. I think there was some hesitation about the name "it" initially, because "it" is an essential method name in rspec, and is used within blocks there.
Oh damn. I have been using `_1`, `_2`, etc. extensively for years... I didn't know about that footgun.
I'd like know if `it` is merely an alias for `_1`, or if protects from this "arity issue" too.
I pity anyone needing to debug a fiddly Rspec problem in the next few years.
IIRC, the decision was that it in a block is only ever called without arguments, e.g. map { it * 2 }, and it in Rspec is only ever called with arguments, e.g. it "describes a test" do ... end. So it ended up being a non-issue.
I can totally see some add on gem for rspec breaking that assumption.
FYI, one of my favorite Ruby idioms is to capture command output with `open(...){_1.read}`
pp open("|ls -lh /usr/bin/ls"){_1.read}
"-rwxr-xr-x 1 root root 135K Aug 30 04:57 /usr/bin/ls\n"
or to quickly print tabular data open("|column -t -s \\t", "w"){_1 << tsv_data}
Am I missing something - it's 2am here, so possibly - or could you not just use backticks for the first one?
Oh that's embarrassing -- you're right, the first example doesn't make sense. Kinda pointless actually haha
I use it for code like this:
raw = IO.popen(%W[gzip -d -c -- #{path}]){_1.read}
raw = IO.popen(%W[gzip -d -c], in: pipe){_1.read}
raw = IO.popen(%W[git status --porcelain -- #{path}]){_1.read}
Useful because it eliminates /bin/sh footguns (e.g. `md5sum hello&world` forking or `~john` expanding), plus you get kernel.spawn() options. `open("| ...)` only made sense for the second example.Anyway, I find "_1" more eye-pleasing than:
IO.popen(%W[gzip -d -c #{path}]){|io| io.read}
Did you know you were going to use Ruby before Applying? Just wondering.
Yup. I don't mind switching languages, I've done it a few times and I enjoy learning new things.
The market for ruby seems to have good salaries and job satisfaction despite being smallish, so it didn't seem like a bad area to get some experience in.
Why, is there any issue with the choice I'm not aware of?
>Why, is there any issue with the choice I'm not aware of?
No, not at all. I was just interested since there is a sudden influx of people joining Ruby ( I guess mostly Rails ) companies without previous Ruby background. As I have notice this across HN, Reddit, Twitter and elsewhere. And yes Ruby market tends to be on the slightly higher end because they mostly hire people with years of programming experiences and lack of junior position. And there used to be complains about not being able to find people with Ruby / Rails experiences etc. So it is a good market shift I guess.
Ah well, as soon as I even glanced at Ruby my social media feeds were filled with tech influencers.
There is a niche there of very popular channels producing Ruby tutorials, seemingly aimed at the junior js-bootcamp dev crowd. They also focus on Neovim, tmux and other terminal based tools.
It is a completely anecdotal observation, but my guess is that it might explain part of the trend.
I have a love-hate relationship with Ruby. On one hand, it's a very expressive language that's excellent for building structured, lightweight applications. On the other hand, it requires significant discipline and a strong memory of your codebase and all the different types in play. When you combine this highly dynamic nature with Rails, especially its concerns and hooks, it can become extremely challenging to understand what's actually happening in the system.
I don't understand the change of the default block parameter name. It's already _1, _2, etc. Why create yet another, backward-incompatible way?
And still, they doom march forward with the fragmentation of rbs and sorbet/tapioca, rather than adopting in-band gradual typing like Python did.
I think the greater problem is Ruby appears to be developed by a nearly-closed small clique of people who refuse to listen to others or to reason.
I agree that `it` is unnecessary, but I'm really confused by the push for a type system. It adds a lot of clutter to a language that optimizes for expressiveness. I would prefer to work in something like Go, which is designed to have types, rather than awkwardly patch them into Ruby.
Apples (dynamic language) vs. oranges (static languages). Python's gradual typing approach solved this problem similarly to TypeScript, which is the right way to do it: https://peps.python.org/pep-0483/
It may be less bad, but I don't think there's a right way to retroactively add a type system to a dynamic language. I generally like working in JavaScript, but I have no desire to ever see TypeScript again.
Is ruby used outside of web dev (i.e., Ruby on Rails)? it seems like a nice cute language but I almost never hear about it.
I think it's quite sad that Ruby is so associated with Rails. Ruby is one of my favorite languages and last time that I touched a Rails code was in 2017. Even in web dev Rails is not the only thing in Ruby, there's also Sinatra which is an elegant micro-framework for building HTTP APIs, similar to Flask.
Some projects that I remember that uses Ruby that are not related to web dev: Homebrew, Metasploit, Vagrant and Jekyll.
I also find Ruby very useful for shell scripts. I wrote a blog post about that some months ago, you can read it and the discussion about it here: https://news.ycombinator.com/item?id=40763640
Some other examples: DragonRuby, and Chef (which I prefer over ansible).
I got into Ruby kind of early, around 2001. When Rails initially came out a few years later (circa 2004, IIRC) I remember being excited to see something putting Ruby out there giving it some publicity. But in a few years I think a lot of us were regretting the fact that most people's view of Ruby was formed by Rails.
Congratulations on getting Matz to tweet about your post.
Thanks! I never thought this would reach him!
Ruby is my go to language for short "fun" programs, as there are many places where it optimized for development experience (such as the new "it" feature). One of the committers, Yusuke Endoh, clearly understood the joy of coding in itself as opposed to being means to an end, and has authored a book on esoteric programming:
https://www.amazon.co.jp/dp/4774176435
Before Ruby, my preferred fun language was Perl. Ruby is like Perl but without having to type $ all the time. I have never used Rails.
Oh yes, Ruby is my go to language to use when I need to glue things together or when I want to automate tasks on my computer. It's such a pleasant language to use!
I think the reason it's not talked about a lot is mainly because Rails overshadowing it and because there aren't so much hype or controversies around it.
At my day job we use Ruby with Sorbet to stitch together a large number of data engineering pipelines. It's a good choice since we also often stand up small Rails apps to expose the results from those pipelines, so we can keep everything in one language. The fluent functional approach it enables is pretty nice for that business logic (but I would not want to do it without the gradual typing on top). We do find ourselves glancing over at the Python ecosystem with envy from time to time but overall it has worked pretty well. As I've gotten better with it I find myself reaching for irb for more and more one-off tasks in the shell too.
Oh nice! I haven't used Sorbet yet, but this is the second time I've heard good things about it outside of Stripe (where it originated). I'll have to give it a proper look.
I think they direct people to tapioca by default at this point, but that was key to making it a smooth process for us.
I find it to be a mixed bag. Better than nothing, but doesn't come anywhere close to what something like typescript can do for example.
Yup, I wrote smartcard reader programs in it. Some of them talk to a http server using async-http. It can be used for anything that Perl or Python is good at, well maybe except data science because Python really shines there. And irb is massively useful for everyday tasks.
I wish I could reach for Kotlin as a kind of "Ruby with typing out of the box" but the lack of a good REPL is a real dealbreaker.
You'll get Ruby with typings soon when rbs-inline is finalized
Is that really something that's been slated to be added to the language proper? I attended RubyConf and in his keynote Matz seemed pretty opposed to adding types to Ruby source, and argued in favor of automatic typing instead.
You can always use Crystal or Dart if you want builtin types. I like Ruby the way it is an trust Matz with his language design decisions.
Crystal is the closest alternative to Ruby with types we have, even though they are semantically different and differ in some places. I do not see why you mentioned Dart as an alternative thought, it’s a totally different language.
> Dart as an alternative thought, it’s a totally different language
Yes it's not Ruby but it has good design, optional type annotations.
Yeah I actually did not necessarily mean to dispute Matz's perspective there. I actually think it will benefit programming as a whole if at least one widely used language takes the path of trying to eschew explicit type annotations.
Ooh, I hadn't heard of rbs-inline before. I was always a bit put off by the type definitions having to live in separate files.
Yes! In practice it's a scripting language similar in vein to Python, and it's used for similar things.
It's actually the language of choice for a lot of OpenSUSE projects as well, like the Open Build Service.
The reason you don't here much about it is because of its maturity.
It's used for chef/cinc. I rather like that "recipes" use ruby with an edsl rather than yaml like ansible or salt.
Vagrant, chef, puppet and lots of other stuff is written in Ruby. It's also great as a scripting language replacing Bash, Python or Perl for any number of things. I write all my small, one off programs in Ruby.
I use Ruby extensively in ops scripting and text mangling, where it supplanted Perl for me around about the same time that Perl stagnated ca.2010-2015.
However, Ruby doesn't make sense to me as a general applications language (Swift & Kotlin have won me over from C++ & Java), or as a systems programming language (I'm still rusted on to C, pun intended), and I remain super ambivalent about Rails despite using it extensively to stick web interfaces onto things. That doubt is in large part because Rails frequently undermines the Smalltalk-ish heart of Ruby.
Sure. I use it for almost everything, because it's so pleasant to use.
Yeah, I use it for everything between 5-lines-of-bash and a needs-a-compiled-language. You almost never hear about it, because it's mature. No big controversies, no huge fuckups or new versions that break everything, just a steady trickle of improvements.
I am happy in this moment because as I lay here with my ear on the ground, I can hear many many people hearing about Ruby
We use it for microservices that only deal with Json and avro. Of course, we do that on Rails for some reason I'll never understand.
Definitely, although Rails is its most common use
You might have heard about Metasploit.
Happy to see chilled strings; eventually getting rid of the frozen strings pragma will be enjoyable.
You can already get rid of it with the freezolite gem. https://github.com/ruby-next/freezolite
See also: https://nithinbekal.com/posts/ruby-3-4/