Sorbet: `T::Enum` is currently not `Marshal`-safe

Created on 5 Jun 2020  路  3Comments  路  Source: sorbet/sorbet

Problem

class A < T::Enum
  enums do
    Foo = new('foo')
    Bar = new('bar')
  end

  sig {returns(T::Boolean)}
  def is_good?
    case self
    when Foo then true
    when Bar then false
    else T.absurd(self)
    end
  end
end

x = A::Foo
y = Marshal.load(Marshal.dump(A::Foo))

x.is_good? # true
A::Foo === x # true
A::Foo === y # false
y.is_good? # raises as it reached T.absurd(self)

This is problematic because when parallelizing Ruby scripts with multiple-processes, object passing is achieved through serializing the object using Marshal, piping it down to the destination process, then deserializing it using Marshal again.

Proposed solution


Currently, the definition of === for T::Enum is super(other). I propose changing it to super(other) || (self.class == other.class && self.serialize == other.serialize).

However, I realized that there could be other design decisions to be made beyond this.

enhancement

Most helpful comment

Thanks for the workaround with this, @julius-stripe!

We're experiencing this as well. Can we update this to a bug instead of an enhancement?

All 3 comments

Another possible solution is to change the Marshal custom serialization/deserialization instead:

def _dump(level)
  serialize
end

def self._load(args)
  deserialize(args)
end

Thanks for the workaround with this, @julius-stripe!

We're experiencing this as well. Can we update this to a bug instead of an enhancement?

Fixed in #3206

Was this page helpful?
0 / 5 - 0 ratings