[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Too many default argument values!

Tim Hunter

10/19/2004 10:59:00 PM

Looking for coding style advice...

I'm trying to write a method that describes a rectangle. A rectangle is
defined by the x,y coordinates of its upper-left corner and its width and
height. These values are required. Optionally, the rectangle can have
"styles," like the fill color and the stroke color. Also optionally, the
rectangle can have rounded corners, if you specify how much rounding you
want in the x and y directions. (The default is square corners.)

The method I started with is:

def rect(x, y, width, height, rx=0, ry=0, styles=nil)
# blah, blah, blah
end

Where the styles argument (if present) is a Hash formed by the usual
trailing key=>value pairs. All very standard Ruby.

I was thinking that you'd create a square-corner rectangle like this:

canvas.rect(10, 10, 20, 30, :fill=>'black', :stroke='red')

But of course that doesn't work, because the styles hash
"{:fill=>'black', :stroke=>'red'}" gets assigned to rx, not to styles.

Of course, within rect I could test the class of rx and/or ry and if it's a
Hash, assign it to styles, but that seems kludgy and insufficiently
Rubyish. I could divide rect into two methods, rect and rounded_rect, but
that means that the user has to remember an extra method name. I could make
rx and ry required arguments. Blech.

Thoughts?
11 Answers

Florian Gross

10/19/2004 11:30:00 PM

0

Tim Hunter wrote:

> [snip]
> The method I started with is:
>
> def rect(x, y, width, height, rx=0, ry=0, styles=nil)
> # blah, blah, blah
> end
>
> Where the styles argument (if present) is a Hash formed by the usual
> trailing key=>value pairs. All very standard Ruby.
>
> I was thinking that you'd create a square-corner rectangle like this:
>
> canvas.rect(10, 10, 20, 30, :fill=>'black', :stroke='red')
>
> But of course that doesn't work, because the styles hash
> "{:fill=>'black', :stroke=>'red'}" gets assigned to rx, not to styles.
>
> Of course, within rect I could test the class of rx and/or ry and if it's a
> Hash, assign it to styles, but that seems kludgy and insufficiently
> Rubyish. I could divide rect into two methods, rect and rounded_rect, but
> that means that the user has to remember an extra method name. I could make
> rx and ry required arguments. Blech.
>
> Thoughts?

def rect(x, y, width, height, *more)
styles = more.pop || {}
rx = more.shift || 0
ry = more.shift || 0
end

This will however force you to specify the styles when you want to use a
custom rx/ry.

In general I guess it would be a good idea to just move rx/ry inside the
styles hash.

Regards,
Florian Gross

T. Onoma

10/19/2004 11:31:00 PM

0

My word I'm looking at almost the same problem! I wish we had real named
parameters. But in the mean time try:

def rect(x, y, width, height)
# ...
yield(self)
# ...
end

rect(10,10,100,100){ |r| r.rx=0; r.ry=0; r.fill='red' }

At least I think that's how it's done. For even more "inner" control:

def rect(x, y, width, height, &yld)
# ...
instance_eval &yld
# ...
end

rect(10,10,100,100){ @rx=0; @ry=0; @fill='red' }

These aren't tested so sorry if I made any mistakes, but you get the idea at
least.

T.


On Tuesday 19 October 2004 07:04 pm, Tim Hunter wrote:
| Looking for coding style advice...
|
| I'm trying to write a method that describes a rectangle. A rectangle is
| defined by the x,y coordinates of its upper-left corner and its width and
| height. These values are required. Optionally, the rectangle can have
| "styles," like the fill color and the stroke color. Also optionally, the
| rectangle can have rounded corners, if you specify how much rounding you
| want in the x and y directions. (The default is square corners.)
|
| The method I started with is:
|
| def rect(x, y, width, height, rx=0, ry=0, styles=nil)
| # blah, blah, blah
| end
|
| Where the styles argument (if present) is a Hash formed by the usual
| trailing key=>value pairs. All very standard Ruby.
|
| I was thinking that you'd create a square-corner rectangle like this:
|
| canvas.rect(10, 10, 20, 30, :fill=>'black', :stroke='red')
|
| But of course that doesn't work, because the styles hash
| "{:fill=>'black', :stroke=>'red'}" gets assigned to rx, not to styles.
|
| Of course, within rect I could test the class of rx and/or ry and if it's a
| Hash, assign it to styles, but that seems kludgy and insufficiently
| Rubyish. I could divide rect into two methods, rect and rounded_rect, but
| that means that the user has to remember an extra method name. I could make
| rx and ry required arguments. Blech.
|
| Thoughts?

--
( o _ ���
// trans.
/ \ transami@runbox.com

I don't give a damn for a man that can only spell a word one way.
-Mark Twain



T. Onoma

10/20/2004 1:14:00 AM

0

BTW: you could have different constructors too.

def self.quick_new(x,y,width,height,styles=nil)
self.new(x,y,width,height,0,0,styles)
end

On Tuesday 19 October 2004 07:04 pm, Tim Hunter wrote:
| Looking for coding style advice...
|
| I'm trying to write a method that describes a rectangle. A rectangle is
| defined by the x,y coordinates of its upper-left corner and its width and
| height. These values are required. Optionally, the rectangle can have
| "styles," like the fill color and the stroke color. Also optionally, the
| rectangle can have rounded corners, if you specify how much rounding you
| want in the x and y directions. (The default is square corners.)
|
| The method I started with is:
|
| def rect(x, y, width, height, rx=0, ry=0, styles=nil)
| # blah, blah, blah
| end
|
| Where the styles argument (if present) is a Hash formed by the usual
| trailing key=>value pairs. All very standard Ruby.
|
| I was thinking that you'd create a square-corner rectangle like this:
|
| canvas.rect(10, 10, 20, 30, :fill=>'black', :stroke='red')
|
| But of course that doesn't work, because the styles hash
| "{:fill=>'black', :stroke=>'red'}" gets assigned to rx, not to styles.
|
| Of course, within rect I could test the class of rx and/or ry and if it's a
| Hash, assign it to styles, but that seems kludgy and insufficiently
| Rubyish. I could divide rect into two methods, rect and rounded_rect, but
| that means that the user has to remember an extra method name. I could make
| rx and ry required arguments. Blech.
|
| Thoughts?

--
( o _ ���
// trans.
/ \ transami@runbox.com

I don't give a damn for a man that can only spell a word one way.
-Mark Twain



Robert Klemme

10/20/2004 9:15:00 AM

0


"Tim Hunter" <cyclists@nc.rr.com> schrieb im Newsbeitrag
news:j%gdd.27795$zA3.4433422@twister.southeast.rr.com...
> Looking for coding style advice...
>
> I'm trying to write a method that describes a rectangle. A rectangle is
> defined by the x,y coordinates of its upper-left corner and its width
and
> height. These values are required. Optionally, the rectangle can have
> "styles," like the fill color and the stroke color. Also optionally, the
> rectangle can have rounded corners, if you specify how much rounding you
> want in the x and y directions. (The default is square corners.)
>
> The method I started with is:
>
> def rect(x, y, width, height, rx=0, ry=0, styles=nil)
> # blah, blah, blah
> end
>
> Where the styles argument (if present) is a Hash formed by the usual
> trailing key=>value pairs. All very standard Ruby.
>
> I was thinking that you'd create a square-corner rectangle like this:
>
> canvas.rect(10, 10, 20, 30, :fill=>'black', :stroke='red')
>
> But of course that doesn't work, because the styles hash
> "{:fill=>'black', :stroke=>'red'}" gets assigned to rx, not to styles.
>
> Of course, within rect I could test the class of rx and/or ry and if
it's a
> Hash, assign it to styles, but that seems kludgy and insufficiently
> Rubyish. I could divide rect into two methods, rect and rounded_rect,
but
> that means that the user has to remember an extra method name. I could
make
> rx and ry required arguments. Blech.
>
> Thoughts?

Robert Klemme

10/20/2004 9:20:00 AM

0


"Tim Hunter" <cyclists@nc.rr.com> schrieb im Newsbeitrag
news:j%gdd.27795$zA3.4433422@twister.southeast.rr.com...
> Looking for coding style advice...
>
> I'm trying to write a method that describes a rectangle. A rectangle is
> defined by the x,y coordinates of its upper-left corner and its width
and
> height. These values are required. Optionally, the rectangle can have
> "styles," like the fill color and the stroke color. Also optionally, the
> rectangle can have rounded corners, if you specify how much rounding you
> want in the x and y directions. (The default is square corners.)
>
> The method I started with is:
>
> def rect(x, y, width, height, rx=0, ry=0, styles=nil)
> # blah, blah, blah
> end
>
> Where the styles argument (if present) is a Hash formed by the usual
> trailing key=>value pairs. All very standard Ruby.
>
> I was thinking that you'd create a square-corner rectangle like this:
>
> canvas.rect(10, 10, 20, 30, :fill=>'black', :stroke='red')
>
> But of course that doesn't work, because the styles hash
> "{:fill=>'black', :stroke=>'red'}" gets assigned to rx, not to styles.
>
> Of course, within rect I could test the class of rx and/or ry and if
it's a
> Hash, assign it to styles, but that seems kludgy and insufficiently
> Rubyish. I could divide rect into two methods, rect and rounded_rect,
but
> that means that the user has to remember an extra method name. I could
make
> rx and ry required arguments. Blech.
>
> Thoughts?

Put all (optional) args into the hash and use a default hash

def rect(x, y, width, height, args={:rx=>0, :ry=>0})
# blah, blah, blah
p x
p y
p width
p height
p args
end

Alternative with slightly better performance:

DEFAULT_RECT_ARGS = {
:rx => 0,
:ry => 0,
}.freeze

def rect(x, y, width, height, args=DEFAULT_RECT_ARGS)
....

>> rect(10, 10, 20, 30, :fill=>'black', :stroke=>'red')
10
10
20
30
{:stroke=>"red", :fill=>"black"}

or even

def rect(args=DEFAULT_RECT_ARGS)
....

Kind regards

robert

Matt Maycock

10/20/2004 12:44:00 PM

0

Putting everything in a default hash is sort of a bad idea.

------------------------- code -------------------------
[ummaycoc@localhost ummaycoc]$ ruby -e '
DEFAULT_ARGS = {:foo => :meow, :santa => :love}.freeze
puts("-" * 50)
p DEFAULT_ARGS
def test(arg1, opt_args=DEFAULT_ARGS)
puts "Test: #{opt_args.inspect}"
end

puts
test(:hey)
puts
test(:two, :foo => 1, :ruby => :language)'
--------------------------------------------------
{:santa=>:love, :foo=>:meow}

Test: {:santa=>:love, :foo=>:meow}

Test: {:ruby=>:language, :foo=>1}
------------------------- end code -------------------------

Actually using it, you lose the fact that santa maps to love (thus
everything in the `optional' hash is `mandatory')

a much better idea would be:

DEFAULT_HASH = { ... }
def myFunc(arg1, ..., argN, optHash={})
DEFAULT_HASH.keys.each {|k|
optHash[k] = DEFAULT_HASH[k] unless optHash.include?(k)
}
....
end


This gives you what you actually want. I hope.


On Wed, 20 Oct 2004 18:24:24 +0900, Robert Klemme <bob.news@gmx.net> wrote:
>
> "Tim Hunter" <cyclists@nc.rr.com> schrieb im Newsbeitrag
> news:j%gdd.27795$zA3.4433422@twister.southeast.rr.com...
> > Looking for coding style advice...
> >
> > I'm trying to write a method that describes a rectangle. A rectangle is
> > defined by the x,y coordinates of its upper-left corner and its width
> and
> > height. These values are required. Optionally, the rectangle can have
> > "styles," like the fill color and the stroke color. Also optionally, the
> > rectangle can have rounded corners, if you specify how much rounding you
> > want in the x and y directions. (The default is square corners.)
> >
> > The method I started with is:
> >
> > def rect(x, y, width, height, rx=0, ry=0, styles=nil)
> > # blah, blah, blah
> > end
> >
> > Where the styles argument (if present) is a Hash formed by the usual
> > trailing key=>value pairs. All very standard Ruby.
> >
> > I was thinking that you'd create a square-corner rectangle like this:
> >
> > canvas.rect(10, 10, 20, 30, :fill=>'black', :stroke='red')
> >
> > But of course that doesn't work, because the styles hash
> > "{:fill=>'black', :stroke=>'red'}" gets assigned to rx, not to styles.
> >
> > Of course, within rect I could test the class of rx and/or ry and if
> it's a
> > Hash, assign it to styles, but that seems kludgy and insufficiently
> > Rubyish. I could divide rect into two methods, rect and rounded_rect,
> but
> > that means that the user has to remember an extra method name. I could
> make
> > rx and ry required arguments. Blech.
> >
> > Thoughts?
>
> Put all (optional) args into the hash and use a default hash
>
> def rect(x, y, width, height, args={:rx=>0, :ry=>0})
> # blah, blah, blah
> p x
> p y
> p width
> p height
> p args
> end
>
> Alternative with slightly better performance:
>
> DEFAULT_RECT_ARGS = {
> :rx => 0,
> :ry => 0,
> }.freeze
>
> def rect(x, y, width, height, args=DEFAULT_RECT_ARGS)
> ....
>
> >> rect(10, 10, 20, 30, :fill=>'black', :stroke=>'red')
> 10
> 10
> 20
> 30
> {:stroke=>"red", :fill=>"black"}
>
> or even
>
> def rect(args=DEFAULT_RECT_ARGS)
> ....
>
> Kind regards
>
> robert
>
>


--
There's no word in the English language for what you do to a dead
thing to make it stop chasing you.


Robert Klemme

10/20/2004 1:10:00 PM

0


"Matt Maycock" <ummaycoc@gmail.com> schrieb im Newsbeitrag
news:e86cebfb04102005431b958b4f@mail.gmail.com...
> Putting everything in a default hash is sort of a bad idea.
>
> ------------------------- code -------------------------
> [ummaycoc@localhost ummaycoc]$ ruby -e '
> DEFAULT_ARGS = {:foo => :meow, :santa => :love}.freeze
> puts("-" * 50)
> p DEFAULT_ARGS
> def test(arg1, opt_args=DEFAULT_ARGS)
> puts "Test: #{opt_args.inspect}"
> end
>
> puts
> test(:hey)
> puts
> test(:two, :foo => 1, :ruby => :language)'
> --------------------------------------------------
> {:santa=>:love, :foo=>:meow}
>
> Test: {:santa=>:love, :foo=>:meow}
>
> Test: {:ruby=>:language, :foo=>1}
> ------------------------- end code -------------------------
>
> Actually using it, you lose the fact that santa maps to love (thus
> everything in the `optional' hash is `mandatory')
>
> a much better idea would be:
>
> DEFAULT_HASH = { ... }
> def myFunc(arg1, ..., argN, optHash={})
> DEFAULT_HASH.keys.each {|k|
> optHash[k] = DEFAULT_HASH[k] unless optHash.include?(k)
> }
> ....
> end
>
>
> This gives you what you actually want. I hope.

True. I forgot that. Alternatives:

DEFAULT_HASH = { ... }.freeze
def myFunc(a, b, args={})
@a = a
@b = b
@foo = args[:foo] || DEFAULT_HASH[:foo]
....
end

or

DEFAULT_HASH = { ... }.freeze

def rect(a, b, args = DEFAULT_HASH)
tmp = DEFAULT_HASH.dup.update( args )
...
@a = a
@b = b
@foo = tmp[:foo]
...
end

Kind regards

robert

>
>
> On Wed, 20 Oct 2004 18:24:24 +0900, Robert Klemme <bob.news@gmx.net>
wrote:
> >
> > "Tim Hunter" <cyclists@nc.rr.com> schrieb im Newsbeitrag
> > news:j%gdd.27795$zA3.4433422@twister.southeast.rr.com...
> > > Looking for coding style advice...
> > >
> > > I'm trying to write a method that describes a rectangle. A rectangle
is
> > > defined by the x,y coordinates of its upper-left corner and its
width
> > and
> > > height. These values are required. Optionally, the rectangle can
have
> > > "styles," like the fill color and the stroke color. Also optionally,
the
> > > rectangle can have rounded corners, if you specify how much rounding
you
> > > want in the x and y directions. (The default is square corners.)
> > >
> > > The method I started with is:
> > >
> > > def rect(x, y, width, height, rx=0, ry=0, styles=nil)
> > > # blah, blah, blah
> > > end
> > >
> > > Where the styles argument (if present) is a Hash formed by the usual
> > > trailing key=>value pairs. All very standard Ruby.
> > >
> > > I was thinking that you'd create a square-corner rectangle like
this:
> > >
> > > canvas.rect(10, 10, 20, 30, :fill=>'black', :stroke='red')
> > >
> > > But of course that doesn't work, because the styles hash
> > > "{:fill=>'black', :stroke=>'red'}" gets assigned to rx, not to
styles.
> > >
> > > Of course, within rect I could test the class of rx and/or ry and if
> > it's a
> > > Hash, assign it to styles, but that seems kludgy and insufficiently
> > > Rubyish. I could divide rect into two methods, rect and
rounded_rect,
> > but
> > > that means that the user has to remember an extra method name. I
could
> > make
> > > rx and ry required arguments. Blech.
> > >
> > > Thoughts?
> >
> > Put all (optional) args into the hash and use a default hash
> >
> > def rect(x, y, width, height, args={:rx=>0, :ry=>0})
> > # blah, blah, blah
> > p x
> > p y
> > p width
> > p height
> > p args
> > end
> >
> > Alternative with slightly better performance:
> >
> > DEFAULT_RECT_ARGS = {
> > :rx => 0,
> > :ry => 0,
> > }.freeze
> >
> > def rect(x, y, width, height, args=DEFAULT_RECT_ARGS)
> > ....
> >
> > >> rect(10, 10, 20, 30, :fill=>'black', :stroke=>'red')
> > 10
> > 10
> > 20
> > 30
> > {:stroke=>"red", :fill=>"black"}
> >
> > or even
> >
> > def rect(args=DEFAULT_RECT_ARGS)
> > ....
> >
> > Kind regards
> >
> > robert
> >
> >
>
>
> --
> There's no word in the English language for what you do to a dead
> thing to make it stop chasing you.
>
>

James Gray

10/20/2004 1:12:00 PM

0

On Oct 20, 2004, at 7:43 AM, Matt Maycock wrote:

> a much better idea would be:
>
> DEFAULT_HASH = { ... }
> def myFunc(arg1, ..., argN, optHash={})
> DEFAULT_HASH.keys.each {|k|
> optHash[k] = DEFAULT_HASH[k] unless optHash.include?(k)
> }
> ....
> end

Or slightly simpler:

DEFAULT_OPTIONS = { ... }
def my_func( arg1, ... argN, options = { } )
options = DEFAULT_OPTIONS.merge(options)

# ...
end

James Edward Gray II



Robert Klemme

10/20/2004 1:22:00 PM

0


"James Edward Gray II" <james@grayproductions.net> schrieb im Newsbeitrag
news:98E27FB2-2299-11D9-A2B6-000A95BA45F8@grayproductions.net...
> On Oct 20, 2004, at 7:43 AM, Matt Maycock wrote:
>
> > a much better idea would be:
> >
> > DEFAULT_HASH = { ... }
> > def myFunc(arg1, ..., argN, optHash={})
> > DEFAULT_HASH.keys.each {|k|
> > optHash[k] = DEFAULT_HASH[k] unless optHash.include?(k)
> > }
> > ....
> > end
>
> Or slightly simpler:
>
> DEFAULT_OPTIONS = { ... }
> def my_func( arg1, ... argN, options = { } )
> options = DEFAULT_OPTIONS.merge(options)
>
> # ...
> end
>
> James Edward Gray II
>
>
>

Robert Klemme

10/20/2004 1:26:00 PM

0


Sorry for the empty post.


"James Edward Gray II" <james@grayproductions.net> schrieb im Newsbeitrag
news:98E27FB2-2299-11D9-A2B6-000A95BA45F8@grayproductions.net...
> On Oct 20, 2004, at 7:43 AM, Matt Maycock wrote:
>
> > a much better idea would be:
> >
> > DEFAULT_HASH = { ... }
> > def myFunc(arg1, ..., argN, optHash={})
> > DEFAULT_HASH.keys.each {|k|
> > optHash[k] = DEFAULT_HASH[k] unless optHash.include?(k)
> > }
> > ....
> > end
>
> Or slightly simpler:
>
> DEFAULT_OPTIONS = { ... }
> def my_func( arg1, ... argN, options = { } )
> options = DEFAULT_OPTIONS.merge(options)

Thanks for that hint! I didn't know Hash#merge yet.

robert