Why use procs instead of methods?
Asked Answered
A

2

22

I'm new to programming, and ruby is my first real run at it. I get blocks, but procs seem like a light method/function concept -- why use them? Why not just use a method?

Thanks for your help.

Acetanilide answered 18/3, 2012 at 20:8 Comment(0)
F
12

Proc is a callable piece of code. You can store it in a variable, pass as an argument and otherwise treat it as a first-class value.

Why not just use a method?

Depends on what you mean by "method" here.

class Foo
  def bar
    puts "hello"
  end
end

f = Foo.new

In this code snippet usage of method bar is pretty limited. You can call it, and that's it. However, if you wanted to store a reference to it (to pass somewhere else and there call it), you can do this:

f = Foo.new
bar_method = f.method(:bar)

Here bar_method is very similar to lambda (which is similar to Proc). bar_method is a first-class citizen, f.bar is not.

For more information, read the article mentioned by @minitech.

Foothold answered 18/3, 2012 at 20:12 Comment(4)
That's not entirely accurate. 's'.method(:size) can be stored in a variable, passed as an argument, and otherwise treated as a first class value but it is a method while not being a Proc.Entoil
For me it is usually more about closures or needing a chunk of code that has no need for a self (or whose self wouldn't be the right thing). The whole Method/Proc/lambda/block thing in Ruby is a bit of a mess IMO. I'm having a hard time thinking of a good answer that wouldn't end up being an entire chapter of a book.Entoil
@muistooshort: you should write a book then and reference it :)Foothold
Thanks guys, this helps get me thinking in the right direction.Acetanilide
I
9

Dispatch table design pattern example


Why use procs instead of methods?

  • You might want to define one dynamically where the behavior varies according to parameters.
  • You might want to get a handle on a method so you can reference it as data.

A common design pattern involves choosing a method or code block to call based on a runtime value. For example...

case 1
  when 0
    p :a
  when 1
    p :b
  when 2
    p :c
end

This gets kind of clunky when there are many selectors and there is no way to put the dispatch mechanism together incrementally. So instead something like this can be done:

h = [ proc { p :a }, proc { p :b }, proc { p :c } ]

h[1].call

You can also use a Hash instead of an Array if your keys are not a sequence of small integers. Although the clunky case-selector design pattern occurs frequently in all languages, the dispatch-table-of-procs is rarely used. Usually, it's possible to store the results themselves in the Array or Hash and then just index them directly. But for something complicated, calling a proc allows the most flexibility.

As you proceed in Ruby you will find that this is the reason Ruby has blocks. Blocks are essentially methods that have been passed as a parameter to another method. This is so easy to do in Ruby and Smalltalk that it gets used all the time. You can do the same thing in C but it's too awkward to be any fun and so it is only seen in C when the code writer is losing a desperate battle with complexity.

Immorality answered 18/3, 2012 at 20:31 Comment(1)
I like this but I wouldn't use the position of an array's index for triggering each proc, as tracking that order would be hard to reason about in any sort of big sequence. I'd link each proc item to a hash key mapping the number.Waistline

© 2022 - 2024 — McMap. All rights reserved.