def foo(a)
# some computation
bar(a, b)
end
def bar(a,b)
# some computation
baz(a, b, c)
end
def baz(a, b ,c)
print a
end
How to avoid passing same parameter (a) to all methods? One way is to make parameter a as an instance variable. What is the right way to do this?
There is no single solution which works in every case, and often, passing the parameters explicitly is simply the best choice, especially when it comes to debugging.
You can use instance variables, but I would not introduce a new instance variable for the sole reason not to avoid passing it down the call chain. It should have its own value in addition.
One approach which I can see often in projects, is to us a single parameter hash, where the new parameters are added:
def foo(a)
....
bar({a:a, b:b})
end
def bar(par)
....
par[:c] = c
end
def baz(par)
par[:a]+par[:b]+par[:c]
end
This is not without drawbacks either. If you, for instance, forget to "add" a necessary parameter, this will either yield wrong results or throw an exception (depending on how to used them), while forgetting them explicitly via the parameter list, would be found at compile time already.
I would make the decisiion depending on the length of the parameter lists involved. If the number of parameters to a methods is larger than 5, I would start thinking, whether a different design might be more appropriate.
Answering the question stated: yes, ruby is a stateful OO language, having mutable everything. So in ruby one might introduce instance variables:
class MyClass
def foo(a)
#a = a
# some computation
bar(b)
end
def bar(b)
#b = b
# some computation
baz(c)
end
def baz(c)
print [#a, #b, c].inspect
end
end
In the real life, the best practice would be to avoid using instance variables wherever possible, and pass everything across methods. That might save you days of debugging in the future.
Related
This is somewhat of an esoteric situation that I am not even sure is possible. I have a method that is called by a lot of methods:
def called_by_a_lot_of_methods
# Work
end
I am introducing a feature in which the called_by_a_lot_of_methods will do stuff depends on the caller method, and my current solution is to change all these methods to pass their names when calling called_by_a_lot_of_methods:
def some_method
called_by_a_lot_of_methods(method_name: some_method)
end
Or, alternatively:
def some_method
called_by_a_lot_of_methods(method_name: __method__)
end
But this is becoming tedious, and I was wondering if I can give the method_name parameter a default value:
def called_by_a_lot_of_methods(method_name: __method__)
# Work
end
This does not work because __method__ evaluates immediately giving called_by_a_lot_of_methods, which is obviously not what I want. The question then is, is there a way in Ruby to defer the evaluation of the argument until a useful time when I know it should give the correct result, which is the outer caller method? Thus saving me from having to pass the argument everywhere?
I'm trying to understand when one should code blocks implicitly or explicitly. Given the following code blocks:
Implicit
def two_times_implicit
return "No block" unless block_given?
yield
yield
end
puts two_times_implicit { print "Hello "}
puts two_times_implicit
Explicit
def two_times_explicit (&i_am_a_block)
return "No block" if i_am_a_block.nil?
i_am_a_block.call
i_am_a_block.call
end
puts two_times_explicit { puts "Hello"}
puts two_times_explicit
Is it preferable to code using one over the other? Is there a standard practice and are there instances where one would work better or differently than the other and where one would not work at all?
Receiving a block via & creates a new proc object out of the block, so from the point of view of efficiency, it is better not to use it. However, using & generally makes it easier to define methods that may or may not take a block, and using &, you can also handle blocks together with arguments, so it is preferred by many.
Actually, according to one very interesting read, second variant is 439% slower (related thread on HackerNews).
TL;DR: Creating and passing a block via yield is a highly optimized common case in MRI, which is handled by dedicated C function in interpreter, while passing &block is implemented differently and has a big overhead of creating new environment and creating Proc itself on every call.
Summing up, use &block only if you need passing it further (for example, to a next function), or manipulate it somehow in other way. Otherwise, use yield, since it's way faster.
I was looking at some Ruby code somewhere, and I saw the following line:
def do_something a, b, c, &callback
xyz = a + b + c
callback.call(xyz)
end
and then when it was called, they did something like this:
do_something a, b, c do |xyz|
puts xyz
end
Is this better practice to use this sort of callback as opposed to just returning the value made by the function? I can understand why it would be done if there are multiple values that need to be transferred, but this one has just one return.
Analysis
There is insufficient information in your original post to determine if this is useful or not. The intent of your first example seems to be that the method will be passed a block, which is then called as a Proc inside the method rather than yielded back to the block. There might be a valid use case for this, but your given example isn't one of them.
If the block is already there, why not just yield to the block? And what happens if no block is given?
Passing Proc or lambda objects around can certainly be a useful technique in certain cases, but unless it simplifies your code or makes it more readable you are creating additional complexity. The examples in your original post don't make a valid case for why it might be needed. Even if you update your post with better examples, "Is a Proc object necessary?" is almost certainly a subjective question based on the needs of the larger program.
Unless you need the features of a Proc or lambda (e.g. you need a closure or access to a specific Binding) then you are generally better off yielding to a block or returning a value. Your mileage may certainly vary.
Yield or Return
In the general case, you can choose to yield to a block or return a value depending on whether or not a block was given. For example:
def do_something(a, b, c)
xyz = a + b + c
block_given? ? yield(xyz) : xyz
end
Unless you need to pass around a closure, this is likely to be a more useful technique. However, as previously stated, your mileage (and code base) may vary.
I would call this bad practice since this method requires a block (you'll get a NoMethodError without one). It can be useful to have a mechanism for immediately passing the return value to a block, but I wouldn't make it mandatory.
A simple improvement would be to make the block optional
def do_something a, b, c
xyz = a + b + c
return yield(xyz) if block_given?
xyz
end
I know splat arguments are used when we do not know the number of arguments that would be passed. I wanted to know whether I should use splat all the time. Are there any risks in using the splat argument whenever I pass on arguments?
The splat is great when the method you are writing has a genuine need to have an arbitrary number of arguments, for a method such as Hash#values_at.
In general though, if a method actually requires a fixed number of arguments it's a lot clearer to have named arguments than to pass arrays around and having to remember which position serves which purpose. For example:
def File.rename(old_name, new_name)
...
end
is clearer than:
def File.rename(*names)
...
end
You'd have to read the documentation to know whether the old name was first or second. Inside the method, File.rename would need to implement error handling around whether you had passed the correct number of arguments. So unless you need the splat, "normal" arguments are usually clearer.
Keyword arguments (new in ruby 2.0) can be even clearer at point of usage, although their use in the standard library is not yet widespread.
For a method that would take an arbitrary amount of parameters, options hash is a de facto solution:
def foo(options = {})
# One way to do default values
defaults = { bar: 'baz' }
options = defaults.merge(options)
# Another way
options[:bar] ||= 'baz'
bar = options[bar]
do_stuff_with(bar)
end
A good use of splat is when you're working with an array and want to use just the first argument of the array and do something else with the rest of the array. It's much quicker as well than other methods. Here's a smart guy Jesse Farmer's use of it https://gist.github.com/jfarmer/d0f37717f6e7f6cebf72 and here is an example of some other ways I tried solving the spiraling array problem and some benchmarks to go with it. https://gist.github.com/TalkativeTree/6724065
The problem with it is that it's not easily digestible. If you've seen and used it before, great, but it could slow down other people's understanding of what the code is doing. Even your own if you haven't looked at it in a while hah.
Splat lets the argument be interpreted as an array, and you would need an extra step to take it out. Without splat, you do not need special things to do to access the argument:
def foo x
#x = x
end
but if you put it in an array using splat, you need extra step to take it out of the array:
def foo *x
#x = x.first # or x.pop, x.shift, etc.
end
There is no reason to introduce an extra step unless necessary.
I would like to do some fairly heavy-duty reflection in Ruby. I want to create a function that returns the names of the arguments of various calling functions higher up the call stack (just one higher would be enough but why stop there?). I could use Kernel.caller, go to the file and parse the argument list but that would be ugly and unreliable.
The function that I would like would work in the following way:
module A
def method1( tuti, fruity)
foo
end
def method2(bim, bam, boom)
foo
end
def foo
print caller_args[1].join(",") #the "1" mean one step up the call stack
end
end
A.method1
#prints "tuti,fruity"
A.method2
#prints "bim, bam, boom"
I would not mind using ParseTree or some similar tool for this task but looking at Parsetree, it is not obvious how to use it for this purpose. Creating a C extension like this is another possibility but it would be nice if someone had already done it for me.
I can see that I'll probably need some kind of C extension. I suppose that means my question is what combination of C extension would work most easily. I don't think caller+ParseTree would be enough by themselves.
As far as why I would like to do this goes, rather than saying "automatic debugging", perhaps I should say that I would like to use this functionality to do automatic checking of the calling and return conditions of functions:
def add x, y
check_positive
return x + y
end
Where check_positive would throw an exception if x and y weren't positive. Obviously, there would be more to it than that but hopefully this gives enough motivation.
In Ruby 1.9.2, you can trivially get the parameter list of any Proc (and thus of course also of any Method or UnboundMethod) with Proc#parameters:
A.instance_method(:method1).parameters # => [[:req, :tuti], [:req, :fruity]]
The format is an array of pairs of symbols: type (required, optional, rest, block) and name.
For the format you want, try
A.instance_method(:method1).parameters.map(&:last).map(&:to_s)
# => ['tuti', 'fruity']
Of course, that still doesn't give you access to the caller, though.
I suggest you take a look at Merb's action-args library.
require 'rubygems'
require 'merb'
include GetArgs
def foo(bar, zed=42)
end
method(:foo).get_args # => [[[:bar], [:zed, 42]], [:zed]]
If you don't want to depend on Merb, you can choose and pick the best parts from the source code in github.
I have a method that is quite expensive and only almost works.
$shadow_stack = []
set_trace_func( lambda {
|event, file, line, id, binding, classname|
if event == "call"
$shadow_stack.push( eval("local_variables", binding) )
elsif event == "return"
$shadow_stack.pop
end
} )
def method1( tuti, fruity )
foo
end
def method2(bim, bam, boom)
foo
x = 10
y = 3
end
def foo
puts $shadow_stack[-2].join(", ")
end
method1(1,2)
method2(3,4,4)
Outputs
tuti, fruity
bim, bam, boom, x, y
I'm curious as to why you'd want such functionality in such a generalized manner.
I'm curious how you think this functionality would allow for automatic debugging? You'd still need to inject calls to your "foo" function. In fact, something based on set_trace_func is more able to be automatic, as you don't need to touch existing code. Indeed this is how debug.rb is implemented, in terms of set_trace_func.
The solutions to your precise question are indeed basically, as you outlined. use caller + parsetree, or open the file and grab the data that way. There is no reflection capability that I am aware of that will let you get the names of arguments. You can approve upon my solution by grabbing the associated method object and calling #arity to then infer what of local_variables are arguments, but though it appears the result of that function is ordered, I'm not sure it is safe to rely on that. If you don't mind me asking, once you have the data and the interface you describe, what are you going to do with it? Automatic debugging was not what initially came to mind when I imagined uses for this functionality, although perhaps it is failing of imagination on my part.
Aha!
I would approach this differently then. There are several ruby libraries for doing design by contract already, including ruby-contract, rdbc, etc.
Another option is to write something like:
def positive
lambda { |x| x >= 0 }
end
def any
lambda { |x| true }
end
class Module
def define_checked_method(name, *checkers, &body)
define_method(name) do |*args|
unless checkers.zip(args).all? { |check, arg| check[arg] }
raise "bad argument"
end
body.call(*args)
end
end
end
class A
define_checked_method(:add, positive, any) do |x, y|
x + y
end
end
a = A.new
p a.add(3, 2)
p a.add(3, -1)
p a.add(-4, 2)
Outputs
5
2
checked_rb.rb:13:in `add': bad argument (RuntimeError)
from checked_rb.rb:29
Of course this can be made much more sophisticated, and indeed that's some of what the libraries I mentioned provided, but perhaps this is a way to get you where you want to go without necessarily taking the path you planned to use to get there?
if you want the value for the default values, too, there's the "arguments" gem
$ gem install rdp-arguments
$ irb
>> require 'arguments'
>> require 'test.rb' # class A is defined here
>> Arguments.names(A, :go)
In fact, the method you describe clearly fails to distinguish arguments from local variables while also failing to work automatically
That's because what you're trying to do is not something which is supported. It's possible (everything is possible in ruby), but there's no documented or known way to do it.
Either you can eval the backtrace like what logan suggested, or you can bust out your C compiler and hack sourcecode for ruby. I'm reasonably confident there aren't any other ways to do this.