Reputation: 3365
For example, if I have
def function(arg)
#do stuff
end
how do I only allow arg
to be an Array? I could do
def function(arg)
if arg.class != 'Array'
return 'Error'
else
#do stuff
end
end
but is there any better way of doing this?
Upvotes: 7
Views: 2920
Reputation: 168101
If the receiver in your example is trivial and it is defined like a function rather then a method, then, you might want to turn the argument into a receiver.
class Array
def function
# do stuff
end
end
Upvotes: 0
Reputation: 42192
In stead of raising an error you could make certain you convert the argument to an array but you should rather work at the routine providing the parameter so it gives you an array in the first place.
def function(*arg)
a = arg.flatten
p a
end
function("ab")
function(1,2)
function([1,2])
#=>
#["ab"]
#[1, 2]
#[1, 2]
Upvotes: 0
Reputation: 18706
You can't do def function(Array arg)
like in other languages, but you can replace four lines of your second snippet by a single one:
def function(arg)
raise TypeError unless arg.is_a? Array
# code...
end
Upvotes: 13
Reputation: 84353
Ruby does not support type checking--at least, not in the sense of being able to declare argument types as part of the method signature. Generally, the caller is responsible for passing the correct objects, or the passed objects are responsible for converting themselves. However, you can certainly do your own coercions. In fact, about.com has an example of using the case statement for doing just this kind of type checking.
Here are some additional examples:
# Ask your object to convert itself to an array.
def foo my_object
my_object.to_a
end
# Give your object a #to_a method if it doesn't already have one.
def foo my_object
unless my_object.respond_to? :to_a
def my_object.to_a
# perform your type conversion
end
end
end
# Do your own type conversions.
def foo my_object
case my_object
when Array
p my_object
when String
my_object.scan /\d+/
end
end
You can mix and match any of these techniques, and there are certainly others. Ruby is a very flexible language.
Upvotes: 1
Reputation: 26979
Others have pointed out how you can technically enforce a type of an argument, but you are fighting a fundamental battle with the ruby way of thinking. Google around for "duck typing".
In the ruby world, we don't usually worry about the type of an argument, but rather whether it meets the interface of what we want to do with it. In other words, does it quack like a duck? Good enough!
Lets suppose you are trying to use an Array for something:
def function(arg)
arg.each do |a|
puts a
end
end
If you call this like: function(1)
, you get NoMethodError: undefined method 'each'
Let's use your idea of forcing it to be an array.
def function(arg)
raise TypeError unless arg.is_a? Array
arg.each do |a|
puts a
end
end
Ok, now we have made a different error, but if the method gets called with something other than an array, it still generates an error.
Furthermore, what about this?
function("Hello World".chars)
Whoops, we have an error, despite the fact that the function would have worked!
The ruby way would be something more like:
def function(arg)
if arg.respond_to? :each
arg.each do |a|
puts a
end
else
puts arg
end
end
Now your function works well for all sorts of inputs:
function([1,2,3,4])
function("foo")
function("foo".chars)
As for the correctness of the function, you cover that using tests, not the compiler. But that's a whole other subject. :)
Upvotes: 7
Reputation: 2254
Well considered that Ruby is dynamically typed you can't enforce that in a similar way such as in C. Instead of comparing against a string you can actually compare it against the class.
arg.is_a?(Array)
To improve your example I would have written:
def function(arg)
raise TypeError unless arg.is_a?(Array)
# Do stuff
end
Upvotes: 2