type Association = {
     ==(_:Association)->Boolean
     hashcode->Number
     getValue->V
     getKey->K
     setValue(_:V)->V
     asString->String}

type Iterator = {
    reset->Void
    hasNext->Boolean
    get->T
    next->T}

def missing is public, readable = object{
    method asString->String{"-"}
}

// Constructs association with key k, no value
method withKey(k)->Association is public{AssociationClass.new(k, missing)}


// Constructs association with key k, value v
method withKey(k)value(v)->Association is public{AssociationClass.new(k, v)}


// Constructs iterator to traverse values of collection of associations
method valueIterator(data:Iterator)->Iterator is public{ValueIterator.new(data)}


// Constructs iterator to traverse keys of collection of associations
method keyIterator(data:Iterator)->Iterator is public{KeyIterator.new(data)}


class AssociationClass.new(key, value){ //when generics work for classes,
                                        // will have key:K, value:V
    var theKey is readable := key

    var theValue is readable := value

    // @pre other is non-null* Association
    // @post returns true iff keys are equal
    // @param other is another Association
    // @return true iff keys are equal
    method ==(other:Association)->Boolean is public{
        getKey == other.getKey}

     // @post @return hash code for association
     method hashcode->Number is public{getKey.hashcode}
     
     // Fetch value from association. May be null.
     // @post @return value 
     method getValue->Dynamic is public{theValue}
     
     // Fetch key from association. Should not be null.
     // @post @return key
     method getKey->Dynamic is public{theKey}
     
     // Sets value of key-value pair
     // @post sets value to value
     // @param newVal the new value
     // @return the former value
     method setValue(newVal)->Dynamic is public{
         var oldValue := theValue
         theValue := newVal
         oldValue}
     
     // Standard string representation of association
     // @post @return string representation
     method asString->String is public{""}
}

// Iterators to traverse keys and values of collection of 
// associations, respectively, where slave is an iterator
// over a collection of associations
class KeyIterator.new(slave:Iterator){

    method reset->Void is public{slave.reset}

    method hasNext->Boolean is public{slave.hasNext}

    method next->Dynamic is public{
        var pair:Association := slave.next
        return pair.getKey}

    method get->Dynamic is public{
        var pair:Association := slave.get
        return pair.getKey}
}
class ValueIterator.new(slave:Iterator){

    method reset->Void is public{slave.reset}

    method hasNext->Boolean is public{slave.hasNext}

    method next->Dynamic is public{
        var pair:Association := slave.next
        return pair.getValue}

    method get->Dynamic is public{
        var pair:Association := slave.get
        return pair.getValue}
}