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.
···
On 7 February 2013 10:39, Rob Marshall <lists@ruby-forum.com> wrote:
--
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