Difference between Kernel#yield_self, yield(self) and Object#tap in ruby

后端 未结 3 1979
轻奢々
轻奢々 2020-12-18 19:13

Ruby 2.5.0-rc1 has been released and introduces a new Kernel#yield_self method.

What is the difference between yield_self, yield(self

3条回答
  •  情深已故
    2020-12-18 19:35

    Great summary of this here: Ruby 2.5 added yield_self.

    Quick update: yield_self will have an alias then in new versions of Ruby, following requests from the community for this to be more readable.

    It's a very good, concise read, quoted below for posterity. All credit to the original author, Vijay Kumar Agrawal:

    Ruby 2.5 added a new method named yield_self. It yields the receiver to the given block and returns output of the last statement in the block.

    irb> "Hello".yield_self { |str| str + " World" }
      => "Hello World"
    

    How is it different from try in Rails ?

    Without a method argument try behaves similar to yield_self. It would yield to the given block unless the receiver is nil and returns the output of the last statement in the block.

    irb> "Hello".try { |str| str + " World" }
      => "Hello World"
    

    Couple of differences to note are, try is not part of Ruby but Rails. Also try’s main purpose is protection against nil hence it doesn’t execute the block if receiver is nil.

    irb> nil.yield_self { |obj| "Hello World" }
      => "Hello World"
    
    irb> nil.try { |obj| "Hello World" }
      => nil
    

    What about tap?

    tap also is similar to yield_self. It’s part of Ruby itself. The only difference is the value that is returned. tap returns the receiver itself while yield_self returns the output of the block.

    irb> "Hello".yield_self { |str| str + " World" }
      => "Hello World"
    
    irb> "Hello".tap { |str| str + " World" }
      => "Hello"
    

    Overall, yield_self improves readability of the code by promoting chaining over nested function calls. Here is an example of both the styles.

    irb> add_greeting = -> (str) { "HELLO " + str }
    irb> to_upper = -> (str) { str.upcase }
    
    # with new `yield_self`
    irb> "world".yield_self(&to_upper)
                .yield_self(&add_greeting)
      => "HELLO WORLD"
    
    # nested function calls
    irb> add_greeting.call(to_upper.call("world"))
      => "HELLO WORLD"
    

    yield_self is part of Kernel and hence it’s available to all the objects.

    Please don't accept this as the answer, as it's not my own handiwork (and I'm happy to delete if anyone has any objections) - but I found this a very good read and thought it might help others at some point.

提交回复
热议问题