1

I have this preudo code that describes a type

    type MyType1 = {
        type: :type1,
        field1: number,
        field2: any
    } | {
        type: :type2,
        field3: string
    } | {
        type: :type4,
        field4: SomeOtherType
    } | {
        type: :type5,
        field5: string,
        field6: integer,
        field7: float
    } | {
        type: :type6
    }

I've expressed it this way in Ruby:

    class MyType1
        attr_reader :type, :field1, :field2, :field3, :field4, :field5, :field6, :field7

        def init_with_type_1(field1:, field2:)
          @type = :type1
          @field1 = field1
          @field2 = field2
        end

        def init_with_type_2(field3:)
          @type = :type2
          @field3 = field3
        end

        # and so on...

    end

Is there a better, more idiomatic, more simple way?

I don't consider using third-party gems and libraries.

Khinkala2
  • 11
  • 1

1 Answers1

0

I would do it like this:

Type1 = Struct.new(:field1, :field2)
Type2 = Struct.new(:field3)

class MyType1
  def initialize(some_type_item)
    @data = some_type_item
  end
  def self.init_with_type_1(f1, f2)
    self.new(Type1.new(f1,f2))
  end
  def type
    @data.class # Or @data.class.name, if you prefer
  end
  def field1
    # Raises exception, if we don't have Type1 
    @data.field1
  end
end

I coded this explicitly, but some of the work (for instance the definition of field1 etc.) could be made simpler (less typing) using the Forwardable module from the Ruby Standard Library. Also, the init_with_type methods could be generated using a loop, which could simplify things if you have really many different types you want to store here.

I modeled this close to your initial solution, though I ask myself, why you introduce a class MyType1 for this; after having defined Type1, Type2 etc., I would simply do a

myTypeVar = Type2.new(4711)
puts "myTypeVar is a #{myTypeVar.class}"
puts myTypeVar.field3 # OK
puts myTypeVar.field1 # Exception!
user1934428
  • 19,864
  • 7
  • 42
  • 87
  • even if that represents `MyType1`, it doesn't simplify the things, but overcomplicates them. – Khinkala2 Mar 17 '21 at 15:49
  • @Khinkala2 : Actually, that's why I wrote below how I would go at this problem. IMO, inventing MyType1 is unnecessary here. If all the types share certain features, perhaps you would better use a `Module` as a mixin. Unless we see how you plan to use the type, it is hard to recommend. BTW: My approach looks complicated if you manually type out all the methods. I did this only for clarity, but if you have many nested types, you would generate them using a loop, and this would then less code in the end. For instance, you could auto-generate the _field**n**_ and _init_with_type_**n**_ methods. – user1934428 Mar 18 '21 at 08:07