mf
mf copied to clipboard
Use method_missing
It is possible to use method_missing, saving you to define the most operators by hand...
I could, but that would also come at the cost of speed
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..
True, but send is still slow.
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
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.
or perhaps take a cue from your QO evil branch and define it with an eval.