mf icon indicating copy to clipboard operation
mf copied to clipboard

Use method_missing

Open theldoria opened this issue 6 years ago • 6 comments

It is possible to use method_missing, saving you to define the most operators by hand...

theldoria avatar Apr 30 '18 08:04 theldoria

I could, but that would also come at the cost of speed

baweaver avatar Apr 30 '18 16:04 baweaver

theldoria's method_missing defines the method on the first pass, so only the first hit then the method exists.

I think someone did a post years ago using "X" as the module name, but can't find it or recall if it had a different purpose.

If I used this I'd probably do something horrible like define a utf char (option + x) method on Object to wrap it.

class  Object
  def ≈
    Mf
  end
end
[1,2,3,4,5].map(&≈ + 5)

perhaps not for production..

babelian avatar May 01 '18 01:05 babelian

True, but send is still slow.

baweaver avatar May 01 '18 02:05 baweaver

send method vs native
=====================

Send result: 8
Native result: 8

Warming up --------------------------------------
                Send    89.094k i/100ms
              Native   118.006k i/100ms
Calculating -------------------------------------
                Send      1.180M (± 7.0%) i/s -      5.880M in   5.004923s
              Native      1.614M (±11.3%) i/s -      8.024M in   5.022100s

Comparison:
              Native:  1614333.5 i/s
                Send:  1180439.5 i/s - 1.37x  slower

Mark code:

def run_benchmark(title, quiet = false, **benchmarks)
  puts '', title, '=' * title.size, ''

  # Validation
  benchmarks.each do |benchmark_name, benchmark_fn|
    puts "#{benchmark_name} result: #{benchmark_fn.call()}"
  end unless quiet

  puts

  Benchmark.ips do |bm|
    benchmarks.each do |benchmark_name, benchmark_fn|
      bm.report(benchmark_name, &benchmark_fn)
    end
    
    bm.compare!
  end
end

task :send_vs_native do
  run_benchmark('send method vs native',
    'Send':   -> { b = 3; cmd = '+'; proc { |a| a.send(cmd, *b) }[5] },
    'Native': -> { b = 3; proc { |a| b + a }[5] }
  )
end

baweaver avatar May 01 '18 03:05 baweaver

Avoiding the use of the splat operator and ensuring to have the command as a symbol can mitigate the performance penalty from the send command a bit. See commit 0c8ec6e.

Benchmark results:

send method vs native
=====================

Send Optim result: 8
Send Splat result: 8
Send No Sym result: 8
Send result: 8
Native result: 8

Warming up --------------------------------------
          Send Optim   168.790k i/100ms
          Send Splat   143.838k i/100ms
         Send No Sym   150.276k i/100ms
                Send   131.147k i/100ms
              Native   183.411k i/100ms
Calculating -------------------------------------
          Send Optim      2.503M (± 0.6%) i/s -     12.659M in   5.058795s
          Send Splat      1.993M (± 0.5%) i/s -     10.069M in   5.051493s
         Send No Sym      2.128M (± 0.5%) i/s -     10.670M in   5.014852s
                Send      1.764M (± 0.7%) i/s -      8.918M in   5.055496s
              Native      2.755M (± 0.6%) i/s -     13.939M in   5.060607s

Comparison:
              Native:  2754565.6 i/s
          Send Optim:  2502529.4 i/s - 1.10x  slower
         Send No Sym:  2127654.2 i/s - 1.29x  slower
          Send Splat:  1993258.1 i/s - 1.38x  slower
                Send:  1764099.1 i/s - 1.56x  slower

using

CMD_SYM = :'+'
CMD = '+'
b = 3
run_benchmark('send method vs native',
              'Send Optim':   -> { proc { |a| a.send(CMD_SYM, b) }[5] },
              'Send Splat':   -> { proc { |a| a.send(CMD_SYM, *b) }[5] },
              'Send No Sym':   -> { proc { |a| a.send(CMD, b) }[5] },
              'Send':   -> { proc { |a| a.send(CMD, *b) }[5] },
              'Native': -> { proc { |a| a + b }[5] })

If performance really is an issue one still could provide specialized functions and fall back to method_missing to seldom-used operators.

theldoria avatar May 01 '18 08:05 theldoria

or perhaps take a cue from your QO evil branch and define it with an eval.

babelian avatar May 01 '18 10:05 babelian