On Thu, Feb 7, 2013 at 1:39 AM, Rob Marshall <[email protected]> wrote:
> Hi Robert,
>
> At present I'm using the approach I mentioned before, but let me try and
> explain my confusion...
OK, I'll try to clarify where I can.
> 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. 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.
Well, every language has its features which one needs to get used to.
:-) A block is special since Ruby will happily pass it to *every*
method called even though the method does not do anything with it.
And it does not need any declaration. Unless you want to store it
somewhere where the &argument_name syntax is needed (see my last
post). But even that does not affect errors you are seeing:
> 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 [...]
> is evaluated prior to being passed as an argument to func.
Exactly. Not a function is passed but the result of evaluating a
function. Nothing special here. That would be the same as in other
languages. And it doesn't really make a difference in what position
you have the method call. Same as in other languages. I think you're
making it more difficult for you to understand than necessary by
introducing #return_value here: this is just an expression as all the
literals you have in the invocation above.
> But since there's no block, I get the LocalJumpError.
Yes, that's caused by invoking yield in absence of a block passed.
Btw you can check that with #block_given?
irb(main):001:0> def f; block_given? end
=> nil
irb(main):002:0> f
=> false
irb(main):003:0> f {}
=> true
>>> 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.
No, this is wrong. That has absolutely nothing to do with how you
defined the method! This is a syntax error. And it has to do with
different precedence of {} and do end. You don't even have to define
the method for getting those errors - it's all about how the call is
written:
$ ruby -ce 'func "this", "is", "a", "test", { return_value("something") }'
-e:1: syntax error, unexpected '}', expecting tASSOC
$ ruby -ce 'func "this", "is", "a", "test" { return_value("something") }'
-e:1: syntax error, unexpected '{', expecting $end
func "this", "is", "a", "test" { return_value("something") }
^
$ ruby -ce 'func("this", "is", "a", "test") { return_value("something") }'
Syntax OK
$ ruby -ce 'func "this", "is", "a", "test" do return_value("something") end'
Syntax OK
For Ruby at the calling location all methods have the same signature
*at compile time*. Issues like wrong number of arguments etc. are
only detected at runtime!
$ ruby -ce 'def f(a) p a end; f(); f(1); f(1,2)'
Syntax OK
$ ruby -e 'def f(a) p a end; f(); f(1); f(1,2)'
-e:1:in `f': wrong number of arguments (0 for 1) (ArgumentError)
from -e:1:in `<main>'
$ ruby -e 'def f(a) p a end; f(1); f(1,2)'
1
-e:1:in `f': wrong number of arguments (2 for 1) (ArgumentError)
from -e:1:in `<main>'
So, to put it differently, for Ruby all methods have the same signature
f(*args, &block)
when it looks at them on calling sites at compile time.
>>> 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...
So far your issues have been only syntax errors and they are totally
unrelated to how you define the method. I think that's where you took
the wrong turn: Ruby is not checking whether argument lists are
properly passed or whether a method uses a block (all will _accept_ a
block!) at compile time. Only at runtime Ruby will notice
- wrong number of arguments
- using a block when none was passed
Kind regards
robert
--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
--
[email protected] |
https://groups.google.com/d/forum/ruby-talk-google?hl=en
---
You received this message because you are subscribed to the Google Groups
"ruby-talk-google" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.