Named/positional method args

I have a method here that takes two arguments. Both are optional, with
appropriate default values. The first is a string which represents a
filename
to write data to. The second is an integer which represents which data
from a
choice of 1 or more should be written to the file.

So I have:

def write_picture(outfile = nil, n = 1)

When I call as:

write_picture()

it does the right thing and uses both defaults.

When I call as:

write_picture(“somefile”)

it does the right thing and writes the default data to “somefile”

When I call:

write_picture(“front cover”, 1)
write_picture(“back cover”, 2)

it does the right thing. However, when I do:

write_picture(n=1)

I am sure you can guess what happens. I get a picture written to a file
with “1” as a filename. This seems like non-intuitive behavior. With no
support for named args shouldn’t it error here?

Now: I gather I can do:

def write_picture(*args)

and perhaps do a type check on each argument, as there must be one each
String
and Integer, and sort them out appropriately. However, this relies too
heavily, for my comfort, on the users passing sane values to the method.

Is there a clean way to accomplish my goal? Are there plans to give
named
arguments to Ruby in the future?

Thanks for consideration,
-d

darren kirby wrote:

def write_picture(outfile = nil, n = 1)

Is there a clean way to accomplish my goal? Are there plans to give named
arguments to Ruby in the future?

The standard technique for doing this is to use a hash with symbols for
the argument names. Remember Ruby collects up trailing hash assignments
into a single hash, so you could do something like this;

write_picture(:outfile=>whatever, :n=>1)

Your method is defined like this:

def write_picture(args)
outfile = args[:outfile]
n = args[:n]

end

And, yes, I believe the current plan is to have named arguments in a
future release of Ruby.

Hi –

On Sun, 24 Jun 2007, darren kirby wrote:

When I call:
support for named args shouldn’t it error here?
You’re performing a local variable assignment. Try this and you’ll
see:

write_picture(n=1)
puts n

:slight_smile:

Now: I gather I can do:

def write_picture(*args)

and perhaps do a type check on each argument, as there must be one each String
and Integer, and sort them out appropriately. However, this relies too
heavily, for my comfort, on the users passing sane values to the method.

Is there a clean way to accomplish my goal? Are there plans to give named
arguments to Ruby in the future?

The usual idiom for this is to use a hash:

write_picture(:outfile => “file.out”, :n => 1)

I’ve lost track of where things stand with named arguments in future
Rubies but the hash technique is generally quite adequate.

David

On 6/23/07, darren kirby [email protected] wrote:

it does the right thing. However, when I do:

write_picture(n=1)

I am sure you can guess what happens. I get a picture written to a file
with “1” as a filename. This seems like non-intuitive behavior. With no
support for named args shouldn’t it error here?

No, that just becomes write_picture(1)

the reason for this is that arguments can be expressions, not just
singular values.

Now: I gather I can do:

def write_picture(*args)

and perhaps do a type check on each argument, as there must be one each String
and Integer, and sort them out appropriately. However, this relies too
heavily, for my comfort, on the users passing sane values to the method.

Is there a clean way to accomplish my goal?

Yes. use a hash

def my_method(options={})
a = options[:a]
b = options[:b]
end

my_method(:a => 1, :b => 2)
my_method(:b => 3)
my_method(:a => 1)

all work. You can then do something like

def my_method(options={})
a = options[:a] || 10
b = options[:b] || 5
end

to set defaults, or if you have a whole bunch, look at Hash#merge.

Are there plans to give named arguments to Ruby in the future?

Not that I know of but syntactic sugar will be allowed for hash
definition, which will allow

my_method( :foo => 2, :bar => 10)

to become

my_method( :foo : 2, :bar : 10)

(I think…)

On 6/23/07, Gregory B. [email protected] wrote:

Not that I know of but syntactic sugar will be allowed for hash
definition, which will allow

my_method( :foo => 2, :bar => 10)

to become

my_method( :foo : 2, :bar : 10)

Oh, the new literal syntax is:

{ foo : 2, bar : 10 }

so that’d be my_method( foo : 2, bar : 10 )

But it’s supposed to be an addition, not a replacement for the { :foo
=> 2 } syntax.

Thanks guys!

I’ve got it sorted now, using a hash.

