Since I use Ruby at work now, and since I understand C# syntax much better than I understand Ruby syntax, I occasionally run into things that look like they should or shouldn’t work in Ruby, but surprise me by working (or not working). Today I’ll document the first of these surprises: you can’t call static methods from instance methods in Ruby.
To illustrate what I mean, I’ve made two simple examples:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class HasInstanceMethods | |
def instance_method | |
puts "In instance method, the type of `self` is #{self.class}" | |
end | |
def self.class_method | |
puts "In class method, the type of `self` is #{self.class}" | |
end | |
def call_class_from_instance | |
begin | |
class_method # raise NameError | |
rescue Exception => e | |
puts "raised #{e.inspect}" | |
end | |
end | |
def call_self_class_from_instance | |
self.class.class_method # works | |
end | |
end | |
instance = HasInstanceMethods.new | |
instance.instance_method # works | |
HasInstanceMethods.class_method # works | |
# would raise NoMethodError: | |
# instance.class_method | |
instance.call_class_from_instance # NameError | |
instance.call_self_class_from_instance # works | |
# ouptut: | |
# In instance method, the type of `self` is HasInstanceMethods | |
# In class method, the type of `self` is Class | |
# raised #<NameError: undefined local variable or method `class_method' for #<HasInstanceMethods:0x007fc88709d380>> | |
# In class method, the type of `self` is Class |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
namespace ConsoleApplication | |
{ | |
public class HasInstanceAndStaticMethods | |
{ | |
public static void StaticMethod() | |
{ | |
Console.WriteLine("Hello from static method"); | |
} | |
public void InstanceMethod() | |
{ | |
Console.WriteLine($"Type in instance method is {this.GetType().FullName} "); | |
} | |
public void CallStaticMethodFromInstanceMethod() | |
{ | |
Console.Write("Attempting to call static method from instance method…"); | |
StaticMethod(); | |
Console.WriteLine("… and it succeeded."); | |
} | |
} | |
public class Program | |
{ | |
public static void Main(string[] args) | |
{ | |
HasInstanceAndStaticMethods.StaticMethod(); | |
var instance = new HasInstanceAndStaticMethods(); | |
instance.InstanceMethod(); | |
instance.CallStaticMethodFromInstanceMethod(); | |
} | |
} | |
} | |
// Output: | |
// Type in instance method is ConsoleApplication.HasInstanceAndStaticMethods | |
// Attempting to call static method from instance method…Hello from static method | |
// … and it succeeded. |
I think that the reasoning behind this difference is that in Ruby, everything is an object, and even classes are objects. Thus, a static method in Ruby is really a method attached to some instance of a class object. The reference self
in a Ruby object method refers to the present instance of the class object. In other words, I can’t call static methods in Ruby from instances because they are instance methods on a different object. You can still call them from instance methods with self.class.class_method
, but that’s because you’re calling an instance method on the object that represents the current object’s class. Just for fun, since Ruby will let you do whatever you want, let’s make a Ruby class that behaves like a C# class in this respect:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class CSharpStyle | |
def method_missing method_name, *args | |
self.class.send(method_name, *args) | |
end | |
def self.static_method | |
puts "hurray for Ruby" | |
end | |
def instance_method | |
print "here goes nothin! " | |
static_method | |
end | |
end | |
instance = CSharpStyle.new | |
instance.instance_method | |
instance.static_method | |
# Output | |
# here goes nothin! hurray for Ruby | |
# hurray for Ruby |
That works fine. If a method on an instance of that class is about to raise a no method error, which it would do by calling method_missing
on Object, instead my overridden method_missing
will fire, and will call the appropriate method on the class. And that’s a great example of something that’s possible, but probably not a good idea – making your program have your own personal syntax quirks might be confusing to future maintainers. But Ruby is fun!
Till next time, happy learning!
-Will
[…] was my second surprising linguistic difference between Ruby and C#. (The first was that you can’t call class methods from instance methods.) Anyway, I’m still having a blast, and have very high regard for Ruby and C# as languages. I […]
LikeLike