Project

General

Profile

Actions

Feature #17721

closed

Proc.new should be able to contruct a lambda

Added by bughit (bug hit) over 1 year ago. Updated 8 months ago.

Status:
Feedback
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:102834]

Description

since procs and lambdas are of the same type, as long as Proc::new exists, it should be able to create either.

class Proc
  def augment
    self.class.new lambda? do 
      call
    end
  end
end

Updated by ko1 (Koichi Sasada) 8 months ago

  • Status changed from Open to Rejected

could you make new ticket with more motivation/example/discussion?

Updated by bughit (bug hit) 8 months ago

Why a new ticket? What's wrong with this one? If you wanted clarification you didn't have to close it, and even now you can still reopen.

As to the substance, if you want to transform an existing proc or lambda in a way that involves creating a new one and calling the original from it, it makes sense to end up with the same "type" you started with (proc or lambda). The simplest example is negation:


class Proc
  def negate
    self.class.new do |*args, &block|
      not self.(*args, &block)
    end
  end
end

The above will turn a lambda into a proc. Why shouldn't the Proc constructor be able to create a lambda? Lambdas should have probably been a sub-type, but as long as they share the same type and hence constructor, it seems almost an obligation for it to be able to construct either: Proc.new(lambda: true)

Updated by naruse (Yui NARUSE) 8 months ago

  • Status changed from Rejected to Feedback

A correct status of a ticket whose description doesn't have a use cases or user stories to discuss the validness of the request and the actual API design is "Feedback".e

Updated by Eregon (Benoit Daloze) 8 months ago

There is Kernel.send(lambda ? :lambda : :proc) { ... } if you really really need this.
But it's probably slow and Ruby implementations have troubles to optimize this as they have no idea when parsing if the block is for a proc or lambda.

Of course the more sensible thing would be:

class Proc
  def negate
    if lambda?
      lambda do |*args, &block|
        not self.(*args, &block)
      end
    else
      proc do |*args, &block|
        not self.(*args, &block)
      end
    end
  end
end

That has a significant advantage that a given block only has proc or lambda semantics but not both (and so using e.g., break is possible).
And also from looking at the backtrace you can know which it was.

I don't think it matters if negate e.g. always returns a lambda in this case (the caller can only observe the difference though Proc#lambda? and that shouldn't matter), so it should just be:

class Proc
  def negate
    -> (*args, &block) do
      not self.(*args, &block)
    end
  end
end

As discussed extensively in related tickets, it's a very bad idea to convert from proc to lambda or vice-versa, but at least this issue only suggests a polymorphic create with a literal block.

So the important question here is why do you need to preserve whether the source Proc was a lambda or not?

Actions

Also available in: Atom PDF