So for my Rdoc, I take it I would want to have:

Writes embedded images to a file

:call-seq:

write_picture() -> nil

write_picture(:outfile=>“str”) -> nil

write_picture(:n=int) -> nil

write_picture(:outfile=“str”, :n=int) -> nil

Is this right?

Thanks again,
-d

Sigh, I mean:

Writes embedded images to a file

:call-seq:

write_picture() -> nil

write_picture(:outfile=>“str”) -> nil

write_picture(:n=>int) -> nil

write_picture(:outfile=>“str”, :n=>int) -> nil

-d

On 6/23/07, Trans [email protected] wrote:

write_picture(:n=>int) -> nil

...

end

write_picture(“front cover”, 1)
write_picture(1, “front cover”)

Sacrifice a little duck-typiness for some arg-flippiness :slight_smile:

Yuck.

On 6/23/07, Gregory B. [email protected] wrote:

Oh, the new literal syntax is:

{ foo : 2, bar : 10 }

so that’d be my_method( foo : 2, bar : 10 )

But it’s supposed to be an addition, not a replacement for the { :foo
=> 2 } syntax.

Yep, a little more syntactic sugar, or maybe saccharine, since it
slims down the expression a bit..


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

On Jun 23, 9:21 pm, “Gregory B.” [email protected] wrote:

But hey, as Resident Dreamer, I can’t help but wonder how cool it

Yuck.

Is the “formalist” in you disturbed by this?

I think too many programmers feel that way too. See, I wonder when we
ever are going to get past conforming to the requirements of our
computer systems, and start having them conform to ours.

T.

On Jun 23, 6:09 pm, darren kirby [email protected] wrote:

-d
Bingo.

But hey, as Resident Dreamer, I can’t help but wonder how cool it
might be to have highly descriptive and auto-flexible arguments:

def write_picture(n <= Integer, outfile <= String)

end

write_picture(“front cover”, 1)
write_picture(1, “front cover”)

Sacrifice a little duck-typiness for some arg-flippiness :slight_smile:

T.

On 6/26/07, Trans [email protected] wrote:

Sacrifice a little duck-typiness for some arg-flippiness :slight_smile:

Yuck.

Is the “formalist” in you disturbed by this?

I think too many programmers feel that way too. See, I wonder when we
ever are going to get past conforming to the requirements of our
computer systems, and start having them conform to ours.

No. What disturbs me about it is that it doesn’t fit well with Ruby
best practices. Though it might be useful for some cases, it is
likely to be abused, and annoying to deal with.

There are languages that I think benefit from static typing, Ruby to
me just isn’t one of them.

Besides, the utility of what you suggested, being able to flip
arguments, is kind of weak, considering all the limitations it
imposes. I’d need to see a more compelling case for optional static
typing in Ruby before I could support it in any way.

Yuck.

Is the “formalist” in you disturbed by this?

I think too many programmers feel that way too. See, I wonder when we
ever are going to get past conforming to the requirements of our
computer systems, and start having them conform to ours.

Not so fast Tom, not my generation, we have come from Assembler or
Fortran, we have been marveled by Ada (or Smalltalk, at least some
lucky guys I will not name)
than astonished by the powers of Perl and Python before falling in
love with Ruby.
*Our minds have happily adapted to the lesser formal needs as we have
gone along!
It is for the next generation to have that, – your’s probably :slight_smile:

You are completely right of course but it depends on the users of
these systems too and that slows that process down a little bit, sigh.

Robert

Hi –

On Wed, 27 Jun 2007, Trans wrote:

Sigh, I mean:

write_picture(1, “front cover”)

Sacrifice a little duck-typiness for some arg-flippiness :slight_smile:

Yuck.

Is the “formalist” in you disturbed by this?

I think too many programmers feel that way too. See, I wonder when we
ever are going to get past conforming to the requirements of our
computer systems, and start having them conform to ours.

