Skip to content

Instantly share code, notes, and snippets.

@JoshCheek
Last active February 23, 2021 07:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JoshCheek/384af7adb0c576e47203b0965a6bbc2c to your computer and use it in GitHub Desktop.
Save JoshCheek/384af7adb0c576e47203b0965a6bbc2c to your computer and use it in GitHub Desktop.
Subclassing nil in Ruby 2.7.2 (the old version broke)
RUBY_VERSION # => "2.7.2"
require 'fiddle'
User = Struct.new :name
class NullUser < NilClass
# We have no way to allocate a new NullUser... BUT! We can hack around this
# by making a new object and setting its class pointer to point at NullUser
def self.new(*)
instance = Object.new
instance_ptr = Fiddle::Pointer.new Fiddle.dlwrap instance
klass_ptr = Fiddle::Pointer.new Fiddle.dlwrap self
instance.class # => Object
instance_ptr[8, 8] = klass_ptr.ref[0, 8] # set the new object's class
instance.class # => NullUser
instance
end
def name
''
end
end
user = User.new 'Samantha'
user.name # => "Samantha"
user.to_h # => {:name=>"Samantha"}
user.nil? # => false
user # => #<struct User name="Samantha">
user = NullUser.new
user.name # => ""
user.to_h # => {}
user.nil? # => true
user # => nil
# Just to prove the point:
def nil.omg?
:wtf
end
user.omg? # => :wtf
# One reason this works is b/c of this possible bug
# if they ever fix this, we'll have to do more work to hack around it.
nil.singleton_class.singleton_class? # => false
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment