From: Matthew Kerwin Date: 2013-02-07T12:20:02+09:00 Subject: Re: Implementing DRY with a function call --f46d042f9546345a8b04d519e01a Content-Type: text/plain; charset=ISO-8859-1 On 7 February 2013 10:39, Rob Marshall wrote: > Every other language I've worked in, C, Perl, Python, Java...the way you > call a function with arguments is: func(arg1, arg2, arg3). In Python you > can have variable args and keyword args specified as (*args, **kwargs), > but in general you define the arguments that a function expects, and > then pass those arguments between parentheses. Give or take a few other var-args tricks. Remember C has stdarg.h and allows function signatures like: void func(...); And Java has special array syntactic sugar: public static void func(Object... args) And PHP almost completely ignores the variables named in the function signature, because you can always use func_num_args() and func_get_args() etc. Ruby allows non-parenthetical args, the same as shell script (e.g. Bash). Technically perl doesn't require parentheses either, except that functions in perl expect a list of parameters, and perl lists use parentheses, etc. etc. Upshot: `$thingy->foo` is also a function call in perl. > So the idea that I could > do: > > func(arg1,arg2,arg3) { block } > > And a) Not get a syntax error, and b) Be able to define the parameters > for the function as: > > def func(*args) > yield > end > > and not only get the args specified between the parens in *args, but > also still pass the block and "yield" it, is a very new, and foreign, > concept for me. > If it helps, you can also define it as: def func(*args, &a_block) if you want to make explicit the fact that there is (or expects to be) a block. It also gives you direct access to the block, so you can poke it and stuff. > What I find a bit confusing about Ruby is that, given: > > def func(*args) > args.each { |a| puts a } > yield > end > > Then do the following: > > >> func "this", "is", "a", "test", return_value("something") > this > is > a > test > This is the returning value: something > LocalJumpError: no block given > from (irb):108:in `func' > from (irb):110 > > This one is sort-of obvious since the function return_value (which is > just a dummy function that simply shows calling a function with some > arbitrary value and returning it slightly modified...so don't get hung > up on it) is evaluated prior to being passed as an argument to func. But > since there's no block, I get the LocalJumpError. > To the first remark: this is the same as any other programming language. For example in Java: func("this", "is", "a", "test", return_value("something")); ...will execute the 'return_value' function first, then pass its result as the final parameter to 'func'. As an aside to the second: You can get around/preempt the LocalJumpError by wrapping `yield` thus: def func(*args) args.each { |a| puts a } yield if block_given? end Not necessarily what you want to do here, but handy to know. >> func "this", "is", "a", "test", { return_value("something") } > SyntaxError: compile error > (irb):111: odd number list for Hash > from (irb):111 > > This is is also somewhat obvious because it isn't treating the {} as > defining a block but attempting to define a hash...That's because I > haven't "formally" defined the arguments, so the interpreter assumes > everything is supposed to be an argument and not a block. > That would happen irrespective of how you define the function parameters. SyntaxErrors happen when ruby is parsing and interpreting the file, not when it's executing. A curly brace that follows a comma is _always_ interpreted as the start of a Hash literal. Since blocks are special, "out-of-band" parameters, you don't need a comma to distinguish them from the other args. However, since curly-brace block syntax looks a lot like Hash literal syntax, you need to give the parser a bit more help in this case (i.e. by explicitly wrapping the "real" args in parens, then giving the block.) > >> func("this", "is", "a", "test") { return_value("something") } > this > is > a > test > => "This is the returning value: something" > > This is still the odd one for me that now (sort-of) makes sense but > would NOT be allowed in any language I've used in the past. So it's > going to take some getting used to... This is true, but only because those other languages don't have blocks. Note that the following calls are equivalent: func("this", "is", "a", "test") { return_value("something") } func "this", "is", "a", "test" do return_value "something" end my_block = proc { return_value("something") } func "this", "is", "a", "test", &my_block my_block = proc { return_value("something") } func("this", "is", "a", "test", &my_block) The third and fourth versions are the call-site equivalent of the `def func(*args, &a_block)` definition I mentioned above. I hope this helps shed a little light on the issue, and gives you some pointers for further research. -- Matthew Kerwin, B.Sc (CompSci) (Hons) http://matthew.kerwin.net.au/ ABN: 59-013-727-651 "You'll never find a programming language that frees you from the burden of clarifying your ideas." - xkcd --f46d042f9546345a8b04d519e01a Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable
On 7 February 2013 10:39, Rob Marshall &= lt;lists@ruby-for= um.com> wrote:
Every other language I've worked in, C, Perl, Python, Java...the way yo= u
call a function with arguments is: func(arg1, arg2, arg3). In Python you can have variable args and keyword args specified as (*args, **kwargs),
but in general you define the arguments that a function expects, and
then pass those arguments between parentheses.

<= div style>Give or take a few other var-args tricks. =A0Remember C has stdar= g.h and allows function signatures like:

=A0 =A0 void func(...);

And Java has s= pecial array syntactic sugar:

=A0 =A0 public= static void func(Object... args)

And = PHP almost completely ignores the variables named in the function signature= , because you can always use func_num_args() and func_get_args()

etc.

Ruby al= lows non-parenthetical=A0args, the same as shell script (e.g. Bash). =A0Tec= hnically perl doesn't require parentheses either, except that functions= in perl expect a list of parameters, and perl lists use parentheses, etc. = etc. =A0Upshot: `$thingy->foo` is also a function call in perl.

=A0
So the idea that I could
do:

func(arg1,arg2,arg3) { block }

And a) Not get a syntax error, and b) Be able to define the parameters
for the function as:

def func(*args)
yield
end

and not only get the args specified between the parens in *args, but
also still pass the block and "yield" it, is a very new, and fore= ign,
concept for me.

If it helps, you = can also define it as:

=A0 =A0 def fun= c(*args, &a_block)

if you want to = make explicit the fact that there is (or expects to be) a block. =A0It also= gives you direct access to the block, so you can poke it and stuff.

=A0
What I find a bit confusing about Ruby is that, given:

def func(*args)
args.each { |a| puts a }
yield
end

Then do the following:

>> func "this", "is", "a", "test&q= uot;, return_value("something")
this
is
a
test
This is the returning value: something
LocalJumpError: no block given
=A0 =A0 =A0 =A0 from (irb):108:in `func'
=A0 =A0 =A0 =A0 from (irb):110

