Skip to content
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

Use method_missing #1

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Use method_missing #1

wants to merge 2 commits into from

Conversation

theldoria
Copy link

@theldoria theldoria commented Apr 30, 2018

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

@baweaver
Copy link
Owner

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

@babelian
Copy link

babelian commented May 1, 2018

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..

@baweaver
Copy link
Owner

baweaver commented May 1, 2018

True, but send is still slow.

@baweaver
Copy link
Owner

baweaver commented May 1, 2018

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

@theldoria
Copy link
Author

theldoria commented May 1, 2018

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.

@babelian
Copy link

babelian commented May 1, 2018

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants