What’s the best way of checking if an argument has been given or not?

Hi!

What’s the best way of checking if an argument has been given or not?

That is, what’s the best way of achieving

class A
ArgumentMissing = Object.new.freeze

def b(c = ArgumentMissing)
if ArgumentMissing.equal? c
puts ‘no argument was given’
else
puts c
end
end
end

A.new.b # => no argument was given
A.new.b 1 # => 1

? I remember seeing something that didn’t require a constant like
this, but I can’t seem to find it. (Note: I don’t want to use nil for
this particular case. I would preferably use a value that is
inaccessible outside of A.)

…probably not the best way, but this works:

class A
def initialize(arg = “NO ARGUMENT”)
if arg == “NO ARGUMENT”
puts “no argument given”
else
puts arg
end
end
end

A.new
A.new(“foo”)

=> no argument given
=> foo

  • j

On Fri, Oct 14, 2011 at 15:07, jake kaiden [email protected] wrote:

end
Perhaps I wasn’t clear enough. It shouldn’t be possible for the
caller to actually pass in an argument that will match.

A.new(‘NO ARGUMENT’) # => no argument given

You can use this syntax, too. “args” becomes an array of all arguments
given.

def foo *args
if args.length==0
puts ‘no argument was given’
else
puts args[0]
end
end

If you only allow one argument, you should do some checking whether
there are too many.

– Matma R.

You could do it as a wrapper:

def foo_argchek *args
if args.len == 0
“no args given”
else
real_foo(*args)
end
end

def real_foo(arg1, arg2)
#do stuff
end

On Fri, Oct 14, 2011 at 15:29, Bartosz Dziewoński [email protected]
wrote:

If you only allow one argument, you should do some checking whether
there are too many.

Your suggestion is valid. though it seems I underspecified my question
in yet another way. Until Ruby gets a rb_scan_args equivalent, I’d
rather not complicate my argument processing unnecessarily by
destructuring an argument array by hand.

On Fri, Oct 14, 2011 at 15:51, Chris H. [email protected]
wrote:

def real_foo(arg1, arg2)
#do stuff
end

How is this a solution (to anything)?

One can, of course, use define_method (in 1.9), but it’s not ideal, as
you can’t pass a block to A#a in that case.

class A
missing = Object.new
define_method :a do |b = missing|
if b == missing
puts ‘no argument given’
else
puts b
end
end
end

A.new.a
A.new.a 1

You said you didn’t want to manually do it, this lets the interpreter
do it for you.

Maybe a more realistic example would clarify why having to do some
work to achieve this seems
too much effort?

Hmm, if you really don’t want to use the splat *args, you could create a
new instance of A and extend it with a #missing? method, and pass that
instance as the default value for the method. That way, the instance
won’t be available across classes and you can just check if the argument
responds_to :missing?

class A

missing_arg = new
class << missing_arg
def missing?
true
end
end

def a(arg=missing_arg)

end

end

Or, you could check the #object_id of whatever placeholder ‘missing’
object to make sure it’s the missing object and not some rogue object of
the same class.

Hope this helps,

-Luke

luke gruber [2011-10-14 17:15]:

That way, the instance won’t be available across classes and you
can just check if the argument responds_to :missing?
or you can just do this:

class A

def b(c = d = true) # or some other truthy value
if d
puts ‘no argument was given’
else
puts c
end
end

end

can’t remember where i first saw it, but it works perfectly :wink:

cheers
jens

On Fri, Oct 14, 2011 at 17:31, Jens W. [email protected]
wrote:

end

can’t remember where i first saw it, but it works perfectly :wink:

Yes, of course! That’s the trick I saw too; checking if the optional
argument’s default value was evaluated.

Here’s a more general solution that allows you to set d to a value
independent of the desired default value for the argument:

def m(a = (d = true; nil))

d will be true if argument a wasn’t specified

end

One easily forgets how expressive Ruby can be. Or how easily it is to
abuse it.

Thanks!

What’s the situation this code is going to be used in?

What’s wrong with rescuing?

def foo(a, b); [a, b]; end

begin; foo(); rescue(ArgumentError); “More, please.”; end
=> “More, please.”

On Oct 14, 11:31am, Jens W. [email protected] wrote:

else
puts c
end
end

end

can’t remember where i first saw it, but it works perfectly :wink:

That’s pretty cleaver, although it reads perhaps a bit too strangely.

What I have always done is… obviously, if nil is not a valid
argument, then just use that.

def b(a=nil)
if a

end

But if nil is valid then use ArgumentError, as that won’t be a
valid argument in 99.99% (or so) cases anyway.

def b(a=ArgumentError)
if a == ArgumentError

end

For the most robust solution, Ruby F.s defines a toplevel constant
called NA, the sole purpose of which is to fill in for cases such as
this.

def b(a=NA)
if a == NA

end

That’s my favorite, but it require’s a dependency on Facets or copy
and pasting the extra code to one’s project.

(hmm… it occurs to me that global $NA variable would be good to
have too so there’s no namespace issues such as in a BasicObjcet
subclass)

2011/10/14 Jens W. [email protected]:

end
I have to admit that’s kinda cool.

2011/10/14 Intransition [email protected]:

So, is there a downside to this?

Unreadability if you don’t know what it does? Possibly barfing of
code-munging tools? I think that’s it. I’d use it :wink:

– Matma R.

On Oct 14, 12:11pm, Nikolai W. [email protected] wrote:

def m(a = (d = true; nil))

d will be true if argument a wasnt specified

end

One easily forgets how expressive Ruby can be. Or how easily it is to abuse it.

Thanks!

Well shit, that might be my new favorite too.

def m(a=(na=true))
p a, na
end

m
true
true

m(‘foo’)
“foo”
nil

So, is there a downside to this?

2011/10/14 Phillip G. [email protected]:

The downside to this approach is that you use “true” to say something
is “false”.

Nothing stops him from using false in there? You’d just have to
change the condition later (to d==false, not !d, of course).

– Matma R.

On Fri, Oct 14, 2011 at 5:31 PM, Jens W. [email protected]
wrote:

else
puts c
end
end

end

The downside to this approach is that you use “true” to say something
is “false”.


Phillip G.

gplus.to/phgaw | twitter.com/phgaw

A method of solution is perfect if we can forsee from the start,
and even prove, that following that method we shall attain our aim.
– Leibniz

Phillip G. [2011-10-14 23:11]:

The downside to this approach is that you use “true” to say
something is “false”.
well, i guess that depends on your point of view :wink: you seem to read
it as “argument given? => false”; i read it as “apply default case?
=> true”. which is why i always name that variable ‘default’ to
begin with.

Nikolai W. [2011-10-14 18:11]:

Here’s a more general solution that allows you to set d to a
value independent of the desired default value for the argument:

def m(a = (d = true; nil))

d will be true if argument a wasn’t specified

end
exactly! but i hardly ever have a use case for this. i usually don’t
care about the value of ‘a’ when i’m in the default case.

it reminds me of another useful technique, though:

seen = Hash.new { |h, k| h[k] = true; false }
[1, 2, 3, 2, 3, 4].each { |i| p i unless seen[i] }

contrived example, i know. but comes in handy at times.

One easily forgets how expressive Ruby can be. Or how easily it
is to abuse it.
so true :wink: