New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Proc#* and Method#* for Proc and Method composition #935

Open
wants to merge 3 commits into
base: trunk
from

Conversation

4 participants
@mudge

mudge commented Jun 14, 2015

c.f. https://bugs.ruby-lang.org/issues/6284

Allow Procs and Methods to be composed together with *.

f = proc { |x| x * 2 }
g = proc { |x, y| x + y }
h = f * g

h.call(1, 2) #=> 6

Support composition with any object that has a call method, e.g.

class Foo
  def call(x, y)
    x + y
  end
end

f = proc { |x| x * 2 }
g = f * Foo.new

g.call(1, 2) #=> 6

This implementation should be largely equivalent to the following Ruby (excepting that the lambda? property is preserved):

class Proc
  def *(g)
    proc { |*args, &blk| call(g.call(*args, &blk)) }
  end
end
Show outdated Hide outdated proc.c

@mudge mudge closed this Jun 23, 2015

@mudge mudge reopened this Jun 23, 2015

@tsujigiri

This comment has been minimized.

Show comment
Hide comment
@tsujigiri

tsujigiri Feb 2, 2016

I, for one, would love to see this merged! :)

tsujigiri commented Feb 2, 2016

I, for one, would love to see this merged! :)

@marshall-lee

This comment has been minimized.

Show comment
Hide comment
@marshall-lee

marshall-lee Feb 8, 2016

I like the idea of functional composition but I don't like the implementation here.

First of all, I don't like naming it *. Any special reason why use a star symbol? For example dry-pipeline gem implements a pipeline operator >>. Of course, both operators have their numeric analogues (multiplication and bitwise right shift accordingly) and it's confusing but >> is used less often so it's a better option IMO.

And the second problem that it does not deal well with custom callable objects. I mean:

module Increment
  def self.call(x)
    x + 1
  end
end

multiply_two = proc { |x| x * 2 }

(multiply_two * Increment).call(1) # => 4
(Increment * multiply_two).call(1) # => NoMethodError

So, I like the concept of mixin with composition operator more like it's done in dry-pipeline gem. Something llike:

module Increment
  extend PipelineOperator
  def self.call(x)
    x + 1
  end
end

marshall-lee commented Feb 8, 2016

I like the idea of functional composition but I don't like the implementation here.

First of all, I don't like naming it *. Any special reason why use a star symbol? For example dry-pipeline gem implements a pipeline operator >>. Of course, both operators have their numeric analogues (multiplication and bitwise right shift accordingly) and it's confusing but >> is used less often so it's a better option IMO.

And the second problem that it does not deal well with custom callable objects. I mean:

module Increment
  def self.call(x)
    x + 1
  end
end

multiply_two = proc { |x| x * 2 }

(multiply_two * Increment).call(1) # => 4
(Increment * multiply_two).call(1) # => NoMethodError

So, I like the concept of mixin with composition operator more like it's done in dry-pipeline gem. Something llike:

module Increment
  extend PipelineOperator
  def self.call(x)
    x + 1
  end
end

mudge added some commits Jun 14, 2015

proc.c: Implement Proc#* for Proc composition
* proc.c (proc_compose): Implement Proc#* for Proc composition, enabling
  composition of Procs and Methods. [Feature #6284]

* test/ruby/test_proc.rb: Add test cases for Proc composition.
proc.c: Implement Method#* for Method composition
* proc.c (rb_method_compose): Implement Method#* for Method composition,
  which delegates to Proc#*.

* test/ruby/test_method.rb: Add test cases for Method composition.
proc.c: Support any callable when composing Procs
* proc.c (proc_compose): support any object with a call method rather
  than supporting only procs. [Feature #6284]

* proc.c (compose): use the function call on the given object rather
  than rb_proc_call_with_block in order to support any object.

* test/ruby/test_proc.rb: Add test cases for composing Procs with
  callable objects.

* test/ruby/test_method.rb: Add test cases for composing Methods with
  callable objects.
@mooreniemi

This comment has been minimized.

Show comment
Hide comment
@mooreniemi

mooreniemi Oct 28, 2016

FWIW I am pro *, and used it in my C extension. I'd argue it has some mindshare from: https://www.youtube.com/watch?v=seVSlKazsNk

mooreniemi commented Oct 28, 2016

FWIW I am pro *, and used it in my C extension. I'd argue it has some mindshare from: https://www.youtube.com/watch?v=seVSlKazsNk

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment