Messing with optional argument check for the umpteenth time, eg.
def meth(a=Exception)
if a != Exception
…
else
…
end
end
Other’s might do:
def meth(*a)
if !a.empty?
a = a.first
…
else
…
end
end
Neither of which are very satisfying. So it occurs to me tonight that
we already have #has_block? to see if a block was passed. So how about
a #has_arguments? to query if any arguments have been passed. So
then…
def meth(a=default)
if has_arguments?
…
else
…
end
end
Normally I just make the default value for an optional parameter nil,
and check for nil.
If nil is a valid value, then I’d do something like
Right, it precisely the times when nil is a valid value that it is a
problem.
class A
MissingArgument = Object.new
def meth(a=MissingArgument)
if a == MissingArgument
else
end
end
end
Hmm… doesn’t that indicate a need?
And yes, I’ve done that before too, but it falls into the realm of my
first example. Exception is typically just as good as MissingArgument,
and that way you don’t need a stray object that exists just to exist.
But in either case it is still a (albeit minor) jerry-rig.
What we have here is a nail, and I’d much rather have a nice hammer
than to keep using this damn rock.
Either way is fine. The defined method interface doesn’t matter. #has_arguments? would simply report false if a call to the method
passed no arguments. If the interface definition itself does not allow
for no arguments, eg. ‘def meth(a)’, then #has_arguments? would simply
never return false.
Either way is fine. The defined method interface doesn’t matter. #has_arguments? would simply report false if a call to the method
passed no arguments. If the interface definition itself does not allow
for no arguments, eg. ‘def meth(a)’, then #has_arguments? would simply
never return false.
T.
I’m still not convinced this is necessarily needed, but, how about this
for a first stab (still looking at whether there’s a way to not need the
explicit call to binding) :
class Object
def has_arguments?(b)
vars = eval(“local_variables”,b)
return false if vars.length == 0
vars.each do |v|
return false if eval("#{v}.nil?",b)
end
return true
end
end
class Foo
def initialize(first=nil)
if (has_arguments? binding)
puts “We’re defined”
else
puts “Not!”
end
end
def no_args
if (has_arguments? binding)
puts “We’re defined”
else
puts “Not!”
end
end
def mandatory_arg(a)
if (has_arguments? binding)
puts “We’re defined”
else
puts “Not!”
end
end
end
As a followup, has_arguments? could be written as:
def has_arguments?(&b)
vars = eval(“local_variables”,b.binding)
return false if vars.length == 0
vars.each do |v|
return false if eval("#{v}.nil?",b)
end
return true
end
end
then you’d call it like:
if has_arguments? {} #note the empty block
something
end
if has_arguments? {} #note the empty block
something
end
Matt
Using #local_variables won’t work for this, will it?
def has_arguments?(&b)
vars = eval(“local_variables”,b.binding)
return false if vars.length == 0
vars.each do |v|
return false if eval("#{v}.nil?",b)
end
return true
end
def foo(*a)
if has_arguments? {} #note the empty block
p a
else
puts “no args”
end
x=3 # <-- N.B.
end
So it occurs to me tonight that
we already have #has_block? to see if a block was passed. So how about
a #has_arguments? to query if any arguments have been passed. So
then…
def meth(a=default)
if has_arguments?
…
else
…
end
end
Ah… now that would be nice.
But it doesn’t solve the general case of
def meth(a, b, c=default)
…
end
You could have argument_size I suppose. I’ve never felt the need.
Generally the only time I’ve done this is with methods which have a hash
of options, in which case ‘has_key?’ does the job.
Messing with optional argument check for the umpteenth time, eg.
def meth(a=Exception)
if a != Exception
…
else
…
end
end
My 0.02 EUR: if your method’s behavior changes depending on argument
or argument types chances are that you may rather want different
methods.
As a side note: I see this sometimes
def m(a = nil) @a = a.nil? ? 123 : a
end
which is of course silly. The same would be much better expressed as
def m(a = 123) @a = a
end
There is no need for additional optional logic - at least in these
simple cases.
end
end
Ah… now that would be nice.
It may be useful in some cases but since you can always do the “trick”
with “*” I am not sure whether we really need this. I always found
block_given? a bit awkward since it looks like a method of self but is
rather a quick way to get at information about the argument list. The
only reason I use it at times is the fact that the combination m(&b)
b.call is slower than the combination m() yield.
I do not see the connection of this to what I posted.
It saves replicating your default values all over the place, which isn’t
very DRY.
I don’t see how this makes me replicate my default values all over the
place. My proposed solution just changes how a method internally
works, there is no effect on the interface.
Or you could more simply write
def m(a = nil) @a = a || 123
end
I fail to see how this is simpler than
def m(a = 123) @a = a
end
I’m in line with Rick: either I must be missing something - or you.
I do not see the connection of this to what I posted.
Argh! Now I see what you mean. If you use nil as universal “absence”
marker then you have to declare the default only inside the method
when doing the a.nil? logic because you will pass it through from
calling methods.
I only considered a single method and did not have nested calls in
mind. Do you believe that these are common enough to warrant making
this a common pattern?