This question already has answers here:
When to use lambda, when to use Proc.new?
(14 answers)
Closed 8 years ago.
I am new to ruby, and while learning it I didn't understand the concept of lambdas or procs. I know lambda and proc are the blocks of code that have been bound to a set of local variables. But I don't understand their use.
So
what advantage does a programmer get from it?
I had asked this question in past and got marked as duplicate and was given a link that had totally unrelated answered so please before marking it as duplicate or scolding me please view the answers of other links by yourself first.
This is a broad question. You're basically asking "why are closures important?". Two uses that come to mind for me are:
DISCLAIMER: I haven't actually run any of this code, but it should get the point across.
Delayed execution of code. If I want to pass some code as a callback (e.g. Rails' after_create), I can use a closure to "hook" into Rails by passing a block. That block has the context of the current class, but it doesn't need to get run until Rails says so.
class SuperClass
def self.after_create(&block)
#__after_create = block
end
def self.create
# do normal create logic
instance = self.new
if #__after_create
#__after_create.call(instance)
end
end
end
class MyClass < SuperClass
after_create {|instance| instance.log}
def log
puts 'hello world!'
end
end
MyClass.create
Passing functions as parameters. This makes it easier to do things like write a generic tree traversal algorithm that just passes each node of the tree to some function:
def Tree.elements
["hello", "world!"]
end
def Tree.traverse(&block)
elements.each {|el| block.call(el)}
end
Tree.traverse {|el| puts el} # "hello" "world!"
Tree.traverse {|el| puts el.size} # "5" "6"
Related
This question already has answers here:
Is Ruby pass by reference or by value?
(14 answers)
Closed 9 years ago.
I'm not sure what happens when you pass an object to a module method. Does the object gets passed by reference or by copy? Like in this example:
module SampleModule
def self.testing(o)
o.test
end
end
class SampleClass
def initialize(a)
#a = a
end
def test
#a = #a + 1
end
end
sample_object = SampleClass.new(2)
3.times do
SampleModule.testing(sample_object)
end
p sample_object # => #<SampleClass:somehexvalue #a=5>
seems to be pass-by reference. Really unclear about this.
All variables in Ruby are references to objects. You cannot "pass by value" versus "pass by reference" in the same way as you have that choice in C, C++ or Perl. Ruby in fact forces pass by value, there are no options to do otherwise. However, the values that are sent are always references to objects. It's a bit like using C or C++ where all member variables are pointers, or using Perl where you must work with references at all times, even when working with simple scalars.
I think that it is this separation of variable from object data that is confusing you.
A few points:
Variable allocation never over-writes other variables that may point to the same object. This is pretty much the definition of pass-by-value. However this isn't meeting your expectations that object contents are also protected.
Instance variables, and items in containers (e.g. in Arrays and Strings) are separate variables, and if you send a container you can alter its content directly, because you sent the reference to the container, and that includes the same variables for its contents. I think this is what you mean by "seems to be pass-by reference"
Some classes - including those representing numbers, and Symbol - are immutable i.e. there are no change-in-place methods for the number 4. But conceptually you are still passing a reference to the singular object 4 into a routine (under the hood, for efficiency Ruby will have the value 4 encoded simply in the variable's memory allocation, but that is an implementation detail - the value is also the "pointer" in this case).
The simplest way to get close to the "pass by value" semantics you seem to be looking for with SampleModule is to clone the parameters at the start of the routine. Note this does not actually cause Ruby to change calling semantics, just that in this case from the outside of the method you get the safe assumption (whatever happens to the param inside the method stays inside the method) that you seem to want:
module SampleModule
def self.testing(o)
o = o.clone
o.test
end
end
Technically this should be a deep clone to be generic, but that wouldn't be required to make your example work close to a pass-by-value. You could call SampleModule.testing( any_var_or_expression ) and know that whatever any_var_or_expression is in the rest of your code, the associated object will not have been changed.
If you really want to be anal on vocabulary, Ruby passes references to (mutable) objects by value:
def pass_it(obj)
obj = 'by reference'
end
def mutate_it(obj)
obj << ' mutated'
end
str = 'by value'
pass_it(str)
mutate_it(str)
puts str # by value mutated
You can work around issues that may arise from this by using dup or clone (note that both do shallow copies) and freeze.
Everything in Ruby is passed by reference:
class Test
attr_reader :a
def initialize(a)
#a = a
end
end
s = "foo"
o = Test.new(s)
o.a << "bar"
o.a #=> "foobar"
s #=> "foobar"
o.a.equal? s #=> true
In your code, the fact that you are passing an object to a module method doesn't change anything; sample_object is already a reference to the new object SampleClass.new(2)
Sorry for the vague question title, but I have no clue what causes the following:
module Capistrano
class Configuration
def puts string
::Kernel.puts 'test'
end
end
end
Now when Capistrano calls puts, I don't see "test", but I see the original output.
However, when I also add this:
module Kernel
def puts string
::Kernel.puts 'what gives?'
end
end
Now, suddenly, puts actually returns "test", not "what gives?", not the original content, but "test".
Is there a reasonable explanation why this is happening (besides my limited understanding of the inner-workings of Ruby Kernel)?
Things that look off to me (but somehow "seem to work"):
I would expect the first block to return 'test', but it didn't
I would expect the combination of the two blocks to return 'what gives?', but it returns 'test'?
The way I override the Kernel.puts seems like a never-ending loop to me?
module Capistrano
class Configuration
def puts string
::Kernel.puts 'test'
end
def an_thing
puts "foo"
end
end
end
Capistrano::Configuration.new.an_thing
gives the output:
test
The second version also gives the same output. The reason is that you're defining an instance level method rather than a class level method (this post seems to do a good job explaining the differences). A slightly different version:
module Kernel
def self.puts string
::Kernel.puts 'what gives?'
end
end
does the following. Because it is causing infinite recursion, like you expected.
/tmp/foo.rb:14:in `puts': stack level too deep (SystemStackError)
from /tmp/foo.rb:14:in `puts'
from /tmp/foo.rb:4:in `puts'
from /tmp/foo.rb:7:in `an_thing'
from /tmp/foo.rb:18
shell returned 1
I use an answer rather than a comment because of its editing capabilities. You can edit it to add more information and I may delete it later.
Now when Capistrano calls puts, I don't see "test", but I see the
original output.
It's difficult to answer your question without seeing how Capistrano calls puts and which one. I would say it's normal if puts displays its parameter, using the original Kernel#puts (it is not clear what you call original output, I must suppose you mean the string given to puts).
I would expect the first block to return 'test', but it didn't
The only way I see to call the instance method puts defined in the class Configuration in the module Capistrano is :
Capistrano::Configuration.new.puts 'xxx'
or
my_inst_var = Capistrano::Configuration.new
and somewhere else
my_inst_var.puts 'xxx'
and of course it prints test. Again, without seeing the puts statement whose result surprises you, it's impossible to tell what's going on.
I would expect the combination of the two blocks to return 'what gives?', but it returns 'test'?
The second point is mysterious and I need to see the code calling puts, as well as the console output.
I'm writing a simple dsl in ruby. Few weeks ago I stumbled upon some blog post, which show how to transform code like:
some_method argument do |book|
book.some_method_on_book
book.some_other_method_on_book :with => argument
end
into cleaner code:
some_method argument do
some_method_on_book
some_other_method_on_book :with => argument
end
I can't remember how to do this and I'm not sure about downsides but cleaner syntax is tempting. Does anyone have a clue about this transformation?
def some_method argument, &blk
#...
book.instance_eval &blk
#...
end
UPDATE: However, that omits book but don't let you use the argument. To use it transparently you must transport it someway. I suggest to do it on book itself:
class Book
attr_accessor :argument
end
def some_method argument, &blk
#...
book.argument = argument
book.instance_eval &blk
#...
end
some_method 'argument' do
some_method_on_book
some_other_method_on_book argument
end
Take a look at this article http://www.dan-manges.com/blog/ruby-dsls-instance-eval-with-delegation — there is an overview of the method (specifically stated in the context of its downsides and possible solution to them), plus there're several useful links for further reading.
Basically, it's about using instance_eval to execute the block in the desirable context.
Speaking about downside of this technique:
So what's the problem with it? Well, the problem is that blocks are
generally closures. And you expect them to actually be full closures.
And it's not obvious from the point where you write the block that
that block might not be a full closure. That's what happens when you
use instance_eval: you reset the self of that block into something
else - this means that the block is still a closure over all local
variables outside the block, but NOT for method calls. I don't even
know if constant lookup is changed or not.
Using instance_eval changes the rules for the language in a way that
is not obvious when reading a block. You need to think an extra step
to figure out exactly why a method call that you can lexically see
around the block can actually not be called from inside of the block.
Check out the docile gem. It takes care of all the sharp edges, making this very easy for you.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Ruby functions vs methods
Im just reading some ruby documentation and t seems to use the term function and method in an interchangeable way, i jut wanted to know if there is any distinction?
the docs im looking at refer to this as a function:
def saysomething()
puts "Hello"
end
saysomething
and this a method:
def multiply(val1, val2 )
result = val1 * val2
puts result
end
this may be a something semantic but i wanted to check
jt
In Ruby, there are not two separate concepts of methods and functions. Some people still use both terms, but in my opinion, using "function" when talking about Ruby is incorrect. There do not exist executable pieces of code that are not defined on objects, because there is nothing in Ruby that is not an object.
As Dan pointed out, there's a way to call methods that makes them look like functions, but the underlying thing is still a method. You can actually see this for yourself in IRB with the method method.
> def zomg; puts "hi"; end
#=> nil
> method(:zomg)
#=> #<Method: Object#zomg>
> Object.private_instance_methods.sort
#=> [..., :zomg]
# the rest of the list omitted for brevity
So you can see, the method zomg is an instance method on Object, and is included in Object's list of private instance methods.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
What does map(&:name) mean in Ruby?
I was watching a railscast and saw this code.
[Category, Product].(&:delete_all)
In regards to clearing a database.
I asked about the line in IRC and was told
(&:delete_all)
was a shortcut for
{|model| model.delete_all}
I tested this with the following
class ClassOne
def class_method
puts 1
end
end
class ClassTwo
def class_method
puts 2
end
end
[ClassOne, ClassTwo].each(&:class_method)
I received an error saying
Wrong Argument type Symbol (expected Proc)
I also tried
one = ClassOne.new
two = ClassTwo.new
[one, two].each(&:class_method)
But that still failed.
If I modified it to read
[one, two].each{|model| model.class_method}
Everything worked as expected.
So, what does &:delete_all actually do? The docs say delete_all is a method, so I am confused as to what is going on here.
This relies upon a Ruby 1.9 extension that can be done in 1.8 by including the following:
class Symbol
def to_proc
proc { |obj, *args| obj.send(self, *args) }
end
end
I believe Rails defines this in ActiveSupport.
It's some Rails specific patching of Ruby, symbol to proc.