Projects

Ticket #529 (closed defect: fixed)

Opened 2 years ago

Last modified 23 months ago

Using a Proc as a ‘callback function’

Reported by: eloy.de.enige@… Owned by: martinlagardette@…
Priority: blocker Milestone: MacRuby 0.6
Component: MacRuby Keywords:
Cc: eloy.de.enige@…

Description (last modified by martinlagardette@…) (diff)

Some Cocoa methods, or C functions, take pointers to functions which can be used as callbacks. For instance, FSEventStreamCreate:  http://bit.ly/8p70Yw.

RubyCocoa, in conjunction with BridgeSupport, supported this by allowing the user to give a proc that would be used as the callback. MacRuby should support this too.

Here's a spec example:

describe "BridgeSupport" do
  it "bridges a proc to be used where a pointer to a callback function is required" do
    array = [5, 3, 2, 4, 1]
    proc = Proc.new do |x, y, context_pointer|
      context = context_pointer[0].chr + context_pointer[1].chr + context_pointer[2].chr
      x <=> y if context == 'foo'
    end

    array.sortUsingFunction(proc, context: 'bar')
    array.should == [5, 3, 2, 4, 1]

    array.sortUsingFunction(proc, context: 'foo')
    array.should == [1, 2, 3, 4, 5]
  end
end

Don't know if this is feasible, but it would be great if the arguments given to the proc, like the context argument, were no Pointer objects, but the object they actually point to:

describe "BridgeSupport" do
  it "bridges a proc to be used where a pointer to a callback function is required" do
    array = [5, 3, 2, 4, 1]
    proc = Proc.new do |x, y, context|
      x <=> y if context == 'foo'
    end

    array.sortUsingFunction(proc, context: 'bar')
    array.should == [5, 3, 2, 4, 1]

    array.sortUsingFunction(proc, context: 'foo')
    array.should == [1, 2, 3, 4, 5]
  end
end

Change History

Changed 2 years ago by eloy.de.enige@…

Actually, the latter examples should probably be more like:

describe "BridgeSupport, where a pointer to a callback function is required" do
  it "allows the use of a proc as callback" do
    array = [5, 3, 2, 4, 1]
    proc = Proc.new { |x, y, _| x <=> y }

    array.sortUsingFunction(proc, context: nil)
    array.should == [1, 2, 3, 4, 5]
  end

  it "passes the actual objects as arguments instead of the pointers to the arguments" do
    result = ''
    proc = Proc.new { |_, __, context| result = context }
    [1].sortUsingFunction(proc, context: 'foo')
    result.should == 'foo'
  end
end

Changed 2 years ago by eloy.de.enige@…

And here's the RubyCocoa code I want to be able to use on MacRuby:  http://github.com/alloy/kicker/blob/master/vendor/rucola/fsevents.rb#L108

Changed 2 years ago by lsansonetti@…

  • owner changed from lsansonetti@… to martinlagardette@…

Thibault, this could be something for you. The challenge here is to JIT compile at runtime for a given Proc a trampoline function that will call its callback, then passing a pointer to the trampoline to the dispatcher. Also, we must keep a reference to the trampoline inside the internal proc structure so that we can avoid generating it more than once and free the machine code once the proc is finalized by the GC.

Changed 2 years ago by martinlagardette@…

  • status changed from new to assigned

Changed 23 months ago by martinlagardette@…

  • status changed from assigned to closed
  • cc eloy.de.enige@… added
  • resolution set to fixed
  • description modified (diff)
  • milestone set to MacRuby 0.6

Implemented with r3847 :-)

framework 'Foundation'

array = [1, 42, 6, 2, 3]
proc = Proc.new { |a, b, _| a <=> b }
array.sortedArrayUsingFunction(proc, context: nil) # [1, 2, 3, 6, 42]
Note: See TracTickets for help on using tickets.