Overloading in Ruby - ruby

I want to use overloading feature in Ruby like many other languages, but Ruby itself does not support this feature.
Do I have to implement it using the way that define a method with *args argument and determine the number and types of the arguments inside the method? Some like:
class A
def foo(*args)
case (args.length)
when 1
do something
when 2
do something-else
....
end
end
end
You can see, it is really ugly than directly overloading.
I want to know whether there is any keywords or some other manners (like a meta-programming module) that could allow me to define an overloading method in a more elegant way.

You could try some meta programming to reach your target.
See the following code:
class OverloadError < ArgumentError; end
class Class
=begin rdoc
=end
def define_overload_method( methodname, *methods )
methods.each{ | proc |
define_method("#{methodname}_#{proc.arity}".to_sym, &proc )
}
define_method(methodname){|*x|
if respond_to?("#{methodname}_#{x.size}")
send "#{methodname}_#{x.size}", *x
else
raise OverloadError, "#{methodname} not defined for #{x.size} parameters"
end
}
end
end
class X
define_overload_method :ometh,
Proc.new{ "Called me with no parameter" },
Proc.new{ |p1| "Called me with one parameter (#{p1.inspect})" },
Proc.new{ |p1,p2| "Called me with two parameter (#{p1.inspect}, #{p2.inspect})" }
end
x = X.new
p '----------'
p x.ometh()
p x.ometh(1)
p x.ometh(1,2)
p x.ometh(1,2,3) #OverloadError
You can define your overloaded method with define_overload_method. Parameters are the method name and a list of procedures. The method methodname is created and calls the corresponding method. Which method is determined by the number of parameters (Not type!).
An alternative syntax would be:
class OverloadError < ArgumentError; end
class Class
def def_overload( methodname)
define_method(methodname){|*x|
if respond_to?("#{methodname}_#{x.size}")
send "#{methodname}_#{x.size}", *x
else
raise OverloadError, "#{methodname} not defined for #{x.size} parameters"
end
}
end
def overload_method( methodname, proc )
define_method("#{methodname}_#{proc.arity}".to_sym, &proc )
end
end
class X
def_overload :ometh
overload_method :ometh, Proc.new{ "Called me with no parameter" }
overload_method :ometh, Proc.new{ |p1| "Called me with one parameter (#{p1.inspect})" }
overload_method :ometh, Proc.new{ |p1,p2| "Called me with two parameter (#{p1.inspect}, #{p2.inspect})" }
end
def_overload defines the frame for your overloaded methods, overload_method defines one 'overload-method'.
But as already mentioned by Holger:
You should try to adapt to the Ruby way. There is a reason why there is no overloading in Ruby. Methods should only do one thing, not magically decide to do vastly different things just because of different arguments. Instead try to take advantage of Duck Typing and if in doubt, use different methods with meaningful names.
I was curious how I could implement a version with type sensitive overloading. Here it is:
class OverloadError < ArgumentError; end
class Class
def def_overload( methodname)
define_method(methodname){|*x|
methname = "xxx"
methname = "#{methodname}_#{x.size}#{x.map{|p| p.class.to_s}.join('_')}"
if respond_to?(methname)
send methname, *x
elsif respond_to?("#{methodname}_#{x.size}")
send "#{methodname}_#{x.size}", *x
else
raise OverloadError, "#{methodname} not defined for #{x.size} parameters"
end
}
end
def overload_method( methodname, *args, &proc )
types = []
args.each{|arg| types << arg.to_s}
define_method("#{methodname}_#{proc.arity}#{types.join('_')}".to_sym, &proc )
end
end
class X
def_overload :ometh
overload_method(:ometh){ "Called me with no parameter" }
overload_method(:ometh, String ){ |p1| "Called me with one string parameter (#{p1.inspect})" }
overload_method(:ometh ){ |p1| "Called me with one parameter (#{p1.inspect})" }
overload_method(:ometh){ |p1,p2| "Called me with two parameter (#{p1.inspect}, #{p2.inspect})" }
end
When you call it with
p x.ometh(1)
p x.ometh('a')
You get
"Called me with one parameter (1)"
"Called me with one string parameter (\"a\")"

You can test for the existence of each argument separately as they are set to nil if not passed (assuming they are passed in order!).
If you insist on very different arguments I suggest an hash argument with symbols for each argument you intend.. and approriate tests.
** UPDATE **
Also you could also rename the methods that overload with more specific names, such as
def perform_task_with_qualifier_1

