""" Pair.cobra Provides two Pair classes: -- one type arg - both elements of the pair are the same type Pair(2, 2) Pair('foo', 'bar') -- two type args - elements can be different types Pair(3, 'three') Pair(c, amount) Note that Pair inherits Pair. In other words, when accepting arguments, you may wish to use the general Pair type which will accept both. The elements of the pair are accessed as .a and .b or [0] and [1]. You can also use a `for` loop on a pair as it is enumerable. Comparisons between pairs such as `p1 < p2` are effectively comparisons of their elements. You can use a pair's hash code as long don't modify the pair or its elements. That means you can put pairs in sets or use them as keys in dictionaries. Unit tests below show examples of using pairs. """ namespace Cobra.Core class BasePair is abstract def _compare(a, b) as int """ Gracefully handle comparisons that involve nil. A simple `a.compareTo(b)` does not work if `a` can be `nil`. """ if a is nil if b is nil, return 0 else, return -1 else if b is nil return 1 else return a.compareTo(b) get count as int return 2 class Pair inherits BasePair implements System.Collections.IEnumerable, IComparable> test p = Pair(1, 2) assert p.a == 1 and p.b == 2 assert p[0] == 1 and p[1] == 2 assert p.toString == 'Pair(1, 2)' expect IndexOutOfRangeException, assert p[2] == 3 cue init(a as TA, b as TB) base.init _a, _b = a, b get a from var as TA get b from var as TB get [i as int] as dynamic? if i == 0, return _a if i == 1, return _b throw IndexOutOfRangeException('Index [i] is out of range for a pair (0-1).') def toString as String is override sa = CobraCore.toTechString(.a) sb = CobraCore.toTechString(.b) return 'Pair([sa], [sb])' def equals(other as Pair) as bool test assert Pair('a', 'b').equals(Pair('a', 'b')) assert not Pair('a', 'b').equals(Pair('a', 'c')) body return other.a == .a and other.b == .b def equals(obj as Object?) as bool is override test assert Pair('a', 'b') == Pair('a', 'b') assert Pair('a', 'b') <> Pair('a', 'c') body if obj is nil, return false if obj is this, return true if obj inherits Pair, return obj.a == .a and obj.b == .b return false def compareTo(p as Pair) as int test assert Pair('a', 3) < Pair('b', 4) assert Pair(2, 3) > Pair(2, 2) # on-hold. to-do # assert Pair(nil, 'a') < Pair(nil, 'b') # assert Pair(nil, nil) < Pair(1, 1) body diff = _compare(.a, p.a) if diff == 0, diff = _compare(.b, p.b) return diff def getHashCode as int is override test d = { Pair(1, 'one'): 'one', Pair(2, 2): 'two', # to-do Pair(nil, nil): 'nil', } assert d[Pair(1, 'one')] == 'one' assert d[Pair(2, 2)] == 'two' # to-do assert d[Pair(nil, nil)] == 'nil' body return HashCodeUtils.combine( if(.a is nil, 0, .a.getHashCode), if(.b is nil, 0, .b.getHashCode)) def getEnumerator as System.Collections.IEnumerator test assert (for s in Pair('a', 'b') get s) == ['a', 'b'] body yield .a yield .b class Pair inherits Pair # to-do? implements IEnumerable , IComparable> test p = Pair(1, 2) assert p.a == 1 and p.b == 2 assert p[0] == 1 and p[1] == 2 assert p.toString == 'Pair(1, 2)' expect IndexOutOfRangeException, assert p[2] == 3 /# Would be nice if the indexer was strongly typed, but I don't this is possible. get [i as int] as T if i == 0, return _a if i == 1, return _b throw IndexOutOfRangeException('Index [i] is out of range for a pair (0-1).') #/ /# # to-do? def compareTo(p as Pair) as int test assert Pair('a', 'b') < Pair('b', 'c') assert Pair(2, 3) > Pair(2, 2) assert Pair(nil, 'a') < Pair(nil, 'b') assert Pair(nil, nil) < Pair(1, 1) body diff = _compare(.a, p.a) if diff == 0, diff = _compare(.b, p.b) return diff # to-do? def getEnumerator as IEnumerator is override implements System.Collections.IEnumerable test assert (for s in Pair('a', 'b') get s) == ['a', 'b'] body yield .a yield .b def getEnumerator as System.Collections.IEnumerator is override implements System.Collections.IEnumerable return .getEnumerator #/