RE: RE: It doesn't make sense to use [MapClass] for the CacheList interface

From: ¼ÛÁ¤±â [mailto:jungkee.song@samsung.com] 

> Promise already abstracts that async operation. AsyncMap is just a Map that runs async. No more no less. It does get/set/... the entry exactly the same way as Map does but returning Promise that resolves with the value.

That doesn't really address the issue. Let me elaborate.

Promises represent an asynchronous operation. The creator of the promise provides a "hook," the "executor" [1], for actually performing that async operation. One the executor has resolved or rejected the promise, the promise's value can be accessed from the outside with `then`. The result is that promises are created with code that looks like:

```js
var myPromise = new Promise((resolve, reject) => {
  // do async process to resolve or reject the promise
});
```

For AsyncMap, it doesn't represent an async operation. Rather, it more or less represents an entire database API. To have a useful AsyncMap class, you would need to have the creator of the AsyncMap instance define:

- What async process does `get` do?
- What async process does `has` do? (Cannot be derived from `get`, because `undefined` is a valid value to store in a map) 
- What async process does `set` do?
- What async process does `delete` do?
- What async process does `forEach` do?

From there you could derive, somewhat inefficiently, clear, entries, keys, and values. But this is a lot more than the single promise executor. The only way I can see to make this work would be essentially:

```js
var myAsyncMap = new AsyncMap({
  get(key) { /* do async process for get */ },
  has(key) { /* ... */ },
  set(key, value) { /* ... */ },
  delete(key) { /* ... */ },
  forEach(callback, thisArg) { /* ... */ }
});
```

Now you can use that myAsyncMap instance, and e.g. calling `get` will call the provided hook on it, doing whatever specific async op is appropriate for that particular async map.

This is kind of silly, because the only value you have added is (probably inefficient) automatic implementations of `clear`, `entries`, `keys`, and `values`.

A better approach would be to just create a custom class for your specific use case, e.g. a `Cache` class, and have it efficiently do cache-specific I/O. That cache class can conform to a duck-typed interface, but there's no point in actually reifying that interface into an `AsyncMap` class with user-provided hooks.

> The "hook" should be provided by additional methods defined in the derived class, when necessary. Assuming we have AsyncMap (something like the following) ready as a language construct in ES,
> // Syntax is in TypeScript interface
> ...
> > AsyncMap.prototype methods are supposed to provide the generic *async* Map operations.

Part of the issue is might be that you are seeing things in terms of TypeScript, instead of in terms of JavaScript. In JavaScript, those generic type parameters are meaningless, and the entire idea of a "interface" is meaningless. In JavaScript, there are constructible classes, and nothing else.

The design you outline seems to be toward some sort of "abstract base class" idea, where there is no implementation of get/has/set/delete/forEach, but there is an implementation of "generic *async* Map operations", viz. clear/entries/keys/values. But JavaScript doesn't have abstract base classes!

> Isn't it a good idea to have generic asynchronous Map in JavaScript? It's all async and we have Promise now. WDYT?

I think having a generic contract that async map-like things conform to is fine, e.g. what methods will it have. But I don't see much value in providing an actual AsyncMap constructor.


[1]: https://people.mozilla.org/~jorendorff/es6-draft.html#sec-initializepromise

Received on Sunday, 11 May 2014 19:42:05 UTC