there are few gems that provide this feature to your ruby code
functional-ruby
defn(:greet, :male) {
puts "Hello, sir!"
}
defn(:greet, :female) {
puts "Hello, ma'am!"
}
foo.greet(:male) => "Hello, sir!"
foo.greet(:female) => "Hello, ma'am!"
you can find more Elixir like pattern matching features from here
contracts.ruby
Contract 1 => 1
def fact x
x
end
Contract C::Num => C::Num
def fact x
x * fact(x - 1)
end
this gem helps to right beautiful defensive code. there are some criticisms about performance. so benchmark and decide. more examples

The defining characteristic of overloading is that dispatch happens statically. In Ruby, dispatch always happens dynamically, there is no other way. Therefore, overloading is not possible in Ruby.

Related

difference between dot(.) and double colon (::) in accessing class method

A double colon(::) allows constants, instance methods, and class methods defined within a class or module, to be accessed from anywhere outside the class or module.
Looking at this example:
class Sample
VAR_SAMPLE="what is the difference?"
def self.show_var
return VAR_SAMPLE
end
def method2
return VAR_SAMPLE
end
end
puts Sample::show_var # => what is the difference?
puts Sample.show_var # => what is the difference?
puts Sample::new::method2 # => what is the difference?
puts Sample.new.method2 # => what is the difference?
What is the difference in accessing class method using dot(.) and a double colon (::) operator then? Any thoughts are appreciated.
The double colon :: namespace operator can also be used as a message sending operator. In other words,
foo.bar
can also be written as
foo::bar
Except when not.
In particular, . is always a message send. :: is usually a namespace lookup, except when it cannot possibly be. That means, for example, you cannot call a message that starts with an uppercase character, unless you also pass an argument list.
foo = Class.new do
def BAR; :method end
BAR = :constant
end
foo.BAR #=> :method
foo::BAR #=> :constant
foo::BAR() #=> :method
The fact that :: can also be used for message sends is a historical curiosity, and is banned in most style guides except for "class factories", i.e. methods that return classes. Imagine a web framework that is set up like this:
module Controller
def self.R(path)
Class.new(AbstractController) do
# a bunch of methods for dealing with routing to `path`
end
end
end
class IndexController < Controller::R '/index.html'
def get
render 'Welcome'
end
end
In this case, in some style guides, it would be acceptable to write Controller::R because even though R is a method, it returns a class, so it kind-of acts like one.
But this is a special case for certain DSLs and is only allowed in certain style guides. Most style guides disallow :: for message sends, because it is redundant with ., because it already has a another different meaning (namespace resolution), and because it doesn't behave like . in all cases.
What is the difference in accessing class method using dot(.) and a double colon (::) operator then?
On the one hand, you can say, there is no difference because when used as the message sending operator, they both do the exact same thing.
On the other hand, there is a difference in syntax, namely that foo::BAR isn't a message send, it is a namespace lookup which is completely different. from foo.BAR, which is a message send.
You can call ruby methods using following ways
using Dot (.), Double Colon (::), send method & method method
class Sample
VAR_SAMPLE="what is the difference?"
def self.show_var
return VAR_SAMPLE
end
def method2
return VAR_SAMPLE
end
end
puts Sample::show_var
puts Sample.show_var
puts Sample.send(:show_var)
puts Sample.method(:show_var).call
puts Sample::new::method2
puts Sample.new.method2
puts Sample.send(:new).send(:method2)
puts Sample.method(:new).call.method(:method2).call
# All the above will return `what is the difference?` only
Now consider method which is a private
class Sample
VAR_SAMPLE="what is the difference?"
private
def self.show_var
return VAR_SAMPLE
end
end
puts Sample::show_var # Will throw error private method `show_var' called for
puts Sample.show_var # Will throw error private method `show_var' called for
puts Sample.send(:show_var) # what is the difference?
puts Sample.method(:show_var).call # what is the difference?
Note:- Other than this you can call ruby methods using other metaprogramming methods as well.

Ruby Bracket Method with Block

