Reputation: 18893
Here's some code:
$ cat 1.rb
#!/usr/bin/env ruby
def f p1 = nil
unless p1 # TODO
puts 'no parameters passed'
end
end
f
f nil
$ ./1.rb
no parameters passed
no parameters passed
The question is, is there a way to distinguish between no arguments and one nil
argument passed?
UPD
I decided to add a use case in javascript
to make things hopefully clearer:
someProp: function(value) {
if (arguments.length) {
this._someProp = value;
}
return this._someProp;
}
Upvotes: 6
Views: 4997
Reputation: 369488
There are three ways in general use. One way is to use the default value to set another variable indicating whether or not the default value was evaluated:
def f(p1 = (no_argument_passed = true; nil))
'no arguments passed' if no_argument_passed
end
f # => 'no arguments passed'
f(nil) # => nil
The second way is to use some object that is only known inside the method as default value, so that it is impossible for an outsider to pass that object in:
-> {
undefined = BasicObject.new
define_method(:f) do |p1 = undefined|
'no arguments passed' if undefined.equal?(p1)
end
}.()
f # => 'no arguments passed'
f(nil) # => nil
Of these two, the first one is more idiomatic. The second one (actually, a variation of it) is used inside Rubinius, but I have never encountered it anywhere else.
A third solution would be to take a variable number of arguments using a splat:
def f(*ps)
num_args = ps.size
raise ArgumentError, "wrong number of arguments (#{num_args} for 0..1)" if num_args > 1
'no arguments passed' if num_args.zero?
end
f # => 'no arguments passed'
f(nil) # => nil
Note that this requires you to re-implement Ruby's arity checking by hand. (And we still haven't gotten it right, because this raises the exception inside the method, whereas Ruby would raise it at the call site.) It also requires you to manually document your method signature because automated documentation generators such as RDoc or YARD will infer an arbitrary number of parameters instead of a single optional one.
Upvotes: 11
Reputation: 37409
You could request for splat arguments:
def f(*args)
if args.empty?
puts 'no parameters passed'
else
p1 = args[0]
...
end
end
Some other option might be to have a private object to indicate no parameter passed:
def initialize
@no_param_passed = Object.new
end
def f(p1 = @no_param_passed)
if p1 == @no_param_passed
puts 'no parameters passed'
end
end
Upvotes: 5