When are blocks more useful than functions (ruby)?

I have two examples that give the same result.

With block:

def self.do_something(object_id) self.with_params(object_id) do |params| some_stuff(params) end end def self.with_params(object_id, &block) find_object_by_id calculate_params_hash block.call(params_hash) end 

and using the method:

 def self.do_something(object_id) some_stuff(self.get_params(object_id)) end def self.get_params(object_id) find_object_by_id calculate_params_hash params_hash end 

The second solution seems simpler, but I found some ways to use the first application in our code. My question is: in what situation is the first recommended? What are the pros and cons of each?

+6
source share
4 answers

The main difference between a block and a function according to your example is that the block works in the context of the calling function.

So, if your example was like this:

 def self.do_something(object_id) x = "boogy on" self.with_params(object_id) do |params| some_stuff(params) puts x end end 

The code inside the block can refer to the variable x, which was defined outside the block. This is called a closure. You could not do this if you just called the function in accordance with your second example.

Another interesting thing about blocks is that they can influence the control flow of an external function. So you can do:

 def self.do_something(object_id) self.with_params(object_id) do |params| if some_stuff(params) return end end # This wont get printed if some_stuff returns true. puts "porkleworkle" end 

If calling some_stuff inside a block returns a true value, the block will return. This will be returned from the block and from the dosomething method. porkleworkle won't get a way out.

In your examples, you do not rely on any of them, so using function calls is probably much cleaner.

However, there are many situations where using blocks to allow you to take advantage of these things is invaluable.

+2
source

Usually people use blocks when they want to run a piece of code inside another piece of code. Examples:

 DB.with_shard_for_user(user_id) do |db| # perform operations on a user shard end # shard is reverted back to original value File.new(filename) do |file| # work with file end # file is closed automatically User.transaction do # run some operations as a single transaction end 

These blocks are closed in their lexical context (they capture the variables from which the block is declared, and transfer them to the place when the blocks are called).

Schematic structure of a method that takes a block.

 def transaction open_transaction # pre- part yield if block_given? # run provided code commit_transaction # post- part rescue rollback_transaction # handle problems end 

In your first example, using a block is probably unjustified (IMHO). Too complicated for no apparent reason.

+3
source

When you call with_params (), you not only send data, but also provide some code to run. See if different blocks are sent to the with_params () call:

 ... self.with_params(object_id) do |params| some_other_stuff() some_stuff(params) end ... 

and somewhere else:

 ... self.with_params(object_id) do |params| even_more_stuff(params) end ... 

If the blocks are all the same or with __params () just called from one place, you might consider excluding blocks.

To summarize: use blocks if you want to pass different bits of code (blocks) to the method, as well as data: hey with_params, take this data (object_id) and, by the way, run this code (block) while you are on it.

By the way, you do different things in two examples: with_params () returns

 some_stuff(params_hash) 

after evaluating the block. And get_params () just returns

 params_hash 
+1
source

The block relies entirely on your code, but the function has its own code.

So, if your code changes the situation, use a block. If not, create a function and use it as a block.

+1
source

Source: https://habr.com/ru/post/910789/


All Articles