Function overloading in Ruby [duplicate] - ruby

This question already has answers here:
Why doesn't ruby support method overloading?
(9 answers)
Closed 7 years ago.
I have this piece of code in Ruby.
class Superheros
class<<self
def foo1(param1)
print "foo1 got executed\n"
end
def foo1
print "foo1 without param got executed\n"
end
def foo3(param1,param2)
print "foo3 got executed\n"
end
end
end
print Superheros.foo3(2,3)
print Superheros.foo1
print Superheros.foo1
print Superheros.foo1(5)
I get the error in Superheros.foo1(5) . But i already have the function foo1(param1) to match it with, but it gives me an error
`foo1': wrong number of arguments (1 for 0) (ArgumentError)
Why is that?
PS: I found out if i remove the function name without the parameter,
the Superheros.foo1(5) works just fine.

Ruby doesn't support method overloading. In your code, your second definition of foo1 replaced the first. That's why you get an error when you try to pass arguments, the method that accepted arguments is gone.
There is a question on SO about this topic here, with some good explanations.

Maybe you could use variable arguments:
def foo1(*args)
case args.length
when 1
puts "Function A"
when 2
puts "Function B"
else
puts "Called with #{args.length} arguments"
end
end

Related

Why doesn't my ruby method call work? (yield) [duplicate]

This question already has answers here:
Passing block into a method - Ruby [duplicate]
(2 answers)
Closed 2 years ago.
I can't figure out why I get this error message when I run my file on the console: no block given (yield) (LocalJumpError)
Here my code:
def block_splitter(array)
array.partition { |item| yield(item) }
end
beatles = ["John", "Paul", "Ringo", "George"]
puts block_splitter(beatles) do |beatle|
beatle.start_with?("P")
end
Thanks for your help!
It's a whitespace issue. Your problem is in this line:
puts block_splitter(beatles) do |beatle|
# ...
end
The above code is being interpreted like this:
puts(block_splitter(beatles)) do |beatle|
# ...
end
I.e. the ruby interpreter thinks that the block is being passed to the puts method, not the block_splitter method.
By assigning a variable and printing the result, you'll see that this works as expected:
result = block_splitter(beatles) do |beatle|
beatle.start_with?("P")
end
puts result
Or, you can define this as a 1-liner, and the ruby interpreter handles it like you expected:
puts block_splitter(beatles) { |beatle| beatle.start_with?("P") }
Or, you could wrap it in extra brackets:
puts(block_splitter(beatles) do |beatle|
beatle.start_with?("P")
end)
So there is a problem with missing parentheses. Ruby interpreter allow not to use those, but when You use nested method calls It's better (and sometimes necessary) to use them. To fix it You can do something like this
puts(block_splitter(beatles) do |beatle|
beatle.start_with?("P")
end)
Or even better
puts(block_splitter(beatles) {|beatle| beatle.start_with?("P")})

Why can't I print the result of reduce/inject directly [duplicate]

This question already has answers here:
Code block passed to each works with brackets but not with 'do'-'end' (ruby)
(3 answers)
Closed 4 years ago.
Found an interesting quirk in the ruby interpreter - at least in MRI 2.4.2.
As far as I can tell, each of the below code snippets should print '123'. If I try to print the result of reduce directly, I get NoMethodError: undefined method '' for 1:Integer (or whatever type the array contains) But if I first save the result and then print it, it works fine..
So, this code is broken:
puts [1,2,3].reduce('') do |memo, num|
memo + num.to_s
end
And this code works:
temp = [1,2,3].reduce('') do |memo, num|
memo + num.to_s
end
puts temp
These should work exactly the same, right? Should this be filed as a bug? Am I just missing something fundamental here?
I'd think it should at least show which method is trying to be called. Can't find anything in google about an undefined method without a method name...
You need parenthesis on the puts call. This works:
puts([1,2,3].reduce('') do |memo, num|
memo + num.to_s
end)
Normally you can avoid parenthesis, but sometimes the parser will find ambiguities and will just raise an error, like in your first case.

Ruby - working of "yield" in Iterator each

A method can invoke an associated block of code one or more times using the Ruby yield statement. we can also pass values to the block by giving parameters to yield in vertical bars (|). Just like I have done below.
1 def print_name
2 puts "Hello "
3 yield "Vikram"
4 end
5
6 animals = %w( ant bee cat dog elk )
7 animals.each {|animal| puts animal }
8 animals.each
9
10 print_name {|name| puts name}
11 print_name
In my code line number 11 is giving an error that :
`print_name': no block given (yield) (LocalJumpError)
This means we cannot use yield in a method without passing a block of code while calling the method.
My question is that, how in my above code "animals.each" (refer line 8) is working without giving any error, if there is a "yield" statement present inside "each" method of ruby?
If it is not present then
animals.each {|animal| puts animal }
this should not have worked.
Ruby allows you to check whether a block was passed to the current method by using Kernel#block_given?. Array#each, as the documentation says, returns an enumerator if no block is given (which is checked using block_given?).
Unlike each, your print_name method tries to yield regardless of whether a block was given, leading to the error on line 11.

