18 ms·
Ruby's Creed
- stevebmark 8y agoThis is a good reminder as to why Ruby is often called "the bad parts of Perl." I really appreciate other programming language ecosystems (almost any modern ones besides Ruby) that have abandoned things like this as bad practice, while Ruby continues to double down on it.
- woodruffw 8y agoThat's funny, I usually hear Ruby referred to as "the good parts of Perl" (and Google searches for those phrases suggest the same[1]) -- there's no sigil conjugation, objects are first class, and there are fewer magic variables/idiomatic usages of magic variables. I agree with the author that 2.7's new block syntax is a step in the wrong direction (and that safe navigation/method reference are a little uglier than they need to be), but I think Ruby has otherwise done an exceptionally good job of taking the best parts of Perl and combining them with the best parts of Smalltalk. [1]: I only get 1 Google result for "the bad parts of perl" and about 1000 for "the good parts of perl".
- kenhwang 8y agoI definitely see Ruby as Perl's spiritual successor. I would say it's one of the few languages other than Perl that can be considered "write optimized". Ruby makes it very very easy to just write code that just works. Just, a lot of code later you have huge monstrosity of rot that's almost impossible to maintain; I think that happens with all large codebases, Ruby just gets there faster.
- rlue 8y ago> I definitely see Ruby as Perl's spiritual successor. Matz has said this himself: * "I chose the name of the language from the jewel name, influenced by Perl. Although I named Ruby rather by coincidence, I later realized that ruby comes right after pearl in several situations, including birthstones (pearl for June, ruby for July) and font sizes (Perl is 5-point, Ruby is 5.5-point). I thought that it only made sense to use Ruby as a name for a scripting language that was newer (and, hopefully, better) than Perl." (https://lingualeo.com/tr/jungle/231625 https://lingualeo.com/tr/jungle/231625) * "Ruby inherited the Perl philosophy of having more than one way to do the same thing. I inherited that philosophy from Larry Wall, who is my hero actually." (https://www.artima.com/intv/ruby3.html https://www.artima.com/intv/ruby3.html)
- petre 8y agoYou have a huge monstrosity if you or someone on your team is sloppy. I guess you’ve never seen a Drupal or Joomla codebase before. Or JavaScript projects that pull a myriad of junk dependencies. We have a Perl codebase which is actually quite clean. Mojolicious also helps a lot to keep it nice and tidy.
- jimbokun 8y ago"and there are fewer magic variables/idiomatic usages of magic variables" ...although that seems to be heading in Perl's direction, with the positional block argument variables convention.
- drstewart 8y agoThings like this which they only just introduced and you didn't know about until this article?
- mclehman 8y agoI'd say the strongest possible interpretation of what stevebmark said would include older additions to the language such as from this section of the article: --------- Here’s a list of changes and additions that I certainly never needed (or wanted): Ruby 1.9 hash literals Refinements %i literals Rational/Complex literals (2/3r, 2+1i) Endless ranges (1..) Safe navigation operator (&.)
- rlue 8y agoI think what drstewart is getting at is the vagueness of stevebmark's claim: > I really appreciate other programming language ecosystems... that have abandoned things like this He doesn't articulate what "things like this" are, and instead leans on bbatsov's critique, though it's not clear how. It seems you're suggesting he means "the particular syntax additions bbatsov doesn't like," but that doesn't make sense, either—you're telling me he means that other language ecosystems have abandoned Ruby 1.9 hash literals, refinements, %i literals, etc.?
- hirundo 8y agoOne of the good parts of Perl that Matz embraced was TMTOWTDI. https://en.m.wikipedia.org/wiki/There%27s_more_than_one_way_to_do_it https://en.m.wikipedia.org/wiki/There%27s_more_than_one_way_... The author of this piece seems to simply disagree that this is a feature, and that's a widely held, not unreasonable position. But the described changes are just a further expression of that long held design philosophy.
- rlue 8y agoHm. Personally, I think there's a big difference between "there's more than one way to do it" and "there are some extra, esoterically unreadable ways to do it". I definitely don't know enough to be questioning Matz's decisions, but the burden of backwards compatibility means there is a material cost to adding features that end up not getting widely adopted, and if that cost is not accepted by folks like Bozhidar (who must now update Rubocop to recognize this syntax), it gets passed on to the Ruby community in general, who must instead deal with a decaying and fragmented language ecosystem.
- whalesalad 8y agoI’m a huge fan of all the features this person is complaining about.
- rlue 8y agoI like them too, but only because I've been programming Ruby for a while now, and enjoy picking up new tidbits as I go. If I were new to Ruby (or programming in general), I think this would reasonably constitute feature bloat that would make it a less approachable language. Also, bear in mind that "this person" is not just any Joe Blow but Bozhidar Batsov, maintainer of Rubocop and (as an author of the Ruby Style Guide) something of an authority in the Ruby community.
- olingern 8y agoBut do any of these features progress the language or provide any performance benefits? Most read as syntactic-sugar (I understand Ruby is about developer happiness) and unnecessary.
- prophetjohn 8y agoThey progress the language by adding syntactic sugar. Many Ruby programmers aren't waiting around for Ruby to suddenly become fast. If that happened it'd be great, but most code I write isn't performance critical, so it's okay if they just give me a feature where i can write `user&.name` instead of `user && user.name`
- omaranto 8y agoReally? Including the @1, @2, positional arguments? Why are you a big fan of them? Maybe I'm missing something that makes them great.
- barrkel 8y agoI almost invariably use x for @1 in existing code; for manipulating hashes, I almost always use |k, v|. If I'm working with pairs, |x, y|. What's the big difference between x and @1? y and @2? It doesn't really feel that significant to me. I'm a bit meh on the feature. I'm suspicious of lambdas / blocks that take more than three parameters, and for three parameters I'm good with |x, y, z| or |a, b, c|. I do think that giving them meaningful names is usually obscures intent more than it clarifies; |k, v| for maps and |i| for loops self-document well enough.
- djur 8y agoRuby 1.9 hash literal syntax was introduced as an evolutionary step toward keyword arguments. If the former didn't exist, the latter would be a special syntax similar to but incompatible with the existing idiom to use a hash in terminal argument position as keyword arguments. That is, without the ability to treat foo(:a => 1, :b => 2) as equivalent to foo(a: 1, b: 2), you end up with two versions of every API -- "hash kwargs" and "real kwargs". And you'd similarly lose the ability for existing APIs to migrate to explicit keyword arguments from hash kwargs. Would I prefer it if Ruby had started out with Crystal's named argument syntax? Absolutely. But Crystal had the luxury of starting from scratch without any need for backwards compatibility.
- DarkWiiPlayer 8y agoI think Rubys vararg syntax is terribly unintuitive and inconsistent though.
- djur 8y agoIt is, but it was also a compromise meant to maintain compatibility with existing code. And I mentioned it specifically because the OP identified keyword arguments as a good new feature but the new hash syntax as bad.
- Jenz 8y agoCrystal is very exiting ATM, next release is scheduled to come with multithread preview.
- peteforde 8y agoI was sad to see => aka "hashrocket" syntax go, and it still slips in sometimes... but it is nice being able to use the same hash syntax in Ruby and JS. What I'm intrigued by is the author's suggestion that there's more to the change than a relatively minor syntax change. Is there more to the story? I always assumed that both syntaxes are functionally identical.
- rlue 8y ago> What I'm intrigued by is the author's suggestion that there's more to the change than a relatively minor syntax change. I don't remember him saying that about hash literals. All I caught was that he doesn't like how it's limited to expressing only symbol-keyed hashes. Maybe I missed something, though.
- peteforde 8y agoThat was exactly what I didn't pick up on, and you took for granted. I only rarely use non-symbol keys, so it hadn't dawned on me that the new syntax was, in fact, knee-capped.
- bluehavana 8y agoOne can only ever use Symbols as keys in the 1.9 hash literal syntax, whereas complex objects responding to `#hash` can be used as keys in hash rocket literals.
- chrisseaton 8y ago> I was sad to see => aka "hashrocket" syntax go It hasn't gone - still there as of 2.6.2 and still the only way to create non-symbol keys in a literal.
- dasyatidprime 8y agoRegarding the @ positional-argument syntax: I mean, my use of Ruby dropped considerably years ago, but from a Ruby-philosophy standpoint it looks fantastic to me. Having to constantly make up (usually single-character anyway) names for those parameters in map/filter chains was one of the ugliest parts of the language, especially when there was no actually-good name for things like temporary tuples, and the Smalltalk-derived (I think) syntax for block parameters is so visually heavyweight: { |…| … } { |…| … } { |…| … } where all the stuff in the || is close to useless, as opposed to just { … } { … } { … }. Method references passed with &, while separately useful, are not a good substitute; they're often less readable (to me) because the form of the expression is obscured, and they break down much faster, for instance as soon as you need any single other argument, rather than just when the block gets complex enough that the parameter names become important for readability. I can appreciate that it moves farther away from “requiring things to be explicit means you get fewer accidental barriers to moving code around or increasing/decreasing complexity”, though, as some of my recent work has been in Java and I've had an eye for that aspect of it. But the next time I do anything in Ruby I'll be remembering that this is there.
- vbsteven 8y agoI like Kotlins solution for this. If there is only one argument in the lambda/block and the type is clear from the context you don’t have to declare it and you can use the ‘it’ keyword instead.
- pkulak 8y agoAnd one parameter is 99% of the cases. If you have more than one, you should probably name them anyway.
- dragonwriter 8y ago> And one parameter is 99% of the cases. In Ruby, the two-parameter hash-iteration case alone is common enough that that's not true. > If you have more than one, you should probably name them anyway. In a single line block, I think that often impairs rather than enhances readability.
- riffraff 8y agoShouldn't this h = Hash.new { @1[@2] = "Go Fish: #{@1}" } Be h = Hash.new { @1[@2] = "Go Fish: #@1" } For maximum syntax golf? Or are positional arguments not working the same way as instance variables wrt to interpolation?
- deleted 8y ago[deleted]
- int_19h 8y agoNumbered arguments for short lambdas is not a rare language feature, and of them all, Ruby (and Perl) is exactly what I'd expect to have it.
- dasyatidprime 8y agoAs for refinements, the use case I imagine is when you need to be defining a method that dispatches on the type of objects that are not “yours”, especially where that dispatch plausibly needs to be extended with more types by other code. (If it doesn't need to dispatch on type, you can just define a function in a module and be done; if the dispatch never needs to be extended, you can kinda do the same thing, but it's much uglier.) Serialization is the most common case where I've run into this, where objects of different types need to be serialized differently; indeed the https://bugs.ruby-lang.org/projects/ruby-trunk/wiki/RefinementsSpec https://bugs.ruby-lang.org/projects/ruby-trunk/wiki/Refineme... gives “ToJSON” as an example refinement. A different way of handling this exists in CLOS: methods are defined on generic functions, which are are namespaced in packages just like class names are, but importantly, the class package and the generic package have no pervasive special relationship: a class doesn't “own” methods. So I can defgeneric extravagant-imperial-licentiousness:freeze and then define methods for it on all sorts of types, and it won't clash with someone else's jawbreakingly-simplistic-obdurate-numbness:freeze method. A consumer of either or both methods can choose to import one of the symbols and/or refer to either or both of them by their full names. In Ruby, I've observed two “traditional” ways to do this: (1) add an ugly decoration to the method name which can never be elided (which is what I did in some internal projects, and then I added a prettier module function for external consumption that just trampolined to that method); or, seemingly more commonly and much worse, (2) ignore collisions, define whatever name you like on whichever classes you like, assume that you have dominion over your favorite short name and/or that the semantics are “obvious” and universal and that no one will ever load a library that does it some other way on top of yours and thereby break all the code depending on your version, and thereby, when that sometimes happens, land the hapless integrator in the dreaded “monkey patch hell”. Refinements supposedly provide a better way to evade (2). I didn't get to play with them enough to be sure that they do, and in particular ISTR this might not actually let you have a fresh method name which can also be extended elsewhere without requiring all consumers of the method name to be aware of all the extension refinements, which if so seems like a disaster for serious use. I feel like there's a better mechanism for this hiding somewhere in Ruby design-space, but I don't know what it is.
- joelbluminator 8y agoI don't necessarily agree but it's a fair argument and well written. It's probably impossible to satisfy everyone; if Matz drops these features the people who want them (and I'm sure they exist) will yell that the language is stagnating compared to Python 3 and Node. If he adds them, we are adding bloat. There is constant pressure to add more stuff to "evolve" the language, hopefully the community steer through this pressure to the right direction.
- johnlinvc 8y agoIt's interesting to see that languages try to get features that other languages have. In Swift they have position argument in block from the start users.map{$0.name} now they want to add Ruby's &:attr feature[1] users.map(\.name) Maybe the best feature user want is the one other languages have. Or this is just Blub Paradox[2] in real life. [1]: https://github.com/apple/swift-evolution/blob/master/proposals/0249-key-path-literal-function-expressions.md https://github.com/apple/swift-evolution/blob/master/proposa... [2]: http://www.paulgraham.com/avg.html http://www.paulgraham.com/avg.html edit: grammar
- rlue 8y agoAnother way to look at it is that cross-pollination is a good measure of the merit of a language feature. If one language invents it another a dozen other popular languages adopt it, it's probably a good idea, and its proliferation is good for everyone.
- pmontra 8y agoThey both look ugly to me. Furthermore, there is a cognitive burden. There is nothing to think about in users.map{|u| u.name} I even use to write it more explicitly as users.map{|user| user.name} The short forms users.map{&:name} users.map{@1.name} are like "oh wow, what does that mean?" and I've been using Ruby since 2005. And the ugliness...
- ben-schaaf 8y agoI don't actually mind the syntax that much, `&` on a symbol just gives you a proc for calling `send` on the first argument. What bothers me is the limitations. If you're going to have special case syntax to avoid having a useless first argument why not go all the way? Something like this would have made a lot more sense imo: users.map { .name.uppercase + '3' } numbers.map { * 3 }
- majewsky 8y agoThe last one looks a lot like Haskell: map (* 3) numbers
- olingern 8y agoPersonally, even though `.then` resembles A+ promise-like syntax -- I find that it feels more idiomatic than `yeild_self`. I remember Matz talking about this at RubyKaigi, and I wondered how it would work in practice; however, I enjoy that syntax much more than its predecessor. Addressing some of the author's comments, I would agree with: - Endless ranges - The "@" syntax names.each { puts @1 } I would love to see more dialogue on how these changes _could_ positively affect the language. Also, if these are adopted widely, there will be the inevitable Rubocop rule telling you that it prefers this syntax over the "legacy." I love Rubocop, but sometimes I feel there's no end to the journey to writing 'idomatic' ruby and the continued language sprawl definitely does not help on this front.
- DarkWiiPlayer 8y agoah, that topic... Well, for what its worth, I mostly agree with the author, except I never felt Ruby has made me "happy" more than any other programming language with at least some semi-decent features. Its problems make up for its features and, at the end of the day, it has enough annoying parts to make me angry at times. The new features, of course, is pointless. It solves no problem, but brings with it the typical downsides of adding a new language feature. It reinvents the wheel, but makes it triangle-shaped, and tells you it's only meant for crash-tests anyway.
- 59nadir 8y ago> Well, for what its worth, I mostly agree with the author, except I never felt Ruby has made me "happy" more than any other programming language with at least some semi-decent features. In surveys, Ruby hasn't (to my knowledge) scored highest in developer happiness for a very long time (if ever). Languages that don't tie themselves to a subjective tagline like that do, though. Rust, for example, has a pretty clear direction and mission and has some of the most excited and happy users in every survey I've seen. Trying to talk about developer happiness as some kind of defining characteristic has always been a bad idea and I think, ironically, you end up with unhappy users by using it as an ideal to make change in your language. I think it only gets worse when the paradigm the language is built on and how it expresses that paradigm is also susceptible to more bugs than the alternatives. The only real way to optimize for developer happiness is to optimize aggressively for simplicity. The entire foundation of Ruby is a barrier to that and it doesn't have the good tooling, interactivity or introspection of something like Smalltalk to handle that.
- burlesona 8y agoSyntax is hard. In general I think that adding a simple numbered argument access for blocks makes sense, and something like swifts $ syntax would look pretty natural, ie: ``` books.map { $0.title } ``` In the Ruby lang discussion on this they go through a dozen different possible syntaxes and they all have issues -- for example the $ is problematic because Ruby currently uses these for global variables. Even so, IMO using the `@` symbol for this will make the language harder to learn. It's not a very nice thing to have syntax that is almost ambiguous to the human. ``` books.map { @prefix + @1.author } ``` I teach Ruby to a lot of engineers (of all different experience levels), and one of the nice things is that it's so easy to pick up and be productive quickly. But there are bits where it takes some practice, and I'm not looking forward to telling people, "The at sign means it's an instance variable. Well, except if you're in a block and it's @1 or @2 or something, in which case it's a positional argument." Oof.
- ololobus 8y agoI absolutely agree, interference with instance variable/method alias '@' looks awkward. For me it seems a little bit against Ruby-way.
- vidarh 8y agoInstance variables can not start with a digit, so this works fine from that perspective.
- jimbokun 8y agoSo another exceptional edge case to learn.
- vidarh 8y agoGiven how little of Ruby syntax most people know before they're able to read and understand Ruby, I don't see that as much of a concern. "@" suggests it's probably local of sorts, the number makes it clear it's not an instance variable, and the absence of |somevar| in a chained block will strongly suggest it's an argument, without having to know the precise details. There are many additions to Ruby I don't care much for, but this is one of the most intuitive I've seen.
- kureikain 8y agoThe author starts with ` named block parameters`. But Clojure had this. I always Ruby has similar thing. In Clojure you can do `%1` or `%2` similar to `@1` `@2` in Ruby. So I guess the feature were inspired by Clojure. Even Elixir has it. The author is also a Clojure developer so I found it's weird that he hate that Ruby syntax. However, at the same time, I totally agree that Ruby has so much more thing to work and improve, not to worry about these thing. As a Ruby dev, I don't want a new syntax to catch up with JavaScript where new syntax come up every weeks. Ruby should focus more on type system, performance. Even some type hint like PHP would be very helpful. Lots of Ruby gem kind of introduce type. Example in Mongoid: class Person include Mongoid::Document field :first_name, type: String field :middle_name, type: String field :last_name, type: String end I would love to have some type so we can use it directly. Another weak point of Ruby is its module system :(. Some module system like Python would be great where we can load thing and alias them to avoid conflict.
- lloeki 8y ago> In Clojure you can do `%1` or `%2` similar to `@1` `@2` in Ruby I very much like the feature itself, esp. for one liners you can come up with on a pry prompt. What I very much dislike though is the use of @ which is a glorious hack if there is any since currently @ tokenizably resolves to 'instance variable' in many a brain (and @@ to class variable but those should die since class variables can be implemented as instance variables of an instance of Class which is both much more elegant and less prone to corner cases, but I digress). In fact I'd very much be happy to use %1 as a syntax since that would match the "%1" placeholders in strings right away. "%1" in strings, \1 in regex for backrefs, $1 for regex groups, {%1} in blocks somehow works as a metapattern, but reusing @1 vs @myvar is such a mismatch that it brings a terrible cognitive dissonance (just see e.g how in [1, 2, 3].each { @1 + @I } both @ have different scopes!). I can see the argument coming (if it did not already happen) that "OMG this is going to special case stuff in the parser so that the % method can be separate from this new syntax! plus this may break existing code!" to which I reply %1 won't ever appear in the same place in the AST as a modulo operator with a right hand integer argument and this is your job as a language implementor to make the dev job easy, and it's crackpot anyway since that will already special case the @ syntax in the parser. Simple is hard, bailing on implementing the simple solution as a language implementor even if it's internally tough is a copout.
- undecisive 8y agoAs a rubyist of 10 years, a few thoughts. I wasn't aware of these upcoming features, but to some extent they make a lot of sense. Except... yeah, those symbol choices. I agree that @1, @2 etc look totally wrong, and maybe that subjective view will change - but scope-wise, having @-variables that are nothing to do with the current instance would utterly ruin scannability. On the other side, I suspect Rubocop will very quickly react to outlaw it, so no big problem as far as my code goes. I very rarely use &method(:foo). I find it ugly, and &:foo is more useful in 98% of circumstances. Maybe I would use it if it were shorter - but .:foo seems wrong. I feel like it would, again, be harder to scan. That said, the more I let it sit in my brain, the less passionately I object. > Still, I was disappointed when the safe navigation operator as introduced, as it basically acknowledged that it’s fine to return nil I think this is indicative of the crux of the problem. Optimizing for programmer happiness implies you know what programmers need. Some programmers have no problem working with nils - we've long since accepted them, even embraced them. The safe navigator pattern almost gave us a way of implementing a null object pattern with literally no work, while screaming out to the world "this method accepts nil, so watch out". I would much prefer code that accepts nil as a fact of life than code that denies its very existence. I feel that "hacky code" will be well served by these changes, and I think that "production code" will be better served by tight Rubocop rules. So, everyone's happy!
- lloeki 8y ago> I very rarely use &method(:foo). I find it ugly, and &:foo is more useful in 98% of circumstances. Maybe I would use it if it were shorter - but .:foo seems wrong. I feel like it would, again, be harder to scan. Ever since the near-death of the hash rocket syntax have these days been coming as you can already see the same line of thinking coming out of it. Superficially the introduction of the symbolic hash syntax that aligns it with yaml/js and saves a few chars was locally good for readability, yet fundamentally it could not deprecate the hash rocket because if one of your keys is not a literal symbol then you're toast and have to use hash rockets in your code, which means you end up with mixed patterns throughout your code and thus have to 1/ keep two tokenisation branches inside your head and 2/ make decisions about the syntax to use every single time you write a hash, which looks like small things but long term sand in a gearbox grinds it to a stop. At some point you end up with all those little syntactic sugary things which make sense locally but which overall makes for increasingly heavy cognitive overload and you end up in a tar pit through normalization of deviance. When Ruby began to take off, people said it was like Perl's heir, only readable. Today as both a Rubyist and a former Perlist, I do long for Perl (and violently enforce readability rules on Ruby projects I own)
- 59nadir 8y ago> In my opinion half-baked micro-optimizations add nothing, but complexity in the long run, and should be avoided. I’m really worried that Ruby has been gradually losing its way and has strayed from its creed. It seems to me that "Optimizing for programmer happiness" is bound to end up with these half-baked micro-optimizations. The very first example of what the author considers the essence of Ruby is a perfect showcase of that, in my opinion. Without a criteria that establishes whether or not you've now optimized more or less for programmer happiness, your users will just create blub fortresses that they stay in. Since the entire tagline is based on subjectivity and the users don't have any meaningful foundational principles to appreciate, all they have is their opinions on that feature they don't see why they need.
- jsant 8y agoIn “optimizing for programming happiness”, there's much more left to be defined than ”happiness”. I think the biggest ambiguity here is ”programming”. ”Programming” can mean a lot of things, and I think Ruby still tailors too much to the ”be able to scrap things together somewhat elegantly” meaning. But once the project takes off, you want performance and safety. Performance is constantly improved, but it seems safety is completely overlooked. TypeScript & co. proved you can make a type system that doesn't compromise for flexibility, so I think it should be at the core of the Ruby language improvements discussions.
- majewsky 8y agoI would like to have a language that has a builtin dial for strictness. The lowest setting (for use on a REPL or when prototyping something) would use dynamic typing with implicit coercions like e.g. JavaScript. But then, as the safety/performance/stability of your code becomes more critical, you can turn the dial higher and higher to get static type checking, then borrow checking, etc. Sort of like how the NPM guys rewrite some critical-path components in Rust, but without having to hop to a different language. Sort of like how a lot of JS devs move to TypeScript halfway through the project, but then again, TypeScript can only go so far because it's shoehorned onto the existing JS, rather than designed in from the get go.
- coldtea 8y ago>Here’s a list of changes and additions that I certainly never needed (or wanted): A, the classic "features before I came to use the language are nice and dandy, features added after I've learnt it are bad" complain.
- misterdoubt 8y agoIt certainly reads that way. The author takes "programmer happiness" very personally here.
- bozhidar 8y agoWell, I'm sorry if it seems to you like this, but there were plenty of features I didn't like in the past as well. :D I just felt that recently things took a turn for the worse. Language design doesn't get easier with time - quite the contrary, because your options constantly shrink. If that's your only take away I guess I've failed to communicate my points.
- wlll 8y agoCompletely agreed. I find it hard to read anything but the simplest of @ positional examples, and code has to be written to be read. I have been writing Go a lot more these days and greatly appreciate the simplicity of language. Coming from a Perl background, and the TMTOWTDI (There's More Than One Way To Do It) philosophy, I've seen how that can make for clever but hard to read programs and I'd have preferred Ruby to err in the other direction.
- intertextuality 8y agoAllowing @1 and @2 instead of |a, b| is a horrible change to Ruby. In the ruby tracker Matz himself states this is a compromise. So now Ruby is getting half-baked compromises that look out of place, all to appease some people making requests. If the requested functionality is so pertinent, then a proper solution should be made, in line with Ruby's style. Not cryptic sigil soup with @ and .:, etc. If a feature exists, it will get abused down the line. I do not want to read Ruby codebases that have @1, @2, @3, etc instead of named variables. We all know that temporary code is permanent. Just making this syntax possible is terrible. I have to say I'm disappointed. I have enjoyed using Ruby for the last ~5 years but I disagree strongly with this syntax change.
- 0815test 8y agoThese are just De Brujin indexes! https://en.wikipedia.org/wiki/De_Bruijn_index https://en.wikipedia.org/wiki/De_Bruijn_index Far more elegant than literal lambda variables, since they save you the trouble of dealing with variable renaming and/or defining a valid syntax for local identifiers.
- intertextuality 8y agoVariable names are a good thing. When I look at someone else's code (or my own, 6 months later) I do not want to see @1, @2, @3, and so forth. I don't care if it's some existing mathematical notation concept or not, we're not discussing lambda calculus here. Naming things properly is a skill we all need to have as programmers. There are (multiple) reasons we don't call things k, d, j, z, o all over the place anymore. And for the record, I actually prefer λx. λy. x instead of λ λ 2. We do not need to be as terse as possible when writing programs or mathematical statements. This is especially egregious for Ruby, a language that has been valued for being quote, "elegant".
- yebyen 8y agoYou know, naming things is hard, and it's not reasonable to argue that your code should always be in the optimal state. There are "on the way" states, and it seems like this feature can be used well by saving you from choosing a wrong name too early in the development stages. Sometimes you haven't decided what a name should be yet. I do not want to see @1 @2 @3 in code 6 months later, either. That's the kind of thing that I'd search for in my codebase before I closed the project, and assign a name before it's too late for me to remember what that bit of code was for. (And look, how handy it's a completely original arrangement of characters that you can even grep for without straining!) But sometimes you don't have a name ready and it's actually better to defer naming the thing until you know what it is. This feature enables that. You can save yourself from picking a wrong name, come back later when the code around that @# has solidified and it's clearer what to call it. I have never seen this feature before this article, but seeing the ways that people are arguing against it has given me a better understanding of the ways that it can be used well. I've just been catching up on my tech lore and I'm watching Sandi Metz talks from RailsConfs gone by. There's one talk in particular "all the little things" where the subject is the gilded rose exercise, and how she would refactor it. In the course of the exercise the code complexity goes up (almost doubles) before the gains are realized, and suddenly there's this huge bit of code that can be safely deleted, now the complexity has gone way down and the code is good. My only point in bringing this up is that there are intermediary states that, if observed in a vacuum, we'd all agree are badly formed and simply not exemplary. This strikes me as an example of one of those features. You can come back and make it better. This is just how it will look "on the way" to something better. (I know, "you won't come back" but that's not an argument that I'm ready to accept.)
- ashelmire 8y agoI agree and disagree. The more features the language has, the harder it is to read. And using @ for positional arguments when it’s already used for instance variables is a questionable choice. But on the other hand, the syntax for these blocks has always been clunky. But Ruby is all about options. You can do things the way you want, when you want. That’s the happiness you achieve. But it does become more difficult to read for newcomers and devs not up on the latest updates, which is a major sacrifice. Some of these new features are blessings though. The safe navigation operator saves lots of checks and I wish I had it in JavaScript and other languages (rather than checking for a property first).
- intertextuality 8y ago> Ruby is all about options Err, is that why things like Rails are convention over configuration? I personally would rather have consistency throughout ruby codebases than various random solutions people have come up with. @1 and @2 is more difficult to read, full stop. It's more difficult for newcomers because it's more random "magic" that one has to learn, and it's difficult for ruby devs when they read other people's code and have to discern what @1, @2, @3 might possibly be. At least variable names give information, if done properly. Matz even stated this was a compromise. I think it's utterly unsatisfactory for Ruby to just accept this as it is currently. There has to be a better solution than @1 and @2.
- kenforthewin 8y agoRuby != Rails. I think it makes sense that the language remains flexible while the framework is opinionated. I probably won't use @1 et al in my projects, that's where enforcing consistency via rubocop comes into play.
- intertextuality 8y agoSure, ruby isn't rails. But a lot of tools are also opinionated (like Rubocop, even.. or Brakeman, etc). One can always change values but there -are- default configurations that people generally tend to go with. Having consistency in the language is also better overall for the community. If you read through a new codebase, having consistent patterns makes that process significantly better. @1 and @2 are only going to make things less readable. People will choose the easier option and never go back to refactor it once completed. It's a horrible change for Ruby.
- ethagnawl 8y agoI like JavaScript's (old?) solution to the indexed argument problem: the implicit `arguments` parameter. I haven't bothered looking into the rationale for why that wasn't carried over into arrow functions, but I miss it when debugging programs written using ES6. I'd be interested to know if anything similar was considered during the discussions around adding indexed arguments to Ruby.
- hombre_fatal 8y agoCould you pitch an example where Javascript's `arguments` improves the code? Especially wrt the positional arg syntax at hand? The only use-case I've seen for `arguments` is to create confusing function signatures with no formal arguments. Your linter could prohibit its usage and your code would be better off. Btw, `(...args) => args[0] + args[1]` works. No special `arguments` variable needed. Not sure why you'd do that over `(x, y) => x + y` though.
- ethagnawl 8y agoBesides debugging, I don't know that I've ever used the arguments parameter to do anything useful. I've leaned on underscore/lodash/ramda when doing anything involving clever involving partial application, shuffling arguments, etc. As I mentioned, though, I like/d `arguments` (I don't write much JS these days) because it gives you lots of debugging information with a simple call to `console.log(arguments);` -- made even simpler courtesy of a Vim abbreviation (`autocmd FileType javascript iabbrev adebugger console.log(arguments)`).
- revskill 8y agoI was happy with Ruby and Rails until when i have to write my own abstraction. (something like has_many, belongs_to in ActiveRecord). Ruby class/metaclass things is really cumberstone to me. It's not about the magic, it's about the complicated data flow through all the class abstractions that push me off Ruby. I prefer functional abstraction to class abstraction whenever i can.
- mirceal 8y agometa programming and the flexibility Ruby has around how it can be achieved are the things that set Ruby in a league of its own.
- StaticRedux 8y agoDefinitely a league of it's own in difficulty of refactoring
- ravenstine 8y agoThat and difficulty introducing new developers to Ruby projects. When so much metaprogramming and abstraction is used, and everyone creating their own DSLs, developers often have to learn new languages every time they are brought on board to a Ruby project. It basically defeats the point of "convention over configuration" in Rails. Rails is fine on its own, but what Ruby allows people to do creates these "elegant" messes that end up being more difficult to learn, requiring people to become "experts". (which I suppose creates job security) Don't even get me started on how lots of Ruby developers don't believe in documentation because the expressiveness of the language makes their code "self-documenting". (i.e. their shit doesn't stink) I actually love Ruby, but I've learned to avoid the advanced features unless they make perfect sense for the task at hand. The Ruby culture, however, is what caused me to appreciate JavaScript; the fact that it contains a simpler set of tools makes the language more readable IMO, despite it being less English-like, and I find today's JS projects much easier to understand than almost any Ruby or Rails project of even modest scale.
- 8y ago
- Dirlewanger 8y agoI don't understand his problem with hash literals. Hash rockets are just ugly and verbose and needed to go (through they're still needed for some object types to be declared as keys). The positional arguments I'm on-the-fence about. I enjoy them in Elixir, but at the same time I wish it had a little more flexibility to name arguments. And I like the clarity that named arguments provide. The `then` alias is also a major improvement; `yield_self` is a confusing and ugly combination of protected keywords.
- jimbokun 8y ago"Hash rockets are just ugly and verbose" Ugh, you make it sound like playing code golf and counting every character automatically leads to the most readable code. Replacing a two character operator with a one character operator, or whatever, is not a significant win for developer productivity. More powerful abstraction tools are what allow non linear productivity gains. Slightly different literal syntax is more a bike shedding topic than anything that's going to help programmers produce better software faster.
- Dirlewanger 8y agoI contend it pretty much is an issue of bikeshedding. Still, it's less code, and I don't really see how `{ key: 'value' }` is not preferred over `{ :key => 'value' }`. Ok I'm done on this issue...
- bozhidar 8y agoThen is also a keyword. :D As for hash literals - I didn't like the addition of the new syntax simply because it's limited to one type of keys. We had a perfectly good universal syntax and introduced a second one just to save up on typing in one common usecase. Not to mention that in the 1.9 syntax you don't use keywords directly but labels, which are different syntactic construct (:keyword vs label:). I think I understand your perspective, but it seems you value typing less and subjective aesthetics and I value mostly simplicity (minimalistic syntax and uniformity being some of its key aspects).
- 8y ago
- alexeiz 8y agoLooks like Tim Toady finally got his hands on Ruby.
- kazinator 8y agoTXR Lisp envy. 1> (mapcar (op list (cons @1 @2)) '(1 2 3) '(a b c)) (((1 . a)) ((2 . b)) ((3 . c))) http://nongnu.org/txr/txr-manpage.html#N-038348D3 http://nongnu.org/txr/txr-manpage.html#N-038348D3
- jacobsenscott 8y agoI'll come to the defense of &. - for better or worse Ruby is mostly used for building database backed web applications where nils are simply unavoidable without some extreme over engineering or awkward idioms. `user&.address&.street` is at least safer than `try` - `user.try(:adress).try(:street)` - will not raise an error that `adress` is not a method. You could try and apply the null object pattern, but then `user.address.present?` is quite a rabbit hole - and frankly nil is the right return value for a user with no address on file.
- mberning 8y agoAgreed. This does not seem that egregious and is way better than .try() or even worse putting a rescue at the end.
- schneidmaster 8y agoYeah, the safe navigation operator is great, and I really miss it especially when I write JavaScript and have to do something like `foo && foo.bar && foo.bar.baz` instead (...which isn't even the same since it returns `false` if something is null).
- lobo_tuerto 8y agoJust use lodash for that. Your example would become: // this won't throw an exception if foo is null _.get(foo, 'bar.baz') And you can even set a default value to return if it is: https://lodash.com/docs/4.17.11#get https://lodash.com/docs/4.17.11#get
- freewilly1040 8y agoThe point isn't that it's an unsolvable problem, the point is that you have to resort to clunky syntax or a 3rd party library to do this. And for something as basic as this, there's probably a number of different libraries that solve the same problem a slightly different way.
- hombre_fatal 8y ago
- jacobsenscott 8y agoI've been primarily a ruby programmer for the last 10 years. I remember when I started to learn Ruby the "there's more than one way to do it" philosophy really bothered me, and I thought it would cause lots of problems. But I just haven't found that to be the case. Even though a lot of these language additions don't add functionality they do make day to day programming more pleasant. Maybe I just kind of think the same way as Matz. I remember I thought &. was going to lead to loads of PHP style abuse, but I haven't seen that. My initial reaction to the new implicit block parameters was also "yuk" for all the reasons mentioned in the article. But I think they will generally be used responsibly for very small blocks, where people would typically just name their vars x, y, z anyway. "There's more than one way to do it" did make learning a little harder, but you spend much more time as an expert than as a beginner, so I don't think languages should be optimized for beginners. As for refinements, I have never used them, never seen them used, and I don't even really remember what they are. I think they were to save us from the evils of monkey patching. But in general the community has learned to monkey patch fairly responsibly, and I've rarely had a problem with it, except with a few fairly old gems. As for new features that I think would really bring ruby to the next level - better functional programming support, better concurrency support, and optional typing would be fantastic (I know, hello Elixir. But I hear typespecs in elixir are meh). Functions are only "first class-ish" in ruby - the block/proc stuff was fairly revolutionary to people coming from Java and C, but it is clunky compared to most any other language with first class functions. Javascript should never do something better than ruby. Good concurrency primitives are also key for language adoption in 2019 - even though simple process based concurrency is simple and safe for probably 80% to 90% of the apps out there - when people choose languages they want the one that will handle 10,000 requests per second using 2 GB of RAM.
- JohnBooty 8y agoAs for refinements, I have never used them, never seen them used, and I don't even really remember what they are. I think they were to save us from the evils of monkey patching. They're pretty cool. IMHO they could be considered a best practice whenever you're reopening a class, whether it's for the purpose of monkey patching an existing method or adding your own. Rather than overriding, say, `String#upcase` on a global basis you could override it in some reduced scope, like within some specific class. This is arguably not ideal, but I would say that it is more explicit and less dangerous than a global monkey patch. Or, if you have a use case for adding a bunch of new methods to `String`, you can go ahead and add that `String#decorate_with_random_emoji` method you've always dreamed of - but only within particular scopes, such as a particular Rails presenter or something. I think this is often better than polluting the `String` class globally, or having some utility class full of methods like `MyAwesomeStringUtils.decorate_with_random_emoji(some_string)`. In most cases I would say that these refinements belong in a mixin that classes can explicitly opt into -- `include my_string_refinements` or whatever.
- examancer 8y agoI learned some cool new features coming in Ruby 2.7 and I am very much looking forward to them now. The rest of this post is drivel, complaints, and ends with begging questions answered in his opening bullets. How does this optimize ruby for happiness? Flexibility and choice. Backwards compatibility is maintained. You can write the same old ruby you wrote before if you want to avoid change. I'm very happy to have some new syntax tools in the toolbox.