Procs/blocks - blocks with procs, blocks with blocks?

Well, maybe not blocks with blocks but blocks with yield? although
right now, I only have a fix for procs with blocks and not blocks with
blocks via blocks with yield when a proc block is not in stock...

class Proc
  alias __proc_block_call call
  alias __proc_block_indexer []
  
  def call(*args, &block)
    __proc_block_call(*(block.nil? ? args : args << block))
  end
  
  def [](*args, &block)
    __proc_block_indexer(*(block.nil? ? args : args << block))
  end
end

···

-----
usage

prc = Proc.new {|arg, proc_block|
  p arg
  proc_block[arg]
}

prc.call("Foo") {|*what|
  puts "Got #{what.length} whats -- #{what.inspect}"
}

produces:

"Foo"
Got 1 whats -- ["Foo"]

- also - it looks like the indexer function cannot take a block (parse
error) - why?

here is my latest `update' to the idea:

--- code ---
class Proc
  alias __proc_block_call call
  alias __proc_block_indexer []

  @@blocks = []
  
  def Proc.yield(*args)
    fail "No current proc context" if @@blocks.empty?
    raise LocalJumpError, "no block given" if @@blocks[-1].nil?
    # Maybe just @block.call? - This allows for recursion, though
    @@blocks[-1].__proc_block_call(*args)
  end

  def Proc.block_given?(*args)
    fail "No current proc context" if @@blocks.empty?
    !@@blocks[-1].nil?
  end

  def yield(*args)
    Proc.yield(*args)
  end

  def block_given?
    Proc.block_given?
  end

  def call(*args, &block)
    @@blocks.push block
    r = __proc_block_call(*args)
    @@blocks.pop
    r
  end

  def [](*args, &block)
    @@blocks.push block
    r = __proc_block_indexer(*args)
    @@blocks.pop
    r
  end
end

module Kernel
  def pyield(*args)
    Proc.yield(*args)
  end

  def pblock_given?
    Proc.block_given?
  end
end
--- code ---

I still don't know why I can't use a block with the normal use of
[]... is that going to ever change?

I know I can do obj.send(:[], *args) or obj.[](*args) -- but I think
we all know using obj[*args] is best! :slight_smile:

~Me!

···

--
There's no word in the English language for what you do to a dead
thing to make it stop chasing you.

Matt Maycock <ummaycoc@gmail.com> writes:

[snip code]

If I understand what you're trying to do, the latest (CVS) ruby allows
blocks to take blocks.

irb(main):001:0> lammy = lambda{|&b| b.call}
=> #<Proc:0x402145f8@(irb):1>
irb(main):002:0> lammy.call{10}
=> 10
irb(main):003:0>

I still don't know why I can't use a block with the normal use of
... is that going to ever change?

I know I can do obj.send(:, *args) or obj.(*args) -- but I think
we all know using obj[*args] is best! :slight_smile:

I don't know if it will change or not. I'm somewhat impartial to it,
though. I always thought the rationale for Proc# was not for saving
keystrokes, nor for kludging a #() operator, but rather to allow a
compact representation of a procedurally generated collection. E.g.,
instead of explicitly using an array of the numbers [0, 2, 4, ...,
something_big], you can just use lambda{|x| 2*x}. These sorts of uses
generally have no business taking blocks.

I could of course be wrong, though.

If I understand what you're trying to do, the latest (CVS) ruby allows
blocks to take blocks.

irb(main):001:0> lammy = lambda{|&b| b.call}
=> #<Proc:0x402145f8@(irb):1>
irb(main):002:0> lammy.call{10}
=> 10
irb(main):003:0>

Neato!

I don't know if it will change or not. I'm somewhat impartial to it,
though. I always thought the rationale for Proc# was not for saving
keystrokes, nor for kludging a #() operator, but rather to allow a
compact representation of a procedurally generated collection. E.g.,
instead of explicitly using an array of the numbers [0, 2, 4, ...,
something_big], you can just use lambda{|x| 2*x}. These sorts of uses
generally have no business taking blocks.

I could of course be wrong, though.

I could imagine some uses for it taking a block... like the block
being a test for whether to use the current attempted return value, or
try to generate another...