#has_arguments?

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

Ah... now that would be nice.

def meth(*a)
if !a.empty?
a = a.first
...
else
...
end
end

Maybe morph this to

def meth(*a)
  if has_arguments? a
    ...
  else
    ...
  end
end

?
-r

I've never felt the need for this.

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

class A

    MissingArgument = Object.new

   def meth(a=MissingArgument)
       if a == MissingArgument
       else
       end
   end
end

···

On Tue, Aug 18, 2009 at 11:37 PM, Intransition<transfire@gmail.com> wrote:

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

Ah... now that would be nice.

--
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

Here's a little trick I learned (very hacky):

  def meth(a=(no_argument='default'))
    if no_argument
      'nothing given'
    else
      "we got #{a.inspect}"
    end
  end

Your default argument can't be falsy (but you could use something
truey and use your falsy value in its place). Anyway:

  036:0> meth
  "nothing given"
  037:0> meth(nil)
  "we got nil"
  038:0> meth('whatever')
  "we got "whatever""
  039:0> meth
  "nothing given"

I can't vouch for JRuby or Ruby 1.9 or Rubinius or IronRuby for this
one (work's a strictly 1.8.6 kind of place).

-Chris

···

On Aug 18, 11:37 pm, Intransition <transf...@gmail.com> wrote:

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

Ah... now that would be nice.

def meth(a=(defaults=true;Exception))
  if !defaults
    ...
  else
    ...
  end
end

- charlie

···

On Tue, Aug 18, 2009 at 10:37 PM, Intransition<transfire@gmail.com> wrote:

Messing with optional argument check for the umpteenth time, eg.

def meth(a=Exception)
if a != Exception
...
else
...
end
end

Thomas Sawyer wrote:

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.

···

--
Posted via http://www.ruby-forum.com/\.

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.

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

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'm undecided really.

Kind regards

robert

···

2009/8/19 Intransition <transfire@gmail.com>:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

> 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

> Ah... now that would be nice.

I've never felt the need for this.

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? :wink:

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.

···

On Aug 19, 9:09 am, Rick DeNatale <rick.denat...@gmail.com> wrote:

On Tue, Aug 18, 2009 at 11:37 PM, Intransition<transf...@gmail.com> wrote:

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.

···

On Aug 19, 7:53 am, Roger Pack <rogerdp...@gmail.com> wrote:

> def meth(*a)
> if !a.empty?
> a = a.first
> ...
> else
> ...
> end
> end

Maybe morph this to

def meth(*a)
if has_arguments? a
...
else
...
end
end

Yeah, my version avoids the falsy issue...but yours is shorter.

Either way...works fine in JRuby and 1.9.

- Charlie

···

On Wed, Aug 19, 2009 at 3:40 PM, Chris Shea<cmshea@gmail.com> wrote:

Here's a little trick I learned (very hacky):

def meth(a=(no_argument='default'))
if no_argument
'nothing given'
else
"we got #{a.inspect}"
end
end

Your default argument can't be falsy (but you could use something
truey and use your falsy value in its place). Anyway:

Robert Klemme wrote:

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

No, it's not the same. Consider:

  def foo(a = nil)
    m(a)
  end

  foo()

It saves replicating your default values all over the place, which isn't
very DRY.

Or you could more simply write

  def m(a = nil)
    @a = a || 123
  end

···

--
Posted via http://www.ruby-forum.com/\.

class X
   NONE = Object.new

   def blah(a = NONE)
     # ...
   end
end

Suffices for nil as valid value

···

On Aug 19, 2009, at 8:08, Trans <transfire@gmail.com> wrote:

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.

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

Matt

···

On Thu, 20 Aug 2009, Trans wrote:

On Aug 19, 7:53 am, Roger Pack <rogerdp...@gmail.com> wrote:

def meth(*a)
if !a.empty?
a = a.first
...
else
...
end
end

Maybe morph this to

def meth(*a)
if has_arguments? a
...
else
...
end
end

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.

No, it's not the same. Consider:

def foo(a = nil)
m(a)
end

foo()

It saves replicating your default values all over the place, which isn't
very DRY.

I didn't take Robert as meaning that the above is silly.

Or you could more simply write

def m(a = nil)
@a = a || 123
end

But, unless I'm missing something subtle, THIS is what Robert was
calling silly, since as far as I can tell, this

def m(a=123)
    @a = a
end

Has exactly the same effect, and seems much clearer.

···

On Thu, Aug 20, 2009 at 8:03 AM, Brian Candler<b.candler@pobox.com> wrote:

--
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

Robert Klemme wrote:

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

No, it's not the same.

Can you explain what the differences are?

Consider:

def foo(a = nil)
m(a)
end

foo()

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_. :slight_smile:

Cheers

robert

···

2009/8/20 Brian Candler <b.candler@pobox.com>:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

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

Matt

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?

Btw, we can also do this:

def foo(*a)
  bar(*a)
end

def bar(a = 123)
  @a = a
end

Kind regards

robert

···

2009/8/20 Robert Klemme <shortcutter@googlemail.com>:

2009/8/20 Brian Candler <b.candler@pobox.com>:

Robert Klemme wrote:

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

No, it's not the same.

Can you explain what the differences are?

Consider:

def foo(a = nil)
m(a)
end

foo()

I do not see the connection of this to what I posted.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Rick Denatale wrote:

But, unless I'm missing something subtle, THIS is what Robert was
calling silly, since as far as I can tell, this

def m(a=123)
    @a = a
end

Has exactly the same effect

I don't think so:

# prog1.rb
def m(a=123)
  @a = a
end
def a
  @a
end

def foo(x=nil)
  m(x)
end
foo
puts "The result is #{a.inspect}" # shows nil

# prog2.rb
def m(a=nil)
  @a = a || 123
end
def a
  @a
end

def foo(x=nil)
  m(x)
end
foo
puts "The result is #{a.inspect}" # shows 123

···

--
Posted via http://www.ruby-forum.com/\.

Robert Klemme wrote:

I do not see the connection of this to what I posted.

What I mean is, when you have an argument with a default value, you may
want to use the default value even when nil is explicitly passed in,
e.g. m(nil)

This is usually because the function is being called from a higher-level
function, which passes through a value from a higher level again, and
doesn't want to be concerned with knowing what the default value is for
the low-level function. e.g.

# Option 1 - not very DRY

def z(a = 123)
  puts "Handling #{a}"
end

def y(count = 3, a = 123)
  count.times { z(a) }
end

def x(count = 3, a = 123)
  y(count, a)
end

x()

# Option 2 - not always possible

def z(a = 123)
  puts "Handling #{a}"
end

def y(count = 3, *args)
  count.times { z(*args) }
end

def x(*args)
  y(*args)
end

x()

# Option 3 - not pretty

def z(a = 123)
  puts "Handling #{a}"
end

def y(count = 3, a = nil)
  count.times { a ? z(a) : z }
end

def x(count = nil, a = nil)
  count ? (a ? y(count,a) : y(count)) : y
end

x()

# Option 4

def z(a = nil)
  a ||= 123
  puts "Handling #{a}"
end

def y(count = nil, a = nil)
  count ||= 3
  count.times { z(a) }
end

def x(count = nil, a = nil)
  y(count, a)
end

x()

This last option is the one which was called "silly", but I think in
this case it's actually quite a reasonable way to solve the problem. The
defaults are specified in exactly one place, and passing nil means 'use
the default'

Regards,

Brian.

···

--
Posted via http://www.ruby-forum.com/\.

Matthew K. Williams wrote:

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

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

foo()
foo(1,2,3)

__END__

Output:

no args

···

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407