x-yuri
x-yuri

Reputation: 18893

Check if no arguments passed

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

Answers (2)

Jörg W Mittag
Jörg W Mittag

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

Uri Agassi
Uri Agassi

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

Related Questions