I would like to define the [] method on a class of my own creation to take a block. I have done so as follows.
class A
def self.[](*args, &block)
puts "I am calling #{block} on #{args}."
block.(*args)
end
end
I can invoke this as follows.
# Explicit method invocation
A.[](1) { |x| puts x }
# With a procedure argument
arg = proc { |x| puts x }
A[2, &arg]
However, what I would like to be able to do is this.
A[3] { |x| puts x }
Which unfortunately seems to produce a syntax error. Is there a block syntax for the bracket method, or am I stuck with the first two ways of invoking it? In fact, more generally, which Ruby method names will allow blocks in their invocation, as it seems that there might be a limitation on when this is allowed?
There's not much you can do against a syntax error, so you'll have to change the syntax.
If you accept :
to define (i.e. pollute) an uppercase method inside Kernel (similar to Kernel#Array)
to use parens instead of brackets
You could write :
class A
def self.call_block_with_args(*args, &block)
puts "I am calling #{block} on #{args}."
block.call(*args)
end
end
module Kernel
def A(*args, &block)
A.call_block_with_args(*args, &block)
end
end
It works this way :
A(3) { |x| puts x }
#=>
# I am calling #<Proc:0x000000012b9c50#block_brackets.rb:14> on [3].
# 3
It's not clean, but it's probably the closest you can be to A[3] { |x| puts x }.
Blocks work with normal method calls only.
Ruby has plenty of operators, listing all of them here would be exhaustive, there are more than two dozens. Even `a` and !a and -a are method calls in Ruby. And obviously there are limitations to all these operators, eg + must take one parameter but not more, et cetera.
Fun fact, loop is a method call too.

Change the binding of a Proc in Ruby

I have this code:
l = lambda { a }
def some_function
a = 1
end
I just want to access a by the lambda and a special scope which has defined a already somewhere like inside some_function in the example, or just soon later in the same scope as:
l = lambda { a }
a = 1
l.call
Then I found when calling l, it is still using its own binding but not the new one where it was called.
And then I tried to use it as:
l.instance_eval do
a = 1
call
end
But this also failed, it is strange that I can't explain why.
I know the one of the solution is using eval, in which I could special a binding and executing some code in text, but I really do not want to use as so.
And, I know it is able to use a global variable or instance variable. However, actually my code is in a deeper embedded environment, so I don't want to break the completed parts if not quite necessary.
I have referred the Proc class in the documentation, and I found a function names binding that referred to the Proc's context. While the function only provided a way to access its binding but cannot change it, except using Binding#eval. It evaluate text also, which is exactly what I don't like to do.
Now the question is, do I have a better (or more elegant) way to implement this? Or using eval is already the regular manner?
Edit to reply to #Andrew:
Okay, this is a problem which I met when I'm writing a lexical parser, in which I defined a array with fixed-number of items, there including at least a Proc and a regular expression. My purpose is to matching the regular expressions and execute the Procs under my special scope, where the Proce will involved some local variables that should be defined later. And then I met the problem above.
Actually I suppose it is not same completely to that question, as mine is how to pass in binding to a Proc rather than how to pass it out.
#Niklas:
Got your answer, I think that is what exactly I want. It has solved my problem perfectly.
You can try the following hack:
class Proc
def call_with_vars(vars, *args)
Struct.new(*vars.keys).new(*vars.values).instance_exec(*args, &self)
end
end
To be used like this:
irb(main):001:0* lambda { foo }.call_with_vars(:foo => 3)
=> 3
irb(main):002:0> lambda { |a| foo + a }.call_with_vars({:foo => 3}, 1)
=> 4
This is not a very general solution, though. It would be better if we could give it Binding instance instead of a Hash and do the following:
l = lambda { |a| foo + a }
foo = 3
l.call_with_binding(binding, 1) # => 4
Using the following, more complex hack, this exact behaviour can be achieved:
class LookupStack
def initialize(bindings = [])
#bindings = bindings
end
def method_missing(m, *args)
#bindings.reverse_each do |bind|
begin
method = eval("method(%s)" % m.inspect, bind)
rescue NameError
else
return method.call(*args)
end
begin
value = eval(m.to_s, bind)
return value
rescue NameError
end
end
raise NoMethodError
end
def push_binding(bind)
#bindings.push bind
end
def push_instance(obj)
#bindings.push obj.instance_eval { binding }
end
def push_hash(vars)
push_instance Struct.new(*vars.keys).new(*vars.values)
end
def run_proc(p, *args)
instance_exec(*args, &p)
end
end
class Proc
def call_with_binding(bind, *args)
LookupStack.new([bind]).run_proc(self, *args)
end
end
Basically we define ourselves a manual name lookup stack and instance_exec our proc against it. This is a very flexible mechanism. It not only enables the implementation of call_with_binding, it can also be used to build up much more complex lookup chains:
l = lambda { |a| local + func(2) + some_method(1) + var + a }
local = 1
def func(x) x end
class Foo < Struct.new(:add)
def some_method(x) x + add end
end
stack = LookupStack.new
stack.push_binding(binding)
stack.push_instance(Foo.new(2))
stack.push_hash(:var => 4)
p stack.run_proc(l, 5)
This prints 15, as expected :)
UPDATE: Code is now also available at Github. I use this for one my projects too now.
class Proc
def call_with_obj(obj, *args)
m = nil
p = self
Object.class_eval do
define_method :a_temp_method_name, &p
m = instance_method :a_temp_method_name; remove_method :a_temp_method_name
end
m.bind(obj).call(*args)
end
end
And then use it as:
class Foo
def bar
"bar"
end
end
p = Proc.new { bar }
bar = "baz"
p.call_with_obj(self) # => baz
p.call_with_obj(Foo.new) # => bar
Perhaps you don't actually need to define a later, but instead only need to set it later.
Or (as below), perhaps you don't actually need a to be a local variable (which itself references an array). Instead, perhaps you can usefully employ a class variable, such as ##a. This works for me, by printing "1":
class SomeClass
def l
#l ||= lambda { puts ##a }
end
def some_function
##a = 1
l.call
end
end
SomeClass.new.some_function
a similar way:
class Context
attr_reader :_previous, :_arguments
def initialize(_previous, _arguments)
#_previous = _previous
#_arguments = _arguments
end
end
def _code_def(_previous, _arguments = [], &_block)
define_method("_code_#{_previous}") do |_method_previous, _method_arguments = []|
Context.new(_method_previous, _method_arguments).instance_eval(&_block)
end
end
_code_def('something') do
puts _previous
puts _arguments
end

