Why Ruby rocks
skofo.github.io
skofo.github.io
class Person
{
public int Sanity { get; set; }
public Person()
{
Sanity = 50;
}
}
And to call it: var programmer = new Person();
programmer.Sanity += 1000000;
Console.WriteLine(programmer.Sanity);
I don't see much difference between Person.new and new Person();.What are the real ways in which it will knock my socks off? I'm honestly asking. Even though I program C# at work, I'm very interested in the advantages of other languages.
class Person
attr_accessor :sanity
def initialize
@sanity = 50
end
endIf using an "eval" method seems smelly to you, you can achieve the same result in pure Ruby using define_method, instance_exec, and instance_variable_get. There are good practical reasons to use module_eval, though.
Regardless, I think the author's point was more that there's nothing "special" about getters and setters in Ruby. They're just plain ol' methods. As a class of methods we write them often enough that we've also defined a higher-order method that takes an instance variable name as input and dynamically defines those getters and setters on the underlying object.
We wouldn't "lose" anything by not having attr_reader and friends, though. Our code would just be slightly more verbose.
Ah, that's a good point. That seems to be a more accurate interpretation of what the author was trying to express.
type Person struct {
Sanity int
}
func NewPerson() *Person {
return &Person{Sanity: 50}
}
This is good enough 90% of the time (and faster), but if I was writing a library package and I wanted to care about protecting with some logic and care about my export signature: type Person interface {
Sanity()
SetSanity(val int)
}
type person struct {
sanity int
}
func NewPerson() Person {
return &person{sanity: 50}
}
func (p *person) Sanity() {
return p.sanity
}
func (p *person) SetSanity(val int) {
if val > SOME_FOO1 && val < SOME_FOO2 {
p.sanity = val
}
}method_missing, which is a bit of a hack and is at least a double edged sword, makes Ruby rock? Sure, it's handy magic, but it's a pretty dangerous form of magic.
I'm not sure I could think of less significant attributes for a language.
Note: I work on a large Ruby codebase...
I don't doubt that there really are great reasons to use Ruby; hopefully, when the author figures out what they are, he'll revisit this and contrast the real benefits with this unfortunate cruft.
Ruby does not have "properties." All data is private and you interact with objects using messages.
As a user of an object's interface all you need to know is how something behaves when sent various messages. Whether "foo = 12" is really setting an instance variable named "@foo" or something else entirely should be irrelevant. It's an implementation detail.
I realize this sounds possibly condescending and pedantic, but I've seen too many Ruby tutorials that try to present the language in terms of behavior found in other languages where the result is a broken mental model of how Ruby actually works. Hence, confusion.
Unfortunately the conflation of methods that happen to get or set instance variables with the notion of properties (AKA "attributes") has become ingrained.
method_missing, which is a bit of a hack and is at least a double edged sword, makes Ruby rock? Sure, it's handy magic, but it's a pretty dangerous form of magic.
Thinking in terms of messages sent to a receiver, "method_missing" is far less magical. It's more something you'd expect in a message-handling system.
You say, "Ruby's allowing you to elide parentheses means you can't assume that a property is a property or a function."
There's no such "thing" as a property in Ruby, yeah? Everything+ is an object and objects respond to methods. IMO this is one of the places where Ruby is not being magical. attr_reader and friends are built on top of this to give programmer's a convenient shorthand way of defining boilerplate getters and setters when you need them.
In this regard Ruby is more homoiconic. "getters" and "setters" are just plain ol' methods!
It'd be much more confusing, IMO, if there were now two types of "things" that could be attached to an object: methods and properties/attributes. You'd have to develop a separate convention, syntactic or otherwise, for information hiding, e.g., how would private properties work? You're now in a funny situation where one kind of variable (instance variables) might differ from other kinds of variables in a dimension other than scope.
Python's answer is "neither properties nor methods are ever really private" which is internally consistent but very un-Ruby.
+: I know this isn't literally true. Methods aren't objects, for example, and there are plenty of keywords like case, when, if, etc. which are neither methods nor objects but units of pure syntax.
You could do something similar to Ruby's missing_method, by setting the class's __getattr__, but you'd really have to ask yourself why. What kind of creation are you building that you are expecting to not know which methods are available while running your program?
These are the kinds of things that drive me batty with Ruby. Perhaps if I spent about double or triple the hours on Ruby that I have, I might have an "aha" moment. However, from what I've seen I can't help but feel that what it's really trying to accomplish is much more comfortable in functional form (say Lisp?).
Well, metaprogramming is all about exactly that kind of thing. Python is a fine language, but it's not cut from the same cloth as Ruby. That's not a value judgement; plenty of sane, creative, and intelligent people use Python. They're simply not the same kind of language.
In a pinch the (free?) "Barewords" episode of Ruby Tapas will get you close in five minutes.
`method_missing` is more useful for dynamically responding to method calls than actually not knowing how to respond. A good example of this is rails' (version 3.2 and lower) dynamic finders:
User.find_by_username('a_username')
`find_by_username` is never defined anywhere, it is dynamically responded to using method missing. this allows code to be much more precise and DRY (though at the expense of readability if you don't know what's going on)
You normally wouldn't use method_missing in this way. As an example, for better or worse, look at RSpec. I can write code like this:
require 'rspec'
class Person
def initialize
@happy = true
end
def happy?
@happy
end
end
describe Person do
describe '.new' do
it 'is happy by default' do
expect(Person.new).to be_happy
end
end
end
RSpec doesn't know about the Person#happy? method, obviously, so how the heck is there a be_happy method? It's using method_missing to intercept the call to the otherwise-undefined be_happy method, pull out the "happy" part, translate it to "happy?", and then construct the appropriate expectation by delegating the "happy?" message to the underlying Person object and analyzing the response.It also enables RSpec to generate much more useful testing messages. Instead of saying "Expected person.happy? to be true, but got false" it can say "Expected person to be happy, but happy? returned false."
This intercept-and-delegate or intercept-and-translate mechanism is probably the most common use of method_missing. It makes writing DSLs much easier. See, e.g., Nokogiri::XML::Builder for generating XML documents (http://nokogiri.org/Nokogiri/XML/Builder.html).
I don't know if it's the lack of types, the fact that you see streams of "end end end" like Pascal used to do, the abysmal performance of the default VM or just the heavy reliance on monkey patching, but Ruby is not aging very well.
Ruby is a dynamic language, so no, there are no types as such. There are ways to create types, but if you're doing that a lot, you're probably doing Ruby wrong. It's not meant to have types. Different way of thinking.
the abysmal performance of the default VM
That's a myth, a pervasive one. I'll point you to one source that debunks this, but there are many. http://www.unlimitednovelty.com/2012/06/ruby-is-faster-than-...
the heavy reliance on monkey patching
Monkey patching is generally considered an anti-pattern. I'm not sure what in particular has "heavy reliance" on it, but it's not Ruby's libraries themselves, and it's not Rails. (Metaprogramming is not the same thing as monkey patching.)
Ruby is not aging very well.
IMHO Ruby is just now coming fully into its own, and is, for a young language, just reaching maturity.
We've measured the performance of the fundamentals of web applications on two Ruby implementations (MRI, JRuby) and both perform poorly, as compared to the rest of the field. area51org says that Ruby's reputation of slowness is undeserved. I feel our data confirms the reputation.
In fact, I don't think there's much room for improvement by tweaking our tests, but I figured I'd make the solicitation anyway to keep an open mind about it.
I'm not asking you to fix it or shut up, especially since I feel your point of view is corroborated by the data. I am asking, however, for those who say Ruby's reputation is undeserved to consider providing some evidence for that point of view. And one conceivable way to do that would be to improve our Ruby tests.
Given how little code there is in the Ruby/Rails tests there, it doesn't look like a lot of opportunity exists for speeding up the benchmarks by changing that code... but maybe it could be sped up by changing the gems. There are several JSON gems, at least one of which claims to be faster by 2-3x.
In the PHP universe there's Phalcon, a C plugin to handle a lot of the work that otherwise would be done in raw PHP. It has good performance versus the other PHP frameworks (not up to the raw PHP numbers). Why hasn't this become the norm?
I'm not asking bhauer, folks: why not replace chunks of the code that are slow but have been pretty stable (Rack comes to mind, but other chunks of Rails are probably good contenders) with C plugins/gems? We already commonly use Nginx or another server for static content, why not push that further? Hell, how much similar code could be put to use in other frameworks if the core was done in C/C++ or Java? The focus on the singular language as the only way to do any given framework seems to waste an amazing amount of code, and performance.
Yes it is. ActiveSupport (part of Rails) monkey-patches the core library.
That's a myth, a pervasive one. I'll point you to one
source that debunks this, but there are many.
http://www.unlimitednovelty.com/2012/06/ruby-is-faster-than-python-php-and-perl.html
It's unfortunately compromised by some boneheaded things in the MRI implementation. Method caching is a great example: https://charlie.bz/blog/things-that-clear-rubys-method-cache(Rails startup does a lot of the mentioned things, for example, but then so do a lot of apps' controller actions unless they're careful. The OpenStruct example is particular egregious.)
Young? Ruby is 18 years old, it's certainly not a young language.
Well, its not young compared to Go, but its young compared to C or Lisp or Smalltalk.
def sanity
@sanity
end
def sanity=(val)
@sanity = val
end
how are those six lines not boilerplate? attr_accessor :sanity
Would be a neater way to write this. attr_accessor :sanityhttp://ruby-doc.org/core-1.9.3/Module.html#method-i-attr_acc...
The above can be written as
attr_accessor :sanity attr_accessor :sanity
def initialize
@sanity = 0
end
On that note I like Go's default values for primitive types. An int sanity would be zero by default.Edit: seeing five simultaneous posts saying the same thing makes me feel trolled a bit :)
The benefit everything-is-a-message is that you can swap out the implementation of sanity (or sanity=) if needed, eg.
Before:
attr_accessor :radius, :diameter
After: # Refactored radius to be the new source of truth.
def diameter
radius * 2
end
def diameter=(val)
self.radius = val / 2
end
In PHP (for example), MyClass->diameter and MyClass->diameter() are completely different things. Any existing code (including code you don't control) needs updating to change references from the former to the latter when moving logic into something that was previously static.This article is flawed by holding up those six lines in themselves as something great, but I think the point the author is trying to get across is valid.
1. The drama that surrounds Rails makes a lot of people just throw their hands up and quit. 2. There are very few Ruby shops that aren't just Rails shops.
Now every Ruby meetup I attend, 99% of the presentations are from web devs about rails and associated infrastructure.
That's pretty much why I lost interest in not just local groups but most online activity.
I use Ruby and JRuby all the time, but for Web dev I'll start with some simple Rack stuff and evolve to a Ramaze app if needed.
Listening to someone discuss installation and assorted config params for a gem that only works with a specific framework is not terribly interesting.
There are some bright spots online, Greg Brown's Practicing Ruby site being a solid example.
If you think about all the shops out there using Puppet and/or Chef, there is still a lot of non-Rails Ruby out there (in a roundabout way, I'll admit).
What I would like to have: better support for concurrency, less memory consumption in production
method_missing is interesting because it has been criticised in projects like Rails, precisely because it leaves you with an API which isn't documented explicitly in the code. As Rails matures they've moved away from dynamic finders, and more towards defined methods which take options, so instead of
Post.find_all_by_xxx or Post.find_by_xxx
People often use:
Post.where(xxx)
I've never been tempted to use it explicitly myself, in quite a few years of using Ruby, it just feels too hacky somehow and too akin to monkey-patching, another early Ruby practice which Rails has moved away from.
In contrast I do love the automatic accessors (not as shown in this post) in Ruby and the philosophy that everything should be as simple and predictable as possible, just having to edit header files is so jarring when going back to something like Obj-C. Ruby feels comfortable to me mostly because of the attitude of the language and the standard library which is pretty surprise free and covers most of the bases, but it's not markedly superior or different IMHO from other languages like Python, and choosing between them is really a matter of taste.
I tend to look through everything in an OOP/type safe way, so the idea of having an unlimited, highly dynamic vocabulary for method calling is very... Foreign to me.
When does this pattern outshine static interfaces?
[edit] I am NOT a native English speaker. Is OP's blog supposed to be a joke and I don't get it?
They give the illusion that they can be set in any order, but most meaningful classes have invariants that are ambiguous to preserve with single-value setters. Object Oriented designs jump through some serious hoops to preserve the pretty `object.property = value` syntax. Besides, there are considerable advantages to immutability even in the absence of concurrency. `new_object = frob(object, value)` is generally preferable in the long run.
I already know it, so it rocks. Python is fun but I already have Ruby. It's just a language and there's nothing I can really do in Python that I can't do it Ruby, and vice-versa (at my level, anyway).
I guess I'm just lucky I have the option of using either instead of say, ______.
>There are various interwoven reasons for this, but the biggest thing that makes Ruby shine in my eyes is its objects
Learn Smalltalk-80. Its been around a long time, and has a rich history.