How to make a method take one or two arguments? [duplicate]

This question already has answers here:
Should repeat a number of times
(3 answers)
Closed 8 years ago.
I am working on an exercise to make the following tests pass:
describe "repeat" do
it "should repeat" do
repeat("hello").should == "hello hello"
end
# Wait a second! How can you make the "repeat" method
# take one *or* two arguments?
#
# Hint: *default values*
it "should repeat a number of times" do
repeat("hello", 3).should == "hello hello hello"
end
end
I am not understanding this part for some reason.
When I use this:
def repeat(z)
return z + " " + z
end
The first part of the test passes but the second one fails.
Then when I try this:
def repeat(z, 2)
return z * 2
end
I get an error the quits the test/rake.
And then when I try:
f = 2
def repeat(z, f)
return z * f
end
The test won't pass and I get this message:
wrong number of arguments (1 for 2)
I have no idea what is happening here, can someone explain how this works?
You can define the function like following:
def repeat(z, y=2)
return z * y
end
So now, repeat("hello") will result: hellohello and repeat("hello", 3) will return hellohellohello
It seems you're doing the Simon Says exercise.
The purpose of this exercise is to teach you how to take one or multiple arguments, using the default values.
Whenever you assign a default value using the "x = default value", it will be used. If the method was called with a different value, it would be used.
In the example below, the default value of number is 2.
def repeat(word, number = 2)
([word] * number).join(" ")
end
Using the above, we can call repeat("Hello", 3) and it would result with "hello hello hello"
If we call repeat("Hello"), by default it will return "hello hello"
Hope this helps!!!

What does "wrong number of arguments (1 for 0)" mean in Ruby?

What does "Argument Error: wrong number of arguments (1 for 0)" mean?
When you define a function, you also define what info (arguments) that function needs to work. If it is designed to work without any additional info, and you pass it some, you are going to get that error.
Example:
Takes no arguments:
def dog
end
Takes arguments:
def cat(name)
end
When you call these, you need to call them with the arguments you defined.
dog #works fine
cat("Fluffy") #works fine
dog("Fido") #Returns ArgumentError (1 for 0)
cat #Returns ArgumentError (0 for 1)
Check out the Ruby Koans to learn all this.
You passed an argument to a function which didn't take any. For example:
def takes_no_arguments
end
takes_no_arguments 1
# ArgumentError: wrong number of arguments (1 for 0)
I assume you called a function with an argument which was defined without taking any.
def f()
puts "hello world"
end
f(1) # <= wrong number of arguments (1 for 0)
If you change from using a lambda with one argument to a function with one argument, you will get this error.
For example:
You had:
foobar = lambda do |baz|
puts baz
end
and you changed the definition to
def foobar(baz)
puts baz
end
And you left your invocation as:
foobar.call(baz)
And then you got the message
ArgumentError: wrong number of arguments (0 for 1)
when you really meant:
foobar(baz)

Resources