How to create a method like ".find_by_something_and_something_else" using Ruby?

Using Ruby I know you can get pretty creative with how you name your methods. For instance in rails you have .find_by_this_and_that.
How can I do this?
Example:
def get_persons_with_5_things
res = []
persons.each do |person|
if person.number_of_things == %MAGICALLY GET THE NUMBER 5 FROM FUNCTION NAME%
res << person
end
end
return res
end
I'm not even sure how you call this kind of things so any pointers would be appreciated.
I'm a little confused by your example. If you define the method with the hardcoded 5 in the method name, then you don't need to magically figure it out inside the body of the method. If you want to do something dynamic with method missing, it would be something like this:
def method_missing(name, *args)
if name.to_s =~ /get_persons_with_(\d+)_things/
number_of_things = $1.to_i
res = []
persons.each do |person|
if person.number_of_things == number_of_things
res << person
end
end
return res
else
return super(name, *args)
end
end
[EDIT (Jörg W Mittag)]: This is a more Rubyish way of implementing that same method:
def method_missing(name, *args)
return super unless name.to_s =~ /get_persons_with_(\d+)_things/
number_of_things = $1.to_i
return persons.select {|person| person.number_of_things == number_of_things }
end
super without any arguments just passes the original arguments along, no need to pass them explicitly
an early return guarded by a trailing if or unless expression greatly clears up control flow
all the each iterator does, is select items according to a predicate; however, there already is an iterator for selecting items: select
Ruby has different meta programming techniches to do this kind of stuff.
First we need our variable method
class DB
def get_persons_with_x_things(x)
res = []
persons.each do |person|
if person.number_of_things == x
res << person
end
end
return res
end
end
define_method
If there is a finite number of x's. We could use define_method to create all this methods. define_method creates a method. The first argument is the name of the method, the seccond argument or the given block is the stuff, which get's executed when the method is called.
This way, you don't realy create such method's, but It will look for the user if he calls it, as if it existed. But if the user relies on Object#methods and such, he will never see your inifinite number of fake methods.
class DB
99.times do |i|
define_method("get_persons_with_#{i}_things") do
get_persons_with_x_things(i)
end
end
end
method_missing
If there is an infinite numbor of x's method_missing would be better suited for this Task. If someone tries to call a method which does not exist, method_missing is executed instead. The first argument for method_missing is the method name as symbol, the following arguments are the original arguments.
class DB
def method_missing(name, *args)
case name.to_s
when /^get_persons_with_(\d+)_things$/
get_persons_with_x_things($1.to_i)
else
super(name, *args)
end
end
end
method_missing and send
To not use static regexe would be even cooler. But this could have some security implications. The method send I use here, calls a method by it's name.
class DB
def method_missing(name, *args)
name.to_s=~ /\d+/
# always be carefull with $ variables, they are global for this thread, so save everything as fast as you can
new_name= "#{$`}x#{$'}"
number= $1.to_i
if method_defined?(new_name)
send(new_name, number)
else
super(name, *args)
end
end
end
you can do a lot of things like this with method missing:
Ruby Docs
StackOveflow method_missing
Have a look at Ruby's callbacks specially method_missing.

How do I call a method that is a hash value?

