Expressing the type of attribute B as dependent on an arbitrary value of attribute A.

What might be the simplest way to express this type if it is possible? Would monads work here? Is there a better way?

    class VersionedMetadata < Dry::Struct
      attribute :version, Types::Strict::Integer

      # how do I express this?
      attribute :metadata, MetadataV1 # if version == 1
      attribute :metadata, MetadataV2 # if version == 2
      attribute :metadata, UnsupportedVersionMetadata # any other value of version
    end

Yes I am aware that the ‘type’ attribute can allow for polymorphic construction but that isn’t quite the same as what I’m hoping to learn how to do. Would love to be able to change the type of attribute B based on arbitrary values of attribute A.

It can be encoded via

module VersionedMetadata
  class V1 < Dry::Struct
    attribute :version, Types::Strict::Integer.constrained(eql?: 1)
    attribute :metadata, MetadataV1
  end

  class V2 < Dry::Struct
    attribute :version, Types::Strict::Integer.constrained(eql?: 2)
    attribute :metadata, MetadataV2
  end

  class Other < Dry::Struct
    attribute :version, Types::Strict::Integer
    attribute :metadata, UnsupportedVersionMetadata
  end

  Type = V1 | V2 | Other
end
4 Likes

Thanks, thats close to what I had tried another time, was curious to see if there were other methods. Appreciate the response!