Nothing that abstract or sweeping is at stake. (I don’t think
Rubyists who dislike the thought of automatic class-checking are,
overall, more subservient to their computers than those who don’t :slight_smile:
It’s just that constraining Ruby method arguments to be of certain
classes is both unnecessarily limiting and not as much of a guarantor
of behavior as people sometimes think (since the objects don’t “know”
that they’re supposed to ignore the side of themselves that allows for
dynamic typing). In the case of checking class membership in order to
allow arbitrary argument order, you’d also run aground on the fact
that a method might take more than one string, or whatever.

David

On Jun 26, 6:22 pm, [email protected] wrote:

Nothing that abstract or sweeping is at stake. (I don’t think
Rubyists who dislike the thought of automatic class-checking are,
overall, more subservient to their computers than those who don’t :slight_smile:
It’s just that constraining Ruby method arguments to be of certain
classes is both unnecessarily limiting and not as much of a guarantor
of behavior as people sometimes think (since the objects don’t “know”
that they’re supposed to ignore the side of themselves that allows for
dynamic typing). In the case of checking class membership in order to
allow arbitrary argument order, you’d also run aground on the fact
that a method might take more than one string, or whatever.

Is it limiting? Rubyists (myself included) love to wax grand about the
flexibility of Ruby’s type dynamics. But I have to be honest, over the
years it’s become clearer to me that reality is in fact more limiting.
Beyond symbol_or_string.to_s, and the like, how extensively do we ever
see duck-typing playing a roll in our code? On rare occasion perhaps,
but even then is it a serious feature? Or just a, “neato, look what we
can do” after-the-fact realization that never actually gets used? B/c
in reality, when we’re figuring a parameter that our method should
take, we’re not thinking about the methods it will respond_to. We’re
thinking about the type of thing it is.

Granted Class-base typing can be too constricting, just as respond_to
typing can be too granular. What would be optimal is something more
fluid, that can encompass them or any shade inbetween --a way to
specify what something represents, not just how it’s encoded. Take our
example above. We want two arguments, an Integer which represents an
index and a string which represents a file. Now there are a few
ways to represent a file actually, File.open(), Pathname.new(),
probably others. And yet, duck-typing isn’t going to do a bit of good
if one of those is passed in instead of the String representation.

I think Ruby is a great experiment in this area, and undoubtedly it
shows some promise. In particular, mixins have a significant impact
our ability to use duck-typing. They allow us to think in terms of
common functionality --all thing Enumerable, or all things Sortable,
etc. It would be interesting to see how much further this kind of
generalization could be taken. Are there potential mixins we are not
using?

Slightly aside, but I would also point out that a language which is
serious about duck-typing would do well to support complete method
probing. We should be able to pass “decoy” parameters to any method,
acting in DryRun fashion, and record all possible calls made on them.
I suspect such a tool would be invaluable in ascertaining the common,
essential methods we apply to different representations.

T.

On 6/27/07, Trans [email protected] wrote:

On Jun 26, 6:22 pm, [email protected] wrote:

Is it limiting? Rubyists (myself included) love to wax grand about the
flexibility of Ruby’s type dynamics. But I have to be honest, over the
years it’s become clearer to me that reality is in fact more limiting.
Beyond symbol_or_string.to_s, and the like, how extensively do we ever
see duck-typing playing a roll in our code?
I do not know Tom, one application springs into mind, I am generating
iptables commands from a DSL. The outpout is done via #<< to an object
(defaulting to $stdio) for testing I just set that object to an array.
On rare occasion perhaps,
but even then is it a serious feature?
A rare occasion, yes, but a very serious feature indeed.
example above. We want two arguments, an Integer which represents an
index and a string which represents a file. Now there are a few
ways to represent a file actually, File.open(), Pathname.new(),
probably others. And yet, duck-typing isn’t going to do a bit of good
if one of those is passed in instead of the String representation.

That, IMHO, is because your example is not about Duck Typing, as
Strings and Files do not quack and walk alike.

We could make them so of course, and I wonder why I have not done this
before, given that this is indeed a common pattern in my programs too:

class File
alias_method :open_as_file, :open
def to_file; self end
end

class String
def open_as_file *args, &blk
File.open(self, *args, &blk)
end
def to_file *args
File.new( self, *args)
end
end

Now you have Strings and Files that talk and walk alike.
I do not like the expression “Duck typing” too much (Rick’s dog
notwithstanding :wink: I feel more like “using protocols”.
Ruby gives you the power to implement those protocols but you have to
implement some of them yourself :wink:

I think Ruby is a great experiment in this area, and undoubtedly it
shows some promise.
Smalltalk? 35 years ago, I think Rick confirmed the now famous Alain
Kay quotation about Smalltalk beating Java, but being called Ruby.

I am however eager to learn subtle differences in the two “duck typing”
models.

In particular, mixins have a significant impact
our ability to use duck-typing. They allow us to think in terms of
common functionality --all thing Enumerable, or all things Sortable,
etc. It would be interesting to see how much further this kind of
generalization could be taken. Are there potential mixins we are not
using?

And eventually I agree with you :slight_smile:

Slightly aside, but I would also point out that a language which is
serious about duck-typing would do well to support complete method
probing. We should be able to pass “decoy” parameters to any method,
acting in DryRun fashion, and record all possible calls made on them.
I suspect such a tool would be invaluable in ascertaining the common,
essential methods we apply to different representations.

Hmm me bad, I do not understand this, could you mabye give an example
please?
Thx and cheers
Robert

On Jun 27, 1:45 am, “Robert D.” [email protected] wrote:

see duck-typing playing a roll in our code?

I do not know Tom, one application springs into mind, I am generating
iptables commands from a DSL. The outpout is done via #<< to an object
(defaulting to $stdio) for testing I just set that object to an array.

A rare occasion, yes, but a very serious feature indeed.

That’s a pretty good example. It’s easy to effect because it’s based
on the single method #<<. And I’ve used it too.

example above. We want two arguments, an Integer which represents an
index and a string which represents a file. Now there are a few
ways to represent a file actually, File.open(), Pathname.new(),
probably others. And yet, duck-typing isn’t going to do a bit of good
if one of those is passed in instead of the String representation.

That, IMHO, is because your example is not about Duck Typing, as
Strings and Files do not quack and walk alike.

Well, that’s kind of my point. We use a string to represent a file,
even though it’s not a file. Our representation don’t necessarily
correspond to actual types.

  File.open(self, *args, &blk)

end
def to_file *args
File.new( self, *args)
end
end

Nice. You were able to put duck-typing to better work for us. But I
want to emphasis my point here. You were able to do this by thinking
in terms of types. When accepting parameters, you still think “a
File-like thing”. With you’re code it can now be a String or a File.
It’s not really limiting to specify types in method interfaces. We are
rather limited by not having good means to properly specify those
types. So understandably we opt not to specify them at all. It’s
always possible to have an object pretend to be something else:

class Chameleon
def self.===(other)
true
end
end

I am however eager to learn subtle differences in the two “duck typing” models.

Ah, right you are. And I’d like to know too. Have Ruby advanced “duck
typing” or has just given us a lite version?

In particular, mixins have a significant impact
our ability to use duck-typing. They allow us to think in terms of
common functionality --all thing Enumerable, or all things Sortable,
etc. It would be interesting to see how much further this kind of
generalization could be taken. Are there potential mixins we are not
using?

And eventually I agree with you :slight_smile:

:slight_smile: I’m not really arguing against duck-typing. I just don’t think it’s
necessarily in opposition to specifying optional parameter types. If
the the whole duck-typing idea was more deeply pursued we might even
find it quite intuitve to do so, using Mixins:

def foo(a < Enumerable)

Slightly aside, but I would also point out that a language which is
serious about duck-typing would do well to support complete method
probing. We should be able to pass “decoy” parameters to any method,
acting in DryRun fashion, and record all possible calls made on them.
I suspect such a tool would be invaluable in ascertaining the common,
essential methods we apply to different representations.

Hmm me bad, I do not understand this, could you mabye give an example please?

A method probe is something like this:

class Decoy
private *instance_methods
attr_accessor :_record
def initialize()
@_record = []
end
def method_missing(sym, args, blk)
@_record << [sym, args, blk]
end
end

Now I can take any method I want which takes a parameter and drop the
decoy in:

def foo(x)
x.to_s
end

d = Decoy.new
foo(d)
d._record #=> [[:to_s, nil, nil]]

In this way we can see what kind of “duck” a parameter requires.

This isn’t perfect however because of possible side-effects and
conditionals, which can skew the results. We would require a dry-run
mode and some dynamic means of dealing with condition statements (eg.
a decoy would split down both paths of any condition). It’s not an
easy problem, but I don’t think it is impossible either --at least not
impractically so.

T.

On 6/27/07, Trans [email protected] wrote:

Beyond symbol_or_string.to_s, and the like, how extensively do we ever
see duck-typing playing a roll in our code?

I do not know Tom, one application springs into mind, I am generating
iptables commands from a DSL. The outpout is done via #<< to an object
(defaulting to $stdio) for testing I just set that object to an array.

A rare occasion, yes, but a very serious feature indeed.

That’s a pretty good example. It’s easy to effect because it’s based
on the single method #<<. And I’ve used it too.

Note the subtle shift here, the TYPE consists of a set of expected
behavior, in this case the single method #<<. This set of behavior is
like a job requirement. This type arises out of the USE of the object
by somone, not the implementation of the object. This is the
‘role-based’ typing I wrote about years ago in
http://talklikeaduck.denhaven2.com/files/TypesFromTheClientsViewpoint.PDF

One way of thinking about this is that there’s no need to constrain
how we think about ‘type’ to the class implementation hierarchy.
Constraining subclasses to be subtypes which struggle to meet the
Liskov Substitution Property might be the only way of thinking about
things in C++/Java, but it’s overly constraining, and even in those
other languages, it turns out to be a weak version of reality, there
are counterexamples of LSP even in Java and C++.

http://talklikeaduck.denhaven2.com/articles/2006/08/10/ducks-can-be-subtle-birds

or see:
http://c2.com/cgi/wiki?LiskovSubstitutionPrinciple

If you’re up for a rather long discussion about what LSP does/doesn’t
should/shouldn’t mean. And what a subtype is/isn’t.

Look at Alistair Cockburn’s analysis in the c2 page of whether or not
Square is a subtype of Rectangle (or the other way around).

Granted Class-base typing can be too constricting, just as respond_to
typing can be too granular. What would be optimal is something more
fluid, that can encompass them or any shade inbetween --a way to
specify what something represents, not just how it’s encoded.

Ummm, how about rdoc commentary.

Seriously, it seems to me that the best that even a strongly typed
languages can do isn’t much beyond syntactic type matching. There’s
more to avoiding errors than just having matching signatures between
caller and callee. A lot of the discussion on the c2.com (Ward’s
wiki) site is about how LSP falls down when the behavior changes even
though the signature doesn’t.

Sometimes the right approach is that of a surgeon, assisted by a
pathologist.
http://talklikeaduck.denhaven2.com/articles/2006/07/26/my-favorite-duck-typing-story

I’m talking about the close coupling (temporal and otherwise) between
codeing and testing which is found in all of the agile methods.
In other words don’t overthink things, take a shot based on general
knowledge and be prepared to deal with the consequences.

Take our

example above. We want two arguments, an Integer which represents an
index and a string which represents a file. Now there are a few
ways to represent a file actually, File.open(), Pathname.new(),
probably others. And yet, duck-typing isn’t going to do a bit of good
if one of those is passed in instead of the String representation.

No fair, you’re getting back to the OPs example

Seriously, I think that discriminating actual positional arguments
based on type discrimination is a separate issue, and I’m not sure
that it’s that useful.

Positional parameters make a lousy technique for expressing variability.

class File
end
end

Nice. You were able to put duck-typing to better work for us. But I
want to emphasis my point here. You were able to do this by thinking
in terms of types. When accepting parameters, you still think “a
File-like thing”. With you’re code it can now be a String or a File.

I’d argue that it’s not really a file-like thing, it’s an object which
represents a sequence and which has a method << which adds an object
to the end of the sequence.

It’s not really limiting to specify types in method interfaces. We are
rather limited by not having good means to properly specify those
types.

Once again, I’d suggest rdoc commentary, and test cases, rather than
trying to come up with a means of ‘properly’ specifying such types.
Particularly if ‘properly’ means something which would produce a
compiler warning, which in the case of Ruby would appear only
milliseconds before the exception which would be thrown if the type
specification error wasn’t a false negative and the compiler didn’t
check.

notwithstanding :wink: I feel more like “using protocols”.
Ruby gives you the power to implement those protocols but you have to
implement some of them yourself :wink:

To be honest I’m not really that fond of the expression either, for
one thing I get the impression that it makes people think too much
about everything being a duck, instead of geese, hammers, etc.

I think Ruby is a great experiment in this area, and undoubtedly it
shows some promise.

Smalltalk? 35 years ago, I think Rick confirmed the now famous Alain
Kay quotation about Smalltalk beating Java, but being called Ruby.

Actually that was Kent Beck not Alan.

using?
I’d say that mixins have a significant impact on being able to combine
implementation while breaking out of the tyranny of a hierarchy.

Mixins do tend to help cluster protocols, but they don’t REALLY
provide anything more in the way of typing.

Consider some of the recent discussions about Array vs. Hash and the
reject/select methods. Just because two classes include Enumerable
doesn’t make their instances substitutable for each other in all
contexts.

:slight_smile: I’m not really arguing against duck-typing. I just don’t think it’s
necessarily in opposition to specifying optional parameter types. If
the the whole duck-typing idea was more deeply pursued we might even
find it quite intuitve to do so, using Mixins:

def foo(a < Enumerable)

But see the warning above.

In this way we can see what kind of “duck” a parameter requires.

This isn’t perfect however because of possible side-effects and
conditionals, which can skew the results. We would require a dry-run
mode and some dynamic means of dealing with condition statements (eg.
a decoy would split down both paths of any condition). It’s not an
easy problem, but I don’t think it is impossible either --at least not
impractically so.

Well if you think so , go ahead and pursue it. I think that it’s
a pretty big achilles heel.

I’m not sure how this would be used other than as part of a
development tool, you wouldn’t want to do this at runtime would you?

Why not just use the regular test tools with the real objects. This
seems to me like an actor sending a cardboard cutout of himself to an
audition instead of going himself.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

Smalltalk? 35 years ago, I think Rick confirmed the now famous Alain
Kay quotation about Smalltalk beating Java, but being called Ruby.

Actually that was Kent Beck not Alan.

That one hurts all my apologies. c.f. my new signature BLUSH

:slight_smile: I’m not really arguing against duck-typing. I just don’t think it’s
necessarily in opposition to specifying optional parameter types. If
the the whole duck-typing idea was more deeply pursued we might even
find it quite intuitve to do so, using Mixins:

def foo(a < Enumerable)

But see the warning above.
I feel I want to think about this notation - or rather the idea behind
it - a little bit more.
My rationale for such a device – and at first sight it seems a good
device to me – would be something like this:

ok we will work on an object a and we know of course that we will use
a certain interface with a. Please note that I will remain 100% in a
Duck Type/Protocol context.
So please Tom if I am wrong with your basic idea just hit me, but I
will take the risk this is too interesting :).
Let us assume that we will call #abra and #kadabra – I am staying
away from real use cases.
In an ideal world I just do not care because of course nobody will
ever pass an object not responding (1) to these messages.
The ideal world has yet to be invented though :(. Therefore sometimes
we will have some NoMethodError exceptions and that is how it is.
Sometimes – also not true in an ideal world – someone will try to
figure out what foo does with a, and she will read the code and
eventually find out - or not;).

That was the scenario def foo a, now we will create a new
scenario

module AbraKadabra
def abra…
def kadabra
end

def foo a < AbraKadabra

now we will fail earlier and with a meaningful error message…

I know we have had this discussion and while I am writing this I feel
that there is something wrong with my picture, the creation of a
module for the purpose feels so wrong, let us have another try
## utopic code :wink:
protocol AbraKadabra
methods :abra, :kadabra ## no way to say something about arity!
end
def foo a < AbraKadabra

I know we have doc’s and tests but we have to write them ourselves,
maybe the Ruby Interpreter should just ignore protocols and they could
be used for rdoc and automatic test generation only!!!

A method probe is something like this:
end
d._record #=> [[:to_s, nil, nil]]

In this way we can see what kind of “duck” a parameter requires.

This isn’t perfect however because of possible side-effects and
conditionals, which can skew the results. We would require a dry-run
mode and some dynamic means of dealing with condition statements (eg.
a decoy would split down both paths of any condition). It’s not an
easy problem, but I don’t think it is impossible either --at least not
impractically so.
I start grasping the concept, thx a lot.

Robert

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs