Class: Qrb::UnionType

Inherits:
Type
  • Object
show all
Defined in:
lib/qrb/type/union_type.rb

Overview

A union type (aka algebraic type) allows capturing information types through generalization/disjunction. For instance,

Numeric = Int|Real

This class allows capturing such union types, as follows:

Int     = BuiltinType.new(Fixnum)
Real    = BuiltinType.new(Float)
Numeric = UnionType.new([ Int, Real ])

When transforming a value through ‘dress`, the different candidate types are tried in specified order. The first one that succeeds at building the value ends the process and the value is simply returned. Accordingly, the concrete representation will be

R(Numeric) = R(Int) ^ R(Real) = Fixnum ^ Float = Numeric

where ‘^` denotes the `least common super type` operator on ruby classes.

Accordingly, the ‘dress` transformation function has the following signature:

dress :: Alpha  -> Numeric throws TypeError
dress :: Object -> Numeric throws TypeError

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Type

#name, #name=, #to_s

Constructor Details

#initialize(candidates, name = nil) ⇒ UnionType

Returns a new instance of UnionType.



32
33
34
35
36
37
38
39
# File 'lib/qrb/type/union_type.rb', line 32

def initialize(candidates, name = nil)
  unless candidates.all?{|c| c.is_a?(Type) }
    raise ArgumentError, "[Qrb::Type] expected, got #{candidates}"
  end

  super(name)
  @candidates = candidates.freeze
end

Instance Attribute Details

#candidatesObject (readonly)

Returns the value of attribute candidates.



40
41
42
# File 'lib/qrb/type/union_type.rb', line 40

def candidates
  @candidates
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?



67
68
69
70
# File 'lib/qrb/type/union_type.rb', line 67

def ==(other)
  return false unless other.is_a?(UnionType)
  set_equal?(candidates, other.candidates)
end

#default_nameObject



63
64
65
# File 'lib/qrb/type/union_type.rb', line 63

def default_name
  candidates.map(&:name).join('|')
end

#dress(value, handler = DressHelper.new) ⇒ Object

Invoke ‘dress` on each candidate type in turn. Return the value returned by the first one that does not fail. Fail with an TypeError if no candidate succeeds at tranforming `value`.



49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/qrb/type/union_type.rb', line 49

def dress(value, handler = DressHelper.new)

  # Do nothing on TypeError as the next candidate could be the good one!
  candidates.each do |c|
    success, uped = handler.just_try do
      c.dress(value, handler)
    end
    return uped if success
  end

  # No one succeed, just fail
  handler.failed!(self, value)
end

#hashObject



73
74
75
# File 'lib/qrb/type/union_type.rb', line 73

def hash
  self.class.hash ^ set_hash(self.candidates)
end

#include?(value) ⇒ Boolean

Returns:

  • (Boolean)


42
43
44
# File 'lib/qrb/type/union_type.rb', line 42

def include?(value)
  candidates.any?{|c| c.include?(value) }
end