I was wondering which method (or form to keep it separated from Object Methods) to call a method of a variable that can be (Type1 | Type2 | Nil) would be the best to keep a codebase clean while maintaining performance, specially when trying to handle Nil like in this piece of code:
require "benchmark"
module LOL
# Client can be Meow or Meow2 using some sort of statement to set them to a
# Meow or Meow2 object but by default is nil.
@@client : (Meow | Meow2)? = nil
class Meow2
def xd
"xd"
end
end
class Meow
def xd
"xd"
end
end
def self.xdif
# assignment and if
client = @@client
return if client.nil?
client.xd
end
def self.xdcast
# Casting
return if @@client.nil?
@@client.as(Meow | Meow2).xd
end
def self.xdtry
# .try
@@client.try(&.xd)
end
end
Benchmark.ips do |x|
x.report("assign and if") { LOL.xdif }
x.report("cast") { LOL.xdcast }
x.report("try") { LOL.xdtry }
end
The results were:
assign and if 629.44M ( 1.59ns) (± 2.85%) 0.0B/op fastest
cast 448.86M ( 2.23ns) (± 2.10%) 0.0B/op 1.40× slower
try 628.55M ( 1.59ns) (± 2.99%) 0.0B/op 1.00× slower
For some reason using return if @@client.nil? in the self.xdcast yielded a slower result, but that didn’t happen when using
client = @@client
return if client.nil?
In the assignment and if form.
So the best when handling this type of behavior seems to be @@client.try(&.xd), it’s simple and equality fast as the assignment and if form.
I just wanted to share this if someone was searching for a performant and clear way to handle something like this.