This one is sort-of obvious since the function return_value (which is
just a dummy function that simply shows calling a function with some
arbitrary value and returning it slightly modified...so don't get hung<= br> up on it) is evaluated prior to being passed as an argument to func. But since there's no block, I get the LocalJumpError.
=
To the first remark: =A0this is the same as any other = programming language. =A0For example in Java:

=A0 =A0 func("this", "is", "a", "test&qu= ot;, return_value("something"));

...will execute the 'return_value' function first, then pass i= ts result as the final parameter to 'func'.

As an aside to the second: You can get around/pre= empt the LocalJumpError by wrapping `yield` thus:

= =A0 =A0 def func(*args)
=A0 =A0 =A0 args.each { |a| puts a }
=A0 =A0 = =A0 yield if block_given?
=A0 =A0 end

Not necessarily what you wan= t to do here, but handy to know.


>> func "this", "is", "a", "test&q= uot;, { return_value("something") }
SyntaxError: compile error
(irb):111: odd number list for Hash
=A0 =A0 =A0 =A0 from (irb):111

This is is also somewhat obvious because it isn't treating the {} as defining a block but attempting to define a hash...That's because I
haven't "formally" defined the arguments, so the interpreter = assumes
everything is supposed to be an argument and not a block.
<= div>
That would happen irrespective of how you define t= he function parameters. SyntaxErrors happen when ruby is parsing and interp= reting the file, not when it's executing. =A0A curly brace that follows= a comma is _always_ interpreted as the start of a Hash literal.

Since blocks are special, "out-of-band= " parameters, you don't need a comma to distinguish them from the = other args. =A0However, since curly-brace block syntax looks a lot like Has= h literal syntax, you need to give the parser a bit more help in this case = (i.e. by explicitly wrapping the "real" args in parens, then givi= ng the block.)
=A0
>> func("this", "is", "a", "test&q= uot;) { return_value("something") }
this
is
a
test
=3D> "This is the returning value: something"= ;

This is still the odd one for me that now (sort-of) makes sense but would NOT be allowed in any language I've used in the past. So it's=
going to take some getting used to...

This is true, but only because those other languages don&= #39;t have blocks. =A0Note that the following calls are equivalent:
=A0 =A0 func("this", "i= s", "a", "test") { return_value("something&qu= ot;) }
=A0 =A0=A0
=A0 =A0 func "this", "is", "a", "= test" do
=A0 =A0 =A0 return_value "something&q= uot;
=A0 =A0 end
=A0 =A0=A0
=A0 =A0 my_block =3D proc { return_value("somethin= g") }
=A0 =A0 func "this", "is", "a", "test&qu= ot;, &my_block
=A0 =A0=A0
=A0 =A0 my_block =3D proc { return_value(&qu= ot;something") }
=A0 =A0 func("this", "is", "a", "te= st", &my_block)

T= he third and fourth versions are the call-site equivalent of the `def func(= *args, &a_block)` definition I mentioned above.

I hope this helps shed a little light on the issu= e, and gives you some pointers for further research.

--=
=A0 Matthew Kerwin, B.Sc (CompSci) (Hons)
=A0 http://matthew.kerwin.net.au/ =A0 ABN: 59-013-727-651

=A0 "You'll never find a programmin= g language that frees
=A0 you from the burden of clarifying your ideas.&= quot; - xkcd
--f46d042f9546345a8b04d519e01a--