Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't accept the Map constructor an Array of iterable tuples?

I created a tuple type in Javascript that implements the Iterable protocol. Now it should be easy to convert to Map:

const Tuple = (...args) => {
  const Tuple = f => f(...args);
  Tuple[Symbol.iterator] = () => args[Symbol.iterator]();
  return Tuple;
};

new Map([Tuple(1, "a"), Tuple(2, "b")]); // Map {undefined => undefined}

Instead I have to do the conversion manually:

const Tuple = (...args) => {
  const Tuple = f => f(...args);
  Tuple[Symbol.iterator] = () => args[Symbol.iterator]();
  return Tuple;
};

const toArray = tx => tx((...args) => args);

const Map_ = (...pairs) => {
  return new Map(pairs.map(pair => toArray(pair)));
};

const map = Map_(Tuple(1, "a"), Tuple(2, "b"));

console.log(map.get(1), map.get(2)); // "a" "b"

It seems as if Map only accepts an Iterable for the outer composite type, not for the inner pairs. What am I missing? Is there another way to achieve the conversion?


1 Answers

Map's constructor is defined as accepting any Iterable of key/value objects, where the key/value objects are defined as objects where property 0 is the key and property 1 is the value. It says nothing about allowing Iterables for the key/value objects. (It might have been cool if it did allow them and define that it would call the iterator exactly twice, but...that's not what they did. :-) And it would be more complex...)

If we look at the spec, your Tuple would work if it supported the properties 0 (for the key) and 1 (for the value). For instance:

// (Defined this way because you seemed to want a non-constructor)
const TupleMethods = {
  get "0"() {
    return this.key;
  },
  get "1"() {
    return this.value;
  }
};
const Tuple = (key, value) => {
  const t = Object.create(TupleMethods);
  t.key = key;
  t.value = value;
  return t;
}
// Usage:
const m = new Map([
  Tuple("one", "uno"),
  Tuple("two", "due"),
  Tuple("three", "tre")
]);
console.log(m.get("two")); // "due"

In a comment you mentioned immutability. Perhaps:

// (Defined this way because you seemed to want a non-constructor)
const TupleMethods = {};
Object.defineProperties(TupleMethods, {
    "0": {
        get() {
            return this.key;
        }
    },
    "1": {
        get() {
            return this.value;
        }
    }
});
const Tuple = (key, value) => {
    const t = Object.create(TupleMethods);
    Object.defineProperties(t, {
        key: {
            value: key
        },
        value: {
            value: value
        }
    });
    return t;
};

// Usage:
const m = new Map([
    Tuple("one", "uno"),
    Tuple("two", "due"),
    Tuple("three", "tre")
]);
console.log(m.get("two")); // "due"
like image 90
T.J. Crowder Avatar answered Mar 14 '26 15:03

T.J. Crowder



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!