13 ms·
Ruby adds experimental support for rightward assignments
- hhsnopek 6y ago[question]: Is the main benefit of "Rightward assignments" readability and does this provide more benefits?
- zamalek 6y agoRuby currently supports "Rightward conditionals": user.delete() if deleteUser It is probably thought that this feature would result in similar readability improvements.
- choward 6y agoI don't find that more readable at all. I prefer: if deleteUser user.delete() end It's easier for me to read. It doesn't try to hide away logic. And if the line gets longer if the conditional gets more complex or I want to add an else I can without reformatting.
- zamalek 6y agoIt's subjective, the point is that some people prefer it.
- kevincox 6y agoIt works well for some cases. You end up with return if a.nil? return if attempts < max_attempts In this case "return if" becomes like a keyword and you can ignore it and focus on the rest of the expression. It also seems very readable for other simple values like `return false if ...`. But I agree, as soon as the code to the left of the `if` gets non-trivial it is harder to read.
- war1025 6y agoPython has the same "rightward conditional" thing. Any time I use it, I wish python had just gone with the normal ternary (? :) operator.
- dragonwriter 6y ago> Python has the same "rightward conditional" thing. No, python writes the ternary operator with words, it doesn't have rightward conditionals. The key difference is that the else clause is required in the Python ternary, where it's optional in a conditional.
- war1025 6y agoDoesn't make it any less irritating.
- tylerscott 6y agoI am also struggling to think of a situation where I would want to reach for this feature. The only examples I can muster are just minor improvements to readability, like you pointed out. I would love to see a solid example where this is a must have feature.
- imglorp 6y agoI think it would make sense for chained operations in a mental data flow sense. makejunk().filter().last(4) => fourthings feels better than fourthings = makejunk().filter().last(4)
- syspec 6y agoNot to me, and other people who use Ruby sparingly
- Someone 6y agoI’m not sure. In shell, I think makejunk | grep foo | tail -4 > fourthings is more popular than > fourthings makejunk | grep foo | tail -4 Having said that, I don’t understand why you would add this, but then, I don’t understand the popularity of ruby or other languages that think adding alternative ways to do things most of the time is a good thing.
- Izkata 6y agoIn shell outside of file manipulation, fourthings=$(makejunk | grep foo | tail -4)
- ultrarunner 6y agoI think I would use this if I were writing a cpu emulator in Ruby (which I wouldn't). It mirrors assembly, but I'm not sure that's a good thing.
- spc476 6y agoIt depends upon the assembly language. Intel defines its opcodes as `dest,src` and Motorola did `src,dest`.
- kevin_thibedeau 6y agoThis hurts readability of code with lengthy expressions. Knowing the target of the assignment is usually more important than the particulars of the expression when you're skimming unfamiliar code. Having the variable pushed out to random locations on a ragged right side isn't helpful.
- kemiller 6y agoOne of Ruby's philosophies is to provide multiple ways to express the same fundamental operation so that it can conform to your thoughts instead of forcing your thoughts to conform to it. You can still do it the old way where it makes sense. Whether this philosophy is helpful or harmful is another debate.
- onlyrealcuzzo 6y agoThe fat rocket seems like an odd choice for an operator. It's already used for hashes - and you don't have to put set braces around hashes.
- choward 6y agoUntil youre working on a team and your thoughts aren't the same as everyone else's thoughts.
- msbarnett 6y agoSure. Peer review, making sure that the code one person has written makes sense to the rest of the team, is a fundamental and incredibly important part of pretty much all team-based development projects.
- deleted 6y ago[deleted]
- weaksauce 6y agothat's why having a coding style guide is important and to lint it every commit.
- 6y ago
- jcheng 6y agoRightward assignment is pretty strongly discouraged in the R community, due to the effect it has of burying the lede. That said, I always felt the same about Ruby’s inline if/unless (`puts "still working" unless done`) so maybe it will have a better reception in this community.
- toxik 6y agoInteresting, that it became discouraged. Probably won’t make it into Ruby proper then. I don’t fault them for experiment.
- jcheng 6y agoActually, this is a pretty good reason, and it's straight from the source (creator of S, the predecessor of R): https://stackoverflow.com/a/51548423/139922 https://stackoverflow.com/a/51548423/139922 > When you type a long expression only to remember at the end that it would be a good idea to save the result, a right-hand arrow allows you to perform an assignment without retyping the line. (I don't do this personally, though. I just run the expression and then my next command is `x <- .Last.value`)
- thebelal 6y agoI use right assignment in this way all the time, you should try it Joe :)
- iandev 6y ago> While the above pattern has become standardized, it feels somewhat unnatural as we read most of the spoken languages from left to right. Is this true (the 'unnatural' part)? Reading left to right, `age = 42` can be read as "age is 42" which feels perfectly natural in English. `42 => age` would be read as "assign 42 to age"? This feels more awkward to me. I'm not sure I understand why anyone would want Rightward assignment.
- ianmobbs 6y agoExactly how I feel. This is one of the reasons I'm not a huge fan of R, either
- kevinmgranger 6y agoIf you visualize variables as "boxes" with values in them, "put 42 in age" makes sense.
- qbonnard 6y agoA math tutor of mine was actually pretty angry at computer science for writing things like `a=1; a=2; //so 1=2 ?` I guess he'd rather have the "assign 42 to age"... Except he'd probably read `42 => age` as "42 implies age", which would probably cause him more sleepless nights ;)
- toxik 6y agoHe’d probably like a := 42 which is in a lot of languages actually! Also Erlang and other fp’s do consider = equivalence.
- Izkata 6y agoI noticed a year or two ago when I'm pseudocoding I seem to default to "age <- 42" which I kinda like more...
- choward 6y agoI'm a big fan of immutability and using constantly so I agree with your tutor.
- r00fus 6y agoIs this really just syntactic sugar? None of the examples in the article seemed to show why code would be more readable (array assignment maybe, but the leftward seems just as readable).
- lxe 6y agoWhy? Why does ruby have an infinite amount of ways to do the same thing?
- lillesvin 6y agoAs someone else said in these comments, Ruby offers multiple ways to express things, so you have more options to "write how you think" as opposed to being pushed to "think how the language wants you to write". I'm not saying it's good or bad, I'm just saying that appears to be one of the reasons for it.
- choward 6y agoThis is actually one of the things I first liked about Ruby. Then it became one of the main reasons I started disliking Ruby.
- throwaway4007 6y agoIt seems the opinionated, directive "there's only one way to do it" approach is winning over the hacking around, "wrapping around your mind" approach. Lisp and Perl have had their times under the sun, now it's all about Python and Go. Perhaps these things are cyclical.
- drusepth 6y agoI'm just happy that there's still a popular language around that lets me write how I think (or however _I_ think would make the code look the best), so I don't have to suffer through using languages that direct how I have to write every little thing. Having both options is nice!
- lillesvin 6y agoI'm using both Ruby and Go a lot (also Elixir, PHP, Bash and others). I wouldn't even say that they solve different problems for me, it's more a matter of how I need the problem solved. If I need something that runs on other OSes than my Linux box preferably with as few dependencies as possible, Go. However, I can probably code it faster in Ruby, so if it only needs to run on my machine or if I know Ruby's available where it needs to be run, then I'll probably go with Ruby. I think, instead of arguing which is better, the argument should be about whether they're useful. And for both Go and Ruby that's an "absolutely!" from me.
- adamzapasnik 6y agoI love Ruby and its 10th ways of writing code to achieve same thing... Eh, there is a reason why Golang has such a huge popularity.
- jaynetics 6y agoTo counter some of the complaints regarding readability, a major use case for this is simply hacking stuff together in the REPL. Sometimes you notice you want to have your result as a variable when you've just typed a line, and other solutions for this problem (Ctrl+A or ENTER plus foo = _) are not universal. Disclaimer: I'm not a core dev but saw a discussion amongst them about such use cases.
- mcphage 6y agoThis is the exact reason I've wanted this, for a long time. I even asked Matz about it a conference once, probably 10-ish years ago.
- stouset 6y agoThis is a completely unnecessary feature. `_` is always assigned to the value of the previous expression. >> 4 + 2 => 6 >> _ => 6 >> "abc" + "def" => "abcdef" >> _ => "abcdef Adding this kind of syntax for something that's already trivial to do is honestly kind of distressing for me as a Ruby developer who's been around since early 1.8. I still strongly believe that the `key: value` hash syntax was a massive mistake. That's a lost battle, but this is getting ridiculous.
- jordoh 6y ago`_` being assigned the result of the last statement evaluated is an IRB feature [1], not a ruby feature - hence the note that it is not a universal solution. [1]: https://github.com/ruby/irb/blob/master/lib/irb/context.rb#L344 https://github.com/ruby/irb/blob/master/lib/irb/context.rb#L...
- stouset 6y agoSo? Why does this need to be in the language when both major REPLs already support it? Why must this be yet another alternative way to accomplish the same thing as the way that’s existed since the first days of the language? There is no argument in favor of this addition. It doesn’t allow anything new, it provides a pointless alternative to the current way of doing things, and the one situation where it’s useful—REPLs—there’s already a feature that renders it completely unnecessary.
- nooyurrsdey 6y agoThis is just feature bloat. Why is this needed?
- ht85 6y agoBecause after a few thousand hours of ruby, when you can - most of the time - tell a variable form a function, or if a function is receiving a list of argument or a hash, you now need another challenge.
- pqdbr 6y agoI'm also not a fan of spending this syntax card on this feature. The ... => ... syntax might be needed for something more useful in the future.
- EsotericAlgo 6y agoHere is a feature ticket. The usage in a data transformation pipeline feels right and appropriate as in comment #20 https://bugs.ruby-lang.org/issues/15921 https://bugs.ruby-lang.org/issues/15921
- choward 6y agoI don't find that reason any more compelling than any other reason I've read. I still don't get why it's better than what already exists.
- adnzzzzZ 6y agoThe example given in comment #20 provides a practical reason for it, in that in some cases it makes things more consistent visually. But mostly these reasons are subjective and some people will be more or less sensitive to them. A lot of programming language design and tool design in general is not completely rational or about functionality only.
- wyuenho 6y agoI'm sorry but this "feature" is yet another design a hacker living in a bubble came up with. Most people think and program in English, or languages very close to English. In English I can read let x be 4ys and some change. I don't know how to read the arrow. 4ys and some change implies x? If this is a feature designed purely for speakers of SOV or OSV order languages like Japanese, that's fine, but the dominant language in technical discourse isn't one of those.
- mudlus 6y agoComprehension follows perception
- dragonwriter 6y ago> I don't know how to read the arrow. As a description (which is an easier translation of this idiom into English than an imperative) “is assigned to”. Imperatively, English tends to prefer verb-object with implicit subject, so we ought to be using a Lisp family language (setq “foo” 42) maps better to English imperative structure than most popular languages that do imperative assignment.
- wyuenho 6y agoComplete English sentences in present tense are infix, with the subject and object clearly stated. Implicit subjects only follow after the first sentence in a paragraph or a phrase. Case in point is the words you've read so far. "are", "follow" and "is" are verbs. This is why most programming languages are in infix notation. Lisp syntax stayed is a historical accident. [1] Arabic is a prefix languages, and people don't program in Arabic. "is assigned to" is passive voice. I think we've all learned in writing classes we should avoid it as much as possible because stating the active voice is clearer. [1]: http://www.paulgraham.com/icad.html http://www.paulgraham.com/icad.html
- dragonwriter 6y ago> Complete English sentences in present tense are infix. . Implicit subjects only follow after the first sentence in a paragraph or a phrase. This is true of the indicative mood, but not the imperative. Giving commands in the indicative mood is not typical.
- m4r35n357 6y agoROFL!
- throwaway4007 6y ago>R language also has a similar way of doing this 42 -> age. Ah yes, the R language, a model of clarity, beauty and lightness in the world of programming languages. Truly an example to follow. (And it's not like anyone ever uses that "feature" in the R world either.)
- bachmeier 6y agoshrug I've used it. The overloading of the equals sign is something that has never made sense for assignment. (Seriously, it's hard to intentionally come up with dumber notation than x = x+1.) I do use -> sometimes. It's more natural to do the evaluation and then figure out where you're going to store the result (particularly when you're programming). This is minor as these things go. Definitely not a big deal one way or the other.
- actuator 6y agoIf assignment is what we are concerned about, we should introduce something like `x := x + 1`.
- jghn 6y agowhy `:=` and not `<-`? The `<-` in R comes from the APL keyboard, and that glyph is an assignment in APL. It wasn't just some crazy invention from Ross & Robert or even John Chambers.
- actuator 6y agoLeft side assignment is still used to us, from maths and most other programming languages, so it keeps things familar. The `:=` has been in use in other langs like MySQL
- _kst_ 6y agoIs "x<-3" an assignment to x or a comparison of x to -3? The same problem led early C (pre-K&R1) to change its compound assignment operators from "=op" to "op=". In early C, "x = -3" assigned the value -3 to x (as it does now), but "x=-3" meant "x = x - 3" (now written "x-=3").
- Animats 6y agoCan you mix left assignments, right assignments, and assignments in expressions all in one statement? That will be great for obfuscating code.
- beervirus 6y agoIt'll probably be implementation-defined...
- zevv 6y agoWell, this is a nice coincidence, Nim also added support for rightward assignments today! https://play.nim-lang.org/#ix=2x7r https://play.nim-lang.org/#ix=2x7r
- moonchild 6y agoFunny you should mention it, raku just got the same feature! https://tio.run/##K0gtyjH7/7@4NEkhMy8ts8Lq0Gpbu0O7NVQSdRRUgGLFCkXlmgrVILatgkqiQi0XV26lgmdeCZCTnmrNxWVipGBrB@MUJ1ZCmP//AwA https://tio.run/##K0gtyjH7/7@4NEkhMy8ts8Lq0Gpbu0O7NVQSdRRUgG...
- kbenson 6y agoDoesn't Raku essentially already have this with feed operator? [1] 1: https://raku.guide/#_feed_operator https://raku.guide/#_feed_operator
- moonchild 6y agoNot quite. For example: > my $x (Any) > 1 ==> $x (1) > 2 ==> $x (2) > 3 ==> $x (3) > $x [1 2 3] If ==> were simply assignment, we would expect x's value to be 3.
- raiph 6y agoThere's no need for a new operator. The R metaoperator respects precedence, associativity, etc. my Int $age; 42 R= $age; say $age;
- samatman 6y agoAlright, I did in fact chuckle, out loud. But I gotta ask: does it have the correct precedence? And sure, throwing some superficial math at the problem works. But is that a coincidence? I guess what I'm asking is: how does Nim know that `=>` is infix? How does it derive the correct precedence? It looks like spooky magic, but Nim is pretty well-designed in my experience: what's going on here?
- 6y ago
- jbackus 6y agoRuby's parser is notoriously complex; if I remember correctly, only a few members of the core team even know how to maintain it without introducing regressions. The craziest part of this is that Ruby does not provide a full featured Ruby parser, so its entire static and dynamic analysis ecosystem depends on a (actually very high quality) 3rd party parser, begrudgingly maintained by someone who (AFAIK) doesn't even write Ruby anymore: https://github.com/whitequark/parser https://github.com/whitequark/parser When I see new language features like this, I think of how Ruby's entire tooling ecosystem depends on the dramatically underfunded (and therefore primarily goodwill) efforts of high output maintainers like whitequark and a few others. Ruby's highly dynamic and untyped nature means these tools are all the non-runtime guarantees you can get, basically. Epitome of digital infrastructure. Consider asking your company to fund some of these people: * https://github.com/whitequark https://github.com/whitequark (maintains parser) * https://github.com/sponsors/bbatsov https://github.com/sponsors/bbatsov (maintains RuboCop) * https://github.com/sponsors/mbj https://github.com/sponsors/mbj (maintains unparser and mutant) --- As context, I know this stuff intimately because I used to contribute heavily to most static and dynamic analysis tools in the Ruby ecosystem (https://github.com/backus?tab=overview&from=2017-12-01&to=2017-12-31 https://github.com/backus?tab=overview&from=2017-12-01&to=20...) and used to track new ruby changes really closely: https://cognitohq.com/new-features-in-ruby-2-4/ https://cognitohq.com/new-features-in-ruby-2-4/
- marcandre 6y ago`parser` is indeed a fantastic gem. @whitequark is the initial author but today it is maintained by @iliabylich
- hardwaregeek 6y agoIs Ripper dead? I attempted to do some minor work on Ripper and it was profoundly painful. My explanation for Ripper boiled down to a domain specific language in parse.y comments that gets translated into C via a very confusing Ruby script, which manually calls Ruby VM functions, that wait for it, are dynamically defined. This constructs a parse tree. If Ripper is still getting maintained, I'm seriously impressed.
- 6y ago
- jasonrojas 6y agoWhen can we start writing ruby bottom up?
- thysultan 6y agoLeft is right, bottom is up, and the world is upside down.
- e12e 6y agoUh.. I'm not sure I like this, in a language that already has a similar boolean operator (although I suppose that goes for all uses of such "arrow" operators). But still: a = 2 b = 1 b >= a # false b >= a => a # assign false to a? b => a # assign 1 to a?
- dragonwriter 6y agoIt already has at least two different uses for the exact sigil "=>" (hash construction, identifying capture variable in a rescue clauses), which is probably more significant than that it has a kinda similar sigil used as a comparison operator. Like natural language (but unlike programming languages constructed with thought toward ease of automated parsing), Ruby syntax is quite context sensitive.
- e12e 6y agoI forgot one, or two: b <= a # true b <= a => b # assign true to b? I'm not too thrilled about the hash-arrow - but I think it's a bit more obvious from context.
- lacker 6y agoThis is true to Ruby's Perl heritage. There is more than one way to do everything, even the most basic of operations. Quiz: what does the following Ruby code do? a = b => c = d
- regularfry 6y agoMakes me reject the PR for lack of clarifying parentheses.
- copperx 6y agoDo you really punish everybody else because you can't remember precedence rules?
- deleted 6y ago[deleted]
- regularfry 6y agoDo you allow code into your codebase that isn't obvious on a first read?
- JadeNB 6y agoI've always liked the good old Perlism [$a => $b]->[$b <= $a] for the minimum. (I think this is from Effective Perl Programming, but I couldn't find it at a glance.)
- drchopchop 6y agoSo, a = b becomes equivalent to b => a. However, you already construct hashes like hash = {:a => b}. Perhaps we can also add reverse hash construction like hash = {b = a} for consistency (and additional madness)
- ww520 6y agoI like it. The next step is piping result forward. 1.2 + 2 | double | abs => result
- transfire 6y agoI wish they pay more attention to real issues and potentials. e.g. The Refinement design is half-baked -- Can't refine module methods, can't DRYly reuse monkey patch code as refinements...
- dgellow 6y agoBut... why?
- rsanheim 6y agoI love Ruby. I've been working with it as my primary language for 15+ years. Its sad to see how they keep adding new, arcane syntax for fairly obscure use cases, seemingly without any real clear justification. I wish Matz would raise the bar on these changes - Ruby is mature and already has a very powerful, complicated syntax that gets tricky for corner cases. I appreciate "more than one way to do it", but not everything needs to have ten ways to do it when the first three ways work fine.
- bfuclusion 6y agoThe right way to do this is the way Prolog does it. It doesn't matter if you say VAR = 12 or 12 = VAR or 1,2,10 = A, B, C It does whatever it takes to make the left and the right sides equivalent to each other.
- thrwn_frthr_awy 6y agoThat is interesting. How does it work when a variable is on each side? foo = 1 bar = 2 foo = bar
- nemetroid 6y agoIt will share with you its wisdom (the last line is printed by the interpreter): ?- FOO = 1, BAR = 2, FOO = BAR. false.
- JadeNB 6y agoAnd if you haven't bound them previously, it does exactly the right thing, and regards them as now the same variable. ?- FOO = BAR, FOO = 1, print(BAR). 1
- thrwn_frthr_awy 6y agoThat’s neat. Is there a separate syntax for var to var assignment or are variables immutable in Prolog?
- nemetroid 6y agoVariables are immutable, but note that it's the contradiction that leads to the "false" response, there's no issue with the assignment itself: ?- FOO = 1, BAR = 1, FOO = BAR. FOO = BAR, BAR = 1.
- bfuclusion 6y agoErlang is interesting too here, in that it basically works the same way (unification essentially via substitution). If you can't make it work, a program exception is thrown instead of a false language. This all makes sense since prolog talks more about logic, and erlang is GP language.
- deleted 6y ago[deleted]
- drusepth 6y agoMore HN discussion on this topic from 6 days ago: https://news.ycombinator.com/item?id=24369892 https://news.ycombinator.com/item?id=24369892
- dragonwriter 6y agoRuby, it should be noted, already has experimental support for rightward assignments by way of pattern matching, so this is really TMTOWTDI.
- gscho 6y ago(There's more than one way to do it)
- kazinator 6y agoAwk rightward assignment: $ awk 'BEGIN { "echo foo" | getline var; print var }' foo
- Proven 6y agoIs there really nothing else to improve? More unnecessary "features"...
- Igelau 6y agoThis would be nice for situations where you have a lot of method calls daisy chained together. Like builders or Java Streams. DoThing() .withSomeOtherThing() .onSundays() .withCharset(Blah.BLAH) .betterAddThis(x -> { ret stuff() }) .build() => turducken The whole assembly of the variable 'turducken' is drifting rightward. By the end we want to get to the point rather than backtrack.
- kazinator 6y agoIt's possible to have a language design like this: DoThing() .withSomeOtherThing() .onSundays() .withCharset(Blah.BLAH) .betterAddThis(x -> { ret stuff() }) .build() .into(turducken) Where a.into(b) is really (into a b), which is a macro sugar for (set b a) and not a function.
- actuator 6y agoUgh! I love that Ruby is expressive but this will just add confusion when a developer moves to Ruby for the first time. It adds a mental burden to be aware about all these rules.
- ericb 6y agoI love ruby, but this is awful. Hope it goes away.
- awwaiid 6y agoUmmm. Feel like I'm being trolled.
- nchelluri 6y agoi was kinda shocked to see all the negativity in this thread. i looked at this post and thought 'beautiful' and kinda mind-blown at the simple elegance of it. ruby is one of those languages that was cutting edge in 1995 and is apparently cutting edge today. it writes and reads like nothing else. it can be made very, very, or too terse, but it can be made to read simply and concisely and clearly with an economy of characters spent. i also am not a huge fan of the metaprogramming madness. but ruby is a beautiful language and i definitely 'think highly' => sentiment this post.
- matheusmoreira 6y agoI expected this new feature to use the -> token but they went with => instead. Is there any reason why they overloaded the hash rocket? Even the simple examples in the article look like somewhat malformed hashes to me! 3 => box_height [170, 65] => height, weight traits => height, weight How does the parser tell them apart?
- dragonwriter 6y ago> Is there any reason why they overloaded the hash rocket? The fact that it's used for a kinda similar purpose in rescue clauses is a factor. > How does the parser tell them apart? Unbraced hashes can only occur in last-argument-of-function position, so unless it's naked (not a parenthesized subexpression) in that position, it can't be an unbraced hash.