Previously, I asked about a clever way to execute a method on a given condition "Ruby a clever way to execute a function on a condition."
The solutions and response time was great, though, upon implementation, having a hash of lambdas gets ugly quite quickly. So I started experimenting.
The following code works:
def a()
puts "hello world"
end
some_hash = { 0 => a() }
some_hash[0]
But if I wrap this in a class it stops working:
class A
#a = { 0 => a()}
def a()
puts "hello world"
end
def b()
#a[0]
end
end
d = A.new()
d.b()
I can't see why it should stop working, can anyone suggest how to make it work?
that code doesn't work. it executes a at the time it is added to the hash, not when it is retrieved from the hash (try it in irb).
It doesn't work in the class because there is no a method defined on the class (you eventually define a method a on the instance.
Try actually using lambdas like
{0 => lambda { puts "hello world" }}
instead
First of all, you are not putting a lambda in the hash. You're putting the result of calling a() in the current context.
Given this information, consider what the code in your class means. The context of a class definition is the class. So you define an instance method called a, and assign a class instance variable to the a hash containing the result of calling a in the current context. The current context is the class A, and class A does not have a class method called a, so you're trying to put the result of a nonexistent method there. Then in the instance method b, you try to access an instance variable called #a -- but there isn't one. The #a defined in the class context belongs to the class itself, not any particular instance.
So first of all, if you want a lambda, you need to make a lambda. Second, you need to be clear about the difference between a class and an instance of that class.
If you want to make a list of method names to be called on certain conditions, you can do it like this:
class A
def self.conditions() { 0 => :a } end
def a
puts "Hello!"
end
def b(arg)
send self.class.conditions[arg]
end
end
This defines the conditions hash as a method of the class (making it easy to access), and the hash merely contains the name of the method to call rather than a lambda or anything like that. So when you call b(0), it sends itself the message contained in A.conditions[0], which is a.
If you really just want to pretty this sort of thing up,
why not wrap all your methods in a class like so:
# a container to store all your methods you want to use a hash to access
class MethodHash
alias [] send
def one
puts "I'm one"
end
def two
puts "I'm two"
end
end
x = MethodHash.new
x[:one] # prints "I'm one"
x.two # prints "I'm one"
or, to use your example:
# a general purpose object that transforms a hash into calls on methods of some given object
class DelegateHash
def initialize(target, method_hash)
#target = target
#method_hash = method_hash.dup
end
def [](k)
#target.send(#method_hash[k])
end
end
class A
def initialize
#a = DelegateHash.new(self, { 0 => :a })
end
def a()
puts "hello world"
end
def b()
#a[0]
end
end
x = A.new
x.a #=> prints "hello world"
x.b #=> prints "hello world"
One other basic error that you made is that you initialized #a outside of any instance method -
just bare inside of the definition of A. This is a big time no-no, because it just doesn't work.
Remember, in ruby, everything is an object, including classes, and the # prefix means the instance
variable of whatever object is currently self. Inside an instance method definitions, self is an instance
of the class. But outside of that, just inside the class definition, self is the class object - so you defined
an instance variable named #a for the class object A, which none of the instances of A can get to directly.
Ruby does have a reason for this behaviour (class instance variables can be really handy if you know what
you're doing), but this is a more advanced technique.
In short, only initialize instance variables in the initialize method.
table = {
:a => 'test',
:b => 12,
:c => lambda { "Hallo" },
:d => def print(); "Hallo in test"; end
}
puts table[:a]
puts table[:b]
puts table[:c].call
puts table[:d].send( :print )
Well, the first line in your class calls a method that doesn't exist yet. It won't even exist after the whole class is loaded though, since that would be a call to the class method and you've only defined instance methods.
Also keep in mind that {0 => a()} will call the method a(), not create a reference to the method a(). If you wanted to put a function in there that doesn't get evaluated until later, you'd have to use some kind of Lambda.
I am pretty new to using callbacks in Ruby and this is how I explained it to myself using an example:
require 'logger'
log = Logger.new('/var/tmp/log.out')
def callit(severity, msg, myproc)
myproc.call(sev, msg)
end
lookup_severity = {}
lookup_severity['info'] = Proc.new { |x| log.info(x) }
lookup_severity['debug'] = Proc.new { |x| log.debug(x) }
logit = Proc.new { |x,y| lookup_sev[x].call(y) }
callit('info', "check4", logit)
callit('debug', "check5", logit)
a = ->(string="No string passed") do
puts string
end
some_hash = { 0 => a }
some_hash[0].call("Hello World")
some_hash[0][]

Resources