[HN Gopher] Ruby's switch statement is flexible
___________________________________________________________________
Ruby's switch statement is flexible
Author : thunderbong
Score : 147 points
Date : 2023-04-26 11:38 UTC (11 hours ago)
(HTM) web link (www.akshaykhot.com)
(TXT) w3m dump (www.akshaykhot.com)
| ajdude wrote:
| Very similar to Ada'a switch statement, which utilities "case ..
| when". I don't think Ada can utilize regex in their switch
| statements but they can do neat things like convert a string into
| its corresponding enumeration.
| hk1337 wrote:
| even = ->(x) { x % 2 == 0 } even === 4 # true
| even === 5 # false
|
| That's cool. No need for a is_even or is_odd gem.
|
| I really do like that ability to do a case statement though. I
| cannot think of a situation where I need it now but I could
| definitely see it being handy instead of having to do if..else if
| formerly_proven wrote:
| Am I too dumb to find it or do the Ruby docs not contain a
| description of the language?
|
| https://ruby-doc.org/3.2.2/ only seems to contain API docs.
| quechimba wrote:
| The Ruby docs are incredibly difficult to navigate.
| [deleted]
| irishsultan wrote:
| You need to take a closer look at the Pages sidebard, there is
| for example this https://ruby-
| doc.org/3.2.2/syntax/pattern_matching_rdoc.html
| olivierlacan wrote:
| This is not an official documentation site.
|
| The only official Ruby documentation exists at
| https://docs.ruby-lang.org/en/ and is generated via the Ruby
| source code itself.
|
| The excellent Colby Swandale has been working on a new open
| source alternative for Ruby documentation considering the
| design shortcomings of the default generated API documentation
| with https://rubyapi.org which I highly recommend.
|
| If you're coming at Ruby from another language, the official
| Ruby site offers https://www.ruby-
| lang.org/en/documentation/ruby-from-other-l... and other
| documentation aside from API concerns here: https://www.ruby-
| lang.org/en/documentation/
|
| Hope that helps.
| formerly_proven wrote:
| It's actually linked from the official site:
| https://www.ruby-lang.org/en/documentation/
| Alifatisk wrote:
| I feel fooled, I've always thought https://ruby-doc.org was
| the official website!
| olivierlacan wrote:
| Sadly there are a lot of third-party operated documentation
| sites that exist likely because of how hard-to-discover the
| official API documentation site is. It's something the
| community would like to address, but given the amount of
| link equity a lot of these older and often unmaintained doc
| sites have acquired it's fairly tricky.
| nanny wrote:
| That's the Core reference guide. You might want the book
| "Programming Ruby"[1], which is linked on the documentation
| landing page[2]. Alternatively, for a quick overview, I
| recommend Learn X in Y Minutes[3].
|
| [1]: http://ruby-doc.com/docs/ProgrammingRuby/
|
| [2]: https://www.ruby-lang.org/en/documentation/
|
| [3]: https://learnxinyminutes.com/docs/ruby/
| stonemetal12 wrote:
| From [1] > This book documents Version 1.6 of Ruby
|
| Has nothing about the language changed since 1.6?
| fknorangesite wrote:
| Hah yeah, uh, make sure you get a more recent edition that
| was published less than 20 years ago. A profound amount has
| changed since then.
|
| Looks like the 5th edition covers v3.2.
| stonemetal12 wrote:
| Did you expect something else? The way I get to that link is to
| go to ruby-doc.org and click on "Complete API docs for Ruby
| 3.2.2". API docs is what I expected.
| jrockway wrote:
| The rules for one of my favorite games says that it can only
| be experienced, not explained. I see that Ruby has the same
| philosophy.
| stonemetal12 wrote:
| Yeah, ruby is a weird one. They have excellent
| documentation of the API, but all the language
| documentation is wildly out of date. The main web site
| links to an old version of "Programming Ruby" which covers
| 1.6. Has nothing changed about the language in 20 years?
| Alifatisk wrote:
| I find ruby-doc.org very poorly designed.
|
| There is an unofficial website with a better design,
| https://ruby-docs.org
| dragonwriter wrote:
| The Ruby docs are, generally, the weak spot of the language
| (moreso than even being slow, on which there is also more
| progress).
|
| Fortunately (while there was a long time where this was not the
| case), there is a reasonably current version of the "Pickaxe"
| book, which is the closest existing thing to the documentation
| Ruby _should_ have:
| https://pragprog.com/titles/ruby5/programming-ruby-3-2-5th-e...
| web3-is-a-scam wrote:
| Ruby is a wonderful language, I just wish I wasn't stuck with 2.6
| at work because all of the improvements especially in Ruby 3.0
| are just wonderful. I keep wanting to branch out to other
| languages but keep coming back to Ruby as my bread and butter.
| olivierlacan wrote:
| May I recommend to anyone facing similar issues and who may
| have at least some agency in dealing with the problem (can't
| assume you do, so forgive me in that case) the incredible work
| of Victor Shepelev with Ruby References:
| https://rubyreferences.github.io/rubychanges/evolution.html
|
| The site presents evolutions of Ruby since version 2.0 in an
| editorialized and well-written categorized release journal
| called "Ruby Evolution":
| https://rubyreferences.github.io/rubychanges/evolution.html
|
| There's also individual version releases annotated as well, for
| example for the recent Ruby 3.2:
| https://rubyreferences.github.io/rubychanges/3.2.html
|
| Note that these are not copies of the NEWS.md typically
| released when minor and major versions of Ruby come out. Victor
| specifically spent time to write more descriptive notes of what
| each notable change occurred over time. It's an incredible
| resource and we're extremely lucky to have him in our
| community.
|
| There's even a changelog for this meta-changelog, which makes
| my little Keep a Changelog heart sing, so you can see
| evolutions of this site over time as well:
| https://rubyreferences.github.io/rubychanges/
| cschneid wrote:
| I moved us up from 2.4 to 2.7 last year trivially. Basically
| just changing the version base in our dockerfile. A few gems
| had to go up too, to support the kwargs changes. But like... 1
| day of work. I'm looking to go to 3.x soon too, after I get our
| EOL'd rails & lots of gems updated.
|
| What features in particular are you looking at in Ruby 3.0? The
| type system stuff seems really cool, but I haven't been hearing
| much about it in the wild.
| rst wrote:
| Unfortunately, the switch from 2.7 to 3.0 is likely to be
| more troublesome, due mostly to the change in handling
| keyword arguments (they're no longer treated as equivalent to
| a last positional argument that happens to be a hash, and you
| need to toss in '*' to convert from one convention to the
| other). This isn't hard to clean up if you have good test
| coverage... but one reason for not having done upgrades is
| not having that.
| web3-is-a-scam wrote:
| This is a convention we've already adopted but we haven't
| had the chance to do a clean sweep of the rest of the
| codebase unfortunately. You're right though, it's one of
| our biggest hurdles to upgrading.
| andruby wrote:
| If you're willing to share, what's holding your work back at
| 2.6.
|
| Afaik the upgrade has been reasonably smooth, and nothing like
| the ruby 1.9 days.
| SkyPuncher wrote:
| We're on a 2.x version as well.
|
| For us, it's just incredibly hard for us to justify the
| effort _and_ risk. Particularly, the risk.
|
| Most of us have been burned by a major upgrade (either here
| or elsewhere) where things have broken in non-obvious, hard
| to test ways. This is particularly problematic in the
| dependency chain where support is limited. Breaking issues
| may turn us into unexpected maintainers of key libraries.
| web3-is-a-scam wrote:
| > If you're willing to share, what's holding your work back
| at 2.6.
|
| Management.
| williamdclt wrote:
| I'm not saying that it's the case for you, but a lot of
| time I've seen that this actually means "engineers aren't
| able/willing to talk with management to justify the value
| of maintainance and make a concrete proposal of how to go
| about it".
|
| But then again, some other times management just sucks.
| newswasboring wrote:
| Naah, most of the times its that management doesn't want
| to pay the migration cost. They will keep using a system
| till it stops producing value, or till adding new things
| is profitable. They can't give a damn about day to day or
| what's cool/elegant/maintainable because they don't
| interact with the innards, ever. These decisions are made
| with a single equation, if migration cost > new feature
| cost + maintenance, they don't want to migrate.
|
| Edit: The maintenance isn't a long term view btw. They
| are not looking at a 5-6 year window where the migration
| cost slowly pays off. They are worried about optimizing
| the next quarter.
| web3-is-a-scam wrote:
| We upgraded from Rails 4 to 5 last year (lol - it was EOL
| before our migration was even done), but that was before
| our CTO left to be a CEO somewhere else and there's been
| no attempt to find a replacement. Now the executive is
| obsessed with piling on features with little regard to
| technical debt or maintenance. It's going about as well
| as you'd think.
| andruby wrote:
| I've been lucky to have been working in smaller companies
| where I've been able to communicate the issues with that.
|
| I can't imagine working in a place that doesn't want to
| listen to its engineers or experts. (The same works the
| other way around too: engineers not willing to understand
| the business context)
| jabradoodle wrote:
| It also likely means no one in management understands
| building software.
|
| It's tiring when every line of code needs a value
| proposition and a clear use case. Some things don't take
| much work to improve/maintain but are next to impossible
| to slap a $ value on.
| kibwen wrote:
| Have you considered replacing them with ChatGPT?
| newswasboring wrote:
| I think if someone can replace their management with
| chatGPT, they can probably just do the migration :P
| werdnapk wrote:
| You really need to push to upgrade to 3.0. Ruby 2.6 and 2.7
| have passed EOL and are no longer being supported.
| [deleted]
| web3-is-a-scam wrote:
| Believe me, I know. But management doesn't give a crap about
| that. We're still on Postgres 10 as well as Redis 5. Send
| help.
| twic wrote:
| Oh in that case, there's actually a very simple way to
| upgrade: get a job somewhere else.
| nateberkopec wrote:
| Woof. Postgres 11+ also has some nice speed improvements
| with each version as well.
| rakoo wrote:
| 1. Ask management to write in full letters and sign a paper
| basically saying "I acknowledge that not maintaining
| software up-to-date is a security risk and opens the
| company to substantial financial damage"
|
| 2. Hire a Pwn-As-A-Service to extract data from your
| company from the outside
|
| 3. Tell management "I told you so"
|
| You didn't read this here
|
| More seriously, I think the best you can do is not expect
| to find happiness in a setting that you don't fully control
| (ie your job), accept that, and look for joy elsewhere. It
| might be another job, it might be another hobby. Work fewer
| hours.
| web3-is-a-scam wrote:
| I appreciate your advice. I regularly voice concerns
| about security and let management make decisions. From my
| perspective I've done my due diligence and my hands are
| clean.
|
| I've stopped looking for "joy" from work. Mainly focused
| on finding joy with my children and other hobbies, while
| working as little as possible. The job is the means to
| that end now, rather than the end itself. They continue
| to pay me and it supports the things I want to do outside
| of work so I am "happy" enough. The work itself is also
| moderately interesting and a decent challenge from a
| domain perspective, so it's not all bad.
| rakoo wrote:
| > I appreciate your advice. I regularly voice concerns
| about security and let management make decisions. From my
| perspective I've done my due diligence and my hands are
| clean.
|
| I feel like the best you can do unironically is the first
| step I outlined: ask management to formally recognize
| that despite your warnings, they choose cost reduction.
| Have a trace of that, not just in case of problems, but
| for yourself: it's a great reminder that as long as you
| aren't in charge, it can't be your problem.
| izietto wrote:
| > More seriously, I think the best you can do is not
| expect to find happiness in a setting that you don't
| fully control (ie your job), accept that, and look for
| joy elsewhere. It might be another job, it might be
| another hobby. Work fewer hours.
|
| That's how I upgraded from Ruby 2.4 / Rails 5.0 to Ruby
| 3.2 / Rails 7.0
| Alifatisk wrote:
| There is ruby-next gem for polyfills :)
|
| https://rubygems.org/gems/ruby-next-core
| mynonameaccount wrote:
| very cool. Thanks
| adverbly wrote:
| It's cool that Ruby has a === operator, but the fact that it is
| not a more strict version of == has caused me trouble in the
| past.
|
| In TypeScript === is more strict, and when I go back and forth
| between Ruby and TS I have made a mistake in the past by putting
| a === when I intended a strict equality check.
|
| I wonder if there is a linting setting where you can prevent your
| code base from ever using it.
| nusaru wrote:
| Here you go:
| https://docs.rubocop.org/rubocop/cops_style.html#stylecaseeq...
| [deleted]
| cout wrote:
| Ruby does not have a switch statement; it has a case expression
| (which can be used in a statement).
| ape4 wrote:
| That naming is rather maddening.
| calo_star wrote:
| It's the same in Haskell, Erlang and Elixir.
| layer8 wrote:
| It's the same in SQL and Ada. "Case" is an abbreviation for
| "case distinction" here.
|
| "Switch" was never intuitive to me, because nothing gets
| switched.
| mock-possum wrote:
| Whoa that's wild.
|
| > Note: There're no break statements at the end of each when
| clause. Unlike other languages, Ruby's case doesn't fall through.
|
| Aw no fall through?
|
| > Note: Do not use obj.class in the case clause, as Integer ===
| Integer returns false.
|
| Wait what
| marcosdumay wrote:
| > Aw no fall through?
|
| That's a good thing. In fact, that's the only thing on the
| article that is unambiguously good.
|
| Fall through only serves to create bugs.
| hnuser847 wrote:
| The switch statement in Ruby uses the `===` method under the
| hood. `===` does not mean "equals" like it does in Javascript.
| Instead, `a === b` means, does `b` belong in the set of `a`.
| irb(main):001:0> Integer === Integer => false
| irb(main):002:0> String === String => false
| irb(main):003:0> Object === Integer => true
| irb(main):004:0> Object === String => true
| radiospiel wrote:
| This might confuse a reader. The Object === cases are
| successful, because the Class-objects Integer and String are
| Objects. In ruby everything is an Object.
| hnuser847 wrote:
| That's a good point. This might be a better example:
| irb(main):009:0> String === String => false
| irb(main):010:0> Integer === Integer => false
| irb(main):011:0> Class === Integer => true
| irb(main):012:0> Class === String => true
| burke wrote:
| Yeah: it's almost more true to say that `a === b` just means
| whatever we've decided `case b when a` should check. `===` is
| almost never used directly.
| LanceH wrote:
| This makes more sense and seems less egregious when you look
| at it in use, in a case: a = [] case a
| when Array puts true else puts false
| end
| greenpeas wrote:
| > Wait what
|
| Ruby's triple equals (`===`) is defined differently based on
| the type of the operand on the left hand side.
|
| `a === b` is syntactic sugar for `a.===(b)`; and for classes
| `klass.===(other)` is defined as `other.is_a?(klass)`.
|
| More examples here: https://dev.to/baweaver/understanding-ruby-
| triple-equals-2p9...
| TRiG_Ireland wrote:
| This seems to work instead of fall through, though:
|
| when 60, 70
| vidarh wrote:
| > Wait what
|
| `Integer ===` (and more generally if `===` is implemented as a
| class method) checks if the right hand side is of the class
| Integer. The _object_ Integer is not, it 's an object of class
| Class.
|
| EDIT: In other words: $ pry [1]
| pry(main)> Integer === Integer => false [2]
| pry(main)> Class === Integer => true [3]
| pry(main)> Integer.class => Class
| djur wrote:
| `rescue` also uses the match operator, which I found useful in
| the past when wrapping libraries that didn't expose a useful
| exception type hierarchy. In particular I seem to recall that the
| "pg" gem would throw `PG::Error`, with the actual error details
| from the Postgres server only accessible in the `message`. I
| wrote a little library that allowed me to create "virtual"
| exception types that could match based on the message or the
| result of an arbitrary proc (if the underlying exception class
| offered a `code` or `reason` attribute, for instance).
|
| For all its (sometimes deserved) reputation as a big and complex
| language, Ruby is actually pretty good at making sure that
| language features are made with the same underlying building
| blocks, and thus two things that look similar probably work
| similarly as well.
| caseyohara wrote:
| Wow I've been programming Ruby for 15 years and didn't know
| `rescue` uses a match operator.
|
| It's annoying when a library raises only one exception type for
| every error and the only difference is in the message. Matching
| on the message right in the rescue expression would be
| tremendously useful instead of parsing the message and deciding
| how to deal with it inside the rescue body.
| djur wrote:
| Here's the library: https://github.com/mboeh/toe_tag
|
| It's a decade old and less than 100 lines so it might be more
| useful as an example than a gem. The last time I needed to do
| something like this I just rewrote the parts I needed. The
| ecosystem is just generally better about exceptions than it
| used to be, too.
| veidelis wrote:
| This made me laugh:
|
| def can_drive(age) case age when 1..14 then 'no' when 15..100
| then 'yes' end end
|
| puts can_drive(18) # yes
|
| I haven't used Ruby for a long time, and I don't feel bad about
| it.
| userbinator wrote:
| That's because it's more like a compacted if/else ladder than
| what I'd traditionally think of a switch as (indexed jump).
|
| SQL has CASE...WHEN which is a similar concept.
| cschneid wrote:
| Sorta? Like you're right, there's not compiled machine code
| that does a jump. But Ruby's case statement has nice semantics
| to make clear code out of what could be a complex if/elsif/else
| chain. The use of the === function is powerful, and lets the
| reader of the code focus on the condition, not the function
| call to check it. if (patternA.match(input))
| elsif (patternB.match(input)) else end
|
| vs case input when patternA
| when patternB else end
|
| And since it uses ===, you can define that on your own classes
| too. Hypothetically for instance, you can make fairly complex
| policy type classes to make reusable boolean statements.
| case current_user when NotValidatedEmail when
| NotCompletedOnboarding when SomethingElse else
| end
|
| and then you can use those elsewhere in the code by leveraging
| the more global use of === [user1,
| user2].any?(NotCompletedOnboarding)
| byroot wrote:
| > there's not compiled machine code that does a jump
|
| It's more of an implementation detail, but the Ruby VM
| actually does a jump if all the cases are "keyable"(typically
| integers, strings, symbols, etc). It does a hash lookup and
| jump to the returning address.
|
| https://github.com/ruby/ruby/blob/92466e440d459cd21e89f8bfbe.
| ..
| [deleted]
| cirrus3 wrote:
| Swift: Hold my beer
| pjmlp wrote:
| Standard ML enters the bar.
| masto wrote:
| Raku would like to have a word with you.
| pjmlp wrote:
| In what sense does it offer in pattern matching that ML
| can't do?
| werdnapk wrote:
| No mention of pattern matching being used with a case statement:
|
| https://docs.ruby-lang.org/en/3.0/syntax/pattern_matching_rd...
|
| This is where some real magic happens.
| connordoner wrote:
| OP has updated it off the back of this comment.
|
| https://www.akshaykhot.com/ruby-switch-statement#pattern-mat...
| Lammy wrote:
| Pattern matching gets even more fun with the rightward-
| assignment syntax and additional conditionals. Here's a single
| example case from the UUID/GUID library I'm working on where
| the constructor method takes arbitrary positional arguments,
| many combinations of which may yield a valid UUID. This
| particular case matches the components of a Microsoft-style
| GUID so it can handle the endianness appropriately:
| in [::Integer => data1, ::Integer => data2, ::Integer => data3,
| ::Array => data4] if ( data1.bit_length.<=(32) and
| data2.bit_length.<=(16) and data3.bit_length.<=(16) and (
| data4.size.eql?(8) and data4.all?(&::Integer::method(:===)) and
| data4.max.bit_length.<=(8) ) ) then
| greenpeas wrote:
| FIY, you can write `data4.all?(Integer)` because `all?` can
| take a pattern instead of a block, and it uses the === (just
| like case...when)
|
| I just learned this myself from another comment in this
| thread.
|
| UPD: why do you write `obj.<=(16)` instead of `obj <= 16`? is
| this a performance thing or a matter of style or something
| else?
| Lammy wrote:
| Just a style thing. I find it less visually overwhelming
| when every statement that contributes a true/false is
| visually contiguous. You can see it in context here if
| curious: https://github.com/okeeblow/DistorteD/blob/NEW%E2%
| 80%85SENSA...
| software_writer wrote:
| Thanks for pointing it out. I've updated it.
| nomilk wrote:
| Tangental, but this article deserves huge credit for having code
| containing the main point right at the top allowing the reader to
| derive the main point in < 20 seconds. I wish more written
| content was like this. Brilliant.
| n42 wrote:
| And loses credit for a title making click bait claims about
| what I think or don't think
| layer8 wrote:
| It doesn't actually list all interesting cases discussed in the
| article, including the _case_ ... _in_ pattern matching at the
| end.
| greenpeas wrote:
| That's likely because the pattern matching usage was a late
| addition to the article (wasn't planned from the start)
| layer8 wrote:
| It's also missing string-literal matching, relational
| operators (<), and (more interestingly) type matching.
| MrVitaliy wrote:
| Ruby is going through some kind of renascence age, I'm seeing
| allot of Ruby articles lately.
| brightball wrote:
| Productivity is a very sticky feature. IMO there's no language
| that I know of which effectively competes with Ruby in this
| category.
|
| I don't even know if people realize that Ruby is the closest
| thing to an Aspect Oriented Programming experience in the wild,
| at least that I've seen. It's the secret sauce IMO.
| connordoner wrote:
| I'm personally quite enjoying it.
| imacomputertoo wrote:
| I love Ruby so much. Its syntax and flexibility are such a joy
| to work with. I hope it does have a resurgence in popularity.
| I've been using it my whole career, and fearing the day I have
| to switch to something new.
| vlunkr wrote:
| IMO Learning new languages is one of the best ways to be
| become a better programmer. You can carry the things you like
| about Ruby with you, and learn to think about things in new
| ways.
| baremetal wrote:
| Loving all the Ruby articles. Ruby has been my favorite
| language ever since i discovered it back in 08.
|
| Before that I was using Perl..
| SkyPuncher wrote:
| I feel like people got hung up on computational performance for
| a while. 5 to 10 years ago, a bunch of big startups hit the
| scale where they needed to intentionally work around Ruby's
| limitations. People seemed fixate on those performance issues
| while overlooking the business context - that hitting that
| scale means you are wildly successful and solving problems most
| startups never have the chance to solve.
|
| It seems there's a swing back towards people considering raw
| productivity. Especially, at early stage or pre-product market
| fit.
|
| Given that Rails is highly correlated with Ruby usage, it's
| simply hard to beat how much productivity and breadth that
| Rails gives you. Especially, with how much "grunt" work is
| easily handled by it.
|
| I love trying new frameworks on side projects, but I always
| find myself coming back to Rails. There is inevitably some
| nuanced situation that the framework doesn't handle that would
| be ridiculously easy in Rails.
| pizza234 wrote:
| Small mistake on the `/\D/`: the correct semantic is "the string
| (or any matchable class) includes a character that is not a
| number".
|
| It will also never match a number, although it's kinda ok because
| it's supposed to be an example of the functionality.
| tabtab wrote:
| The "C" family has one of the worst case/switch statements out
| there. When Java et. al. cloned it, they should have provided an
| alternative. Perhaps keep the old style for backward
| compatibility, but provide a new one with different key-words to
| avoid confusion. Example: select(a) {
| when 1,2,3 {...} when 4 {...} when 5,6
| {...} otherwise {...} }
| twic wrote:
| Agreed that the C-style switch is crammed with misfeatures. But
| Java does now let you write this (haven't tried compiling this,
| may contain small errors): static String
| describe(int change) { return switch (change) {
| case 0 -> "unchanged"; case
| -1, 1 -> "mostly unchanged"; case
| Integer i && i > 0 -> "increased"; case Integer
| i -> "decreased"; } }
|
| No fallthrough, can mix constants and conditions (with syntax
| some will find clunky), and is an expression.
___________________________________________________________________
(page generated 2023-04-26 23:02 UTC)