Too many default argument values!

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?

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

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

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

"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?

"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

I had same issue,
I had couple of ideas, of course one was using Hash.

I tried to accomplish it another way,

class Canvas

    attr_accessor :args

    def rect
    # Draw canvus using
    # args.width
    # args.length
    # args.fill-color
    end

    def args
        if @args.nil?
            @args = Arguments.new
        end
        return @args
    end
end

class Arguments < Canvas
    attr_accessor :width, :length, :fill-color, :border-color

    def initialize
        return self
    end
end

canvas = Canvas.new
canvas.args.width = 5
canvas.args.height = 10
..
..
..
canvas.args.fill-color = 'Red'
canvas.args.border-color = 'Black'

canvas.rect

Is it too complicated ? !!

Mohammad

···

On Tue, 2004-10-19 at 19:04, 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?

--
Mohammad Khan <mkhan@lextranet.com>
Legal Computer Solutions, Inc.

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.

Or slightly simpler:

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

  # ...
end

James Edward Gray II

···

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

"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

>
> "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

···

On Wed, 20 Oct 2004 18:24:24 +0900, Robert Klemme <bob.news@gmx.net> wrote:
> 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 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

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