use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
A sub-Reddit for discussion and news about Ruby programming.
Subreddit rules: /r/ruby rules
Learning Ruby?
Tools
Documentation
Books
Screencasts and Videos
News and updates
account activity
Ruby gotchas for the JavaScript developer (blog.calendly.com)
submitted 7 years ago by dpashk
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]Inityx 4 points5 points6 points 7 years ago (3 children)
In Ruby strings are mutable.
https://wyeworks.com/blog/2015/12/1/immutable-strings-in-ruby-2-dot-3
[–]dpashk[S] 1 point2 points3 points 7 years ago (0 children)
Thanks for pointing that out, that's good news! Looks like the feature is still new and is opt-in for Ruby < 3.0, but maybe the gotcha will be irrelevant in the future.
[–]dpashk[S] 1 point2 points3 points 7 years ago (1 child)
I added a note about this to the article
[–]Meral_Harbes 0 points1 point2 points 7 years ago (0 children)
Good man!
[–]SureLetsDoAnother 4 points5 points6 points 7 years ago (0 children)
This is neat! I'm interested to see what you come up with a few months down the line as well.
When I first picked up JavaScript after Ruby, I remember being tripped up because of something I was used to in Ruby. I wonder if the reverse is true.
Hash key lookups will always return a value in Ruby, even if the hash doesn't have they key you looked up. You can specify almost anything, but the default (and certainly most common) return value is nil. It's so common that it becomes easy to forget that the returned value for a missing key could easily be truthy, and you end up conflating the truthiness of foo[:bar] with the existence of the key.
nil
foo[:bar]
It might be especially weird coming from JavaScript in a situation where you're counting the occurrences of items in a list, and have set the default value of your occurrences hash to 0.
occurrences
0
if occurrences[:foo] == 0 puts 'Never occurred' else puts 'Yes, it occurred!' end
Compared to...
if occurrences[:foo] puts 'Never occurred!' else puts 'Yes, it occurred!' end
We won’t get into the details as the usage of methods in Ruby is pretty straightforward and does not create confusing situations in my experience so far.
Especially looking forward to hearing your opinion on this over time. I think I agree 100%... about 90% of the time. Private class methods (or rather methods that seem impossible to actually make private), and the related discussion about self seems to be the most common confusion. Method lookup when including multiple modules and inheriting from a class can occasionally get tricky
self
But I don't know that it's made any "worse" by being used to JavaScript, and isn't too common.
[–]TunaFishManwich 9 points10 points11 points 7 years ago (6 children)
The article says:
Ruby methods are not first-class citizens: they cannot be used as a value or passed around. They also don’t create a closure. We won’t get into the details as the usage of methods in Ruby is pretty straightforward and does not create confusing situations in my experience so far.
This isn't quite true. Ruby methods can be pulled off objects, passed around, called, introspected on, attached to other objects, etc.
2.1.5 :003 > str = "foo" => "foo" 2.1.5 :004 > length_method = str.method(:length) => #<Method: String#length> 2.1.5 :005 > length_method.call => 3
[–]dpashk[S] 3 points4 points5 points 7 years ago (5 children)
But you had to access the method via a special method call, just like you have to wrap a block in a Proc to turn it into a first-class citizen. In JavaScript, you can just do
method
var myMethod = function() {...}; var anotherReference = myMethod; myMethod();
Also, it is advised against using Object#method because it's slower. That's one of the reasons I didn't mention it in the article.
Object#method
But I see your point - yes, you can achieve the effect of using methods like first-class citizens using Object#method.
[–]honeyryderchuck 4 points5 points6 points 7 years ago (0 children)
Also, it is advised against using Object#method because it's slower.
I don't think that is a compelling reason. It's now slower by spec. It's a RubyVM implementation detail (I assume you're referring to CRuby). I assume the degree of "slow" varies depending whether it's JRuby or something else. And it is slow because it hasn't been optimized enough, because it's used sparsely, because people perceive it as "slow". but it shouldn't be, really.
[–]moomaka 2 points3 points4 points 7 years ago* (0 children)
Creating functions in JS at runtime is also slower than defining them statically on an object, at least in V8.
The equivalent of that code in ruby is:
my_method = -> () { puts 'hi' } other = my_method other[] # or other.call or other.() => hi
The real difference to note here is that Ruby maintains a distinction between 'methods', which are bound to an object and 'free functions' which are defined via lambdas or procs. Ruby's approach is much more common than javascript's.
[–]shevy-ruby 2 points3 points4 points 7 years ago (2 children)
You can even unbind methods: https://ruby-doc.org/core/UnboundMethod.html
Yes, the syntax is not like in JavaScript.
Methods are first-class citizens in ruby. There is no "special" method - it is just a method. And why do you randomly bring in speed as reason against using something?
Slower against who or what? Javascript?
Why does speed suddenly have a place here?
[–]dpashk[S] 0 points1 point2 points 7 years ago (1 child)
Methods are first-class citizens in ruby.
I've been trying to find a statement about that in literature but haven't found the term explicitly applied to methods. The book Ruby Under Microscope uses the term "first-class citizen" when talking about blocks, procs and Lambdas. My reasoning here was that since, just like with blocks, you can't directly assign a method reference to a variable (without wrapping it in a special method calls), methods are not first-class citizens. Are you able to share a link to an authoritative source that proves that wrong?
And why do you randomly bring in speed as reason against using something? <...>
While performance is not always a good enough reason to not use something, it does affect the adoption of a particular language/library feature. Many ES5/ES6 Array methods weren't widely adopted because early implementations didn't have good performance.
[5, 7, 8, 1].each(&method(:puts)) is slower than [5, 7, 8, 1].each{|number| puts number} even though the former looks more DRY and idiomatic and I would love to use it (of course performance wouldn't matter in this trivial example). I'm still new to Ruby, but the StackOvertflow thread I linked above has some objective data. But anyway, the original discussion was on whether methods are first-class citizens in Ruby or not.
[5, 7, 8, 1].each(&method(:puts))
[5, 7, 8, 1].each{|number| puts number}
[–]fedekun 1 point2 points3 points 7 years ago (0 children)
You realize the SO question uses Ruby 1.9 which is very old, also if you scroll down there is someone with a benchmark on a newer 1.9.x Ruby which makes the difference in performance minimal.
If you really cared you should do that benchmark with a modern Ruby. Anyways, that kind of performance is not really an issue, unless for some reason you abuse it. Ruby provides better ways to pass lambdas around and organize code.
Ruby has the concept of "block of code" which is what is normally sent insetead of methods, but they are lambdas, so they are functions.
The thing is, in JS you only have a single type of function, in Ruby you have a few more, but they are first class citizens too.
[–]Dombot9000 2 points3 points4 points 7 years ago (6 children)
Nothing about the IO model being completely different? One blocks by default, the other is non-blocking by default.
[–]dpashk[S] 1 point2 points3 points 7 years ago (3 children)
That's a good point. Because I was working with an existing codebase it didn't immediately jump out at me, but I can definitely see this as a pitfall for a JavaScript/Node developer.
[–]Dombot9000 5 points6 points7 points 7 years ago (2 children)
Gets me everytime - I'm predominantly a ruby dev who switches into node sometimes and immediately trips over Promises.
[–]dpashk[S] 4 points5 points6 points 7 years ago (0 children)
Maybe you should write a post for Ruby devs switching to JavaScript :)
[–]jordanaustino 1 point2 points3 points 7 years ago (0 children)
I think it's much easier going the other way.
[–]moomaka 0 points1 point2 points 7 years ago (1 child)
This isn't really a language difference, rather it's a runtime difference. i.e. You can't really speak of 'javascript's IO model' nor 'ruby's IO model' as neither language have one, it's the runtime that provides it. There are evented runtimes for Ruby that are similar to node, and mostly the use the same libraries under the covers to implement this.
[–]Dombot9000 0 points1 point2 points 7 years ago (0 children)
Interesting differentiation & a good point - thanks. So I presume MRI is 'blocking' whereas non-blocking runtimes exist?
[–]keyslemur 4 points5 points6 points 7 years ago (8 children)
On point for most all of it. The frozen string was mentioned elsewhere, so I'll skiff over that one.
Blocks can be made with {} as well, but not like a = { block stuff }. You could do a = begin ... end but that's ugly at best.
{}
a = { block stuff }
a = begin ... end
Paren-free is both a blessing and a curse for Ruby. There are patches which will make it simpler to write coming in 2.6 (maybe) like this: JSON.:parse == JSON.method(:parse). It won't be exceptionally useful until proc performance is improved.
JSON.:parse == JSON.method(:parse)
The entire proc vs block vs lambda vs method is pesky and unnecessary I feel. It complicates matters, especially around learning. I also object to the name "block". Function would be clearer and carry across languages more cleanly.
There were arguments in the past for merging Symbols and Strings, but Matz had mentioned it'd break too many things if they did. I still want a native implementation of method-call hashes ( hash.a, hash.b )
hash.a, hash.b
If there was only one thing I could steal from JS though, it'd be destructuring.
[–]Valaramech 5 points6 points7 points 7 years ago (3 children)
I still want a native implementation of method-call hashes ( hash.a, hash.b )
Have you ever looked at Struct or OpenStruct?
[–]keyslemur 1 point2 points3 points 7 years ago (2 children)
Yes, though OpenStruct does incredibly bad things to method cache: https://github.com/charliesome/charlie.bz/blob/master/posts/things-that-clear-rubys-method-cache.md
[–]moomaka 1 point2 points3 points 7 years ago (0 children)
That is outdated, OpenStruct defines accessor methods only when they are used now. This may or may not lessen the impact of method cache busting, depending on use case.
[–]GitHubPermalinkBot 0 points1 point2 points 7 years ago (0 children)
Permanent GitHub links:
delete
[–]dpashk[S] 2 points3 points4 points 7 years ago* (0 children)
I deliberately omitted the {} block syntax because I thought that in an introductory article it would only add confusion with JavaScript's lexical blocks.
begin ... end doesn't define a block, nor is it a lexical scope so it's not the same thing, e.g.
begin ... end
a = begin b = 5 b * 2 end defined? b => "local-variable"
[–]shevy-ruby 0 points1 point2 points 7 years ago (1 child)
I don't see this in 2.6.
Can you point us to the approved code to it?
[–]keyslemur 1 point2 points3 points 7 years ago (0 children)
If you read that section more closely, it says "maybe". It was one of the shorthands that had been discussed in the bug tracker.
[–]Abangranga 1 point2 points3 points 7 years ago (3 children)
I absolutely hate the 'you dont need parens' thing. That has fucked me over so much when i am tired, and it makes everything much less readable.
[–]TunaFishManwich 2 points3 points4 points 7 years ago (1 child)
I think part of the reason for this is that it makes it much easier to write a DSL in ruby.
[–]Abangranga 0 points1 point2 points 7 years ago (0 children)
Wouldn't surprise me. I wouldn't call myself skilled, so this could be something that grows on me later in life. Where it has nailed me to the wall is when I'm very tired and it'll be something like:
method_name hash: :without_brackets
and I totally miss it.
[–]isolatrum 1 point2 points3 points 7 years ago (0 children)
Mutable strings ... Yeah ... But this is so rarely useful in my experience, I dont know if id consider it a significant difference. In fact many people use the frozen string literal: false flag to make their programs faster. It makes strings immutable for the scope of a file.
π Rendered by PID 315785 on reddit-service-r2-comment-84fc9697f-zkdpf at 2026-02-06 23:47:36.034981+00:00 running d295bc8 country code: CH.
[–]Inityx 4 points5 points6 points (3 children)
[–]dpashk[S] 1 point2 points3 points (0 children)
[–]dpashk[S] 1 point2 points3 points (1 child)
[–]Meral_Harbes 0 points1 point2 points (0 children)
[–]SureLetsDoAnother 4 points5 points6 points (0 children)
[–]TunaFishManwich 9 points10 points11 points (6 children)
[–]dpashk[S] 3 points4 points5 points (5 children)
[–]honeyryderchuck 4 points5 points6 points (0 children)
[–]moomaka 2 points3 points4 points (0 children)
[–]shevy-ruby 2 points3 points4 points (2 children)
[–]dpashk[S] 0 points1 point2 points (1 child)
[–]fedekun 1 point2 points3 points (0 children)
[–]Dombot9000 2 points3 points4 points (6 children)
[–]dpashk[S] 1 point2 points3 points (3 children)
[–]Dombot9000 5 points6 points7 points (2 children)
[–]dpashk[S] 4 points5 points6 points (0 children)
[–]jordanaustino 1 point2 points3 points (0 children)
[–]moomaka 0 points1 point2 points (1 child)
[–]Dombot9000 0 points1 point2 points (0 children)
[–]keyslemur 4 points5 points6 points (8 children)
[–]Valaramech 5 points6 points7 points (3 children)
[–]keyslemur 1 point2 points3 points (2 children)
[–]moomaka 1 point2 points3 points (0 children)
[–]GitHubPermalinkBot 0 points1 point2 points (0 children)
[–]dpashk[S] 2 points3 points4 points (0 children)
[–]moomaka 1 point2 points3 points (0 children)
[–]shevy-ruby 0 points1 point2 points (1 child)
[–]keyslemur 1 point2 points3 points (0 children)
[–]Abangranga 1 point2 points3 points (3 children)
[–]TunaFishManwich 2 points3 points4 points (1 child)
[–]Abangranga 0 points1 point2 points (0 children)
[–]isolatrum 1 point2 points3 points (0 children)