JEP 11 suggestion: abilities to get, set, and remove multiple values in single calls

5 views
Skip to first unread message

Myk Melez

unread,
Jun 3, 2009, 4:50:14 AM6/3/09
to mozilla-la...@googlegroups.com
I suggest adding the abilities to get, set, and remove multiple values in single calls to JEP 11's simple persistent storage, via the following API:

To get multiple values, call |get| with an array of their keys. The function will return an array of the values of those keys, which you can assign to individual variables with destructuring assignment:

let [foo, bar, baz] = jetpack.storage.simple.get(["foo", "bar", "baz"])

To set multiple values, call |set| with an object containing the key -> value pairs to set:

jetpack.storage.simple.set({ foo: 1, bar: true, baz: "example" })

To remove multiple values, call |remove| with an array of their keys:

jetpack.storage.simple.remove(["foo", "bar", "baz"])

Internally the implementation can use (homegrown) polymorphism to automatically determine whether the user is calling the functions with single or multiple values and recursion to reuse the same code for both cases. See the Preferences module for an example of these implementation techniques.

-myk

kixx

unread,
Jun 3, 2009, 12:02:09 PM6/3/09
to mozilla-labs-jetpack
Awesome Myk, I love it.

The api could also be simplified a little by handling the arguments
within the methods using the arguments list within the function
scope. So the api would then look like this:

let [foo, bar, baz] = jetpack.storage.simple.get("foo", "bar", "baz")
jetpack.storage.simple.remove("foo", "bar", "baz")

However, we would not be able to assemble long arrays using Array()
methods before passing them to get() and remove(). So perhaps this is
not a good simplification?

Myk Melez

unread,
Jun 3, 2009, 2:19:11 PM6/3/09
to mozilla-la...@googlegroups.com
On 06/03/2009 09:02 AM, kixx wrote:
The api could also be simplified a little by handling the arguments
within the methods using the arguments list within the function
scope.  So the api would then look like this:

let [foo, bar, baz] = jetpack.storage.simple.get("foo", "bar", "baz")
jetpack.storage.simple.remove("foo", "bar", "baz")
  
This is indeed simpler, which I like. I'm just a bit wary of using the arguments list in this way, although it's hard to put my finger on exactly why. Part of it is the inflexibility of not being able to add another parameter to the methods (not that I can think of another parameter I'd add).

Perhaps it's also that there's less symmetry between the get method's parameter and its return value, which makes its behavior a bit less obvious.


However, we would not be able to assemble long arrays using Array()
methods before passing them to get() and remove().  So perhaps this is
not a good simplification?
  
You would still be able to do it by calling the method with apply:

jetpack.storage.simple.get.apply(jetpack.storage.simple, ["foo", "bar", "baz"]);
// equivalent to jetpack.storage.simple.get("foo", "bar", "baz");

However, that certainly isn't very simple. :-)

-myk

Aza

unread,
Jun 18, 2009, 4:29:04 PM6/18/09
to mozilla-la...@googlegroups.com
Myk,

I think these are great additions. Would you mind adding them to the JEP https://wiki.mozilla.org/Labs/Jetpack/JEP/11?

My gut feeling is that the suggested syntax:

let [foo, bar, baz] = jetpack.storage.simple.get("foo", "bar", "baz")

feels cleaner. The two cons I see are:
(1) Programatically constructing an Array and passing it in becomes harder.
(2) Potential future proofing -- we might want to add an options dictionary or something later.

Neither one of these two cons are insurmountable however.
(1) Is solved by either using .apply as you say (which, while gross looking won't be used very often). The other solution is that if first argument to |get| is an array, it returns as you'd expect.
(2) Because all of the values will be passing in are strings, polymorphism is easy.

-- aza | ɐzɐ --

Myk Melez

unread,
Jun 23, 2009, 4:11:21 AM6/23/09
to mozilla-la...@googlegroups.com
On 06/18/2009 01:29 PM, Aza wrote:
Myk,

I think these are great additions. Would you mind adding them to the JEP https://wiki.mozilla.org/Labs/Jetpack/JEP/11?
Sure, no problem. I've done so, adding the originally proposed syntax for the reasons described below.


My gut feeling is that the suggested syntax:
let [foo, bar, baz] = jetpack.storage.simple.get("foo", "bar", "baz")

  
feels cleaner. The two cons I see are:
(1) Programatically constructing an Array and passing it in becomes harder.
(2) Potential future proofing -- we might want to add an options dictionary or something later.
Yeah, it's a bit simpler, but it has the downsides you mention plus a few more:
  • the keys argument and the return value are no longer datatype symmetric for the multiple-values variant (which symmetry provides a useful mnemonic to the API), although this is irrelevant if we stick with the proposal to make the API only asynchronous;
  • the API will be inconsistent with any we define in the future that can't use the arguments array to pass an arbitrary number of values.

Neither one of these two cons are insurmountable however.
(1) Is solved by either using .apply as you say (which, while gross looking won't be used very often). The other solution is that if first argument to |get| is an array, it returns as you'd expect.
The latter solution creates three variants, which seems unnecessarily complicated.


(2) Because all of the values will be passing in are strings, polymorphism is easy.
That's somewhat true for the implementation, but it also complicates the API, which must be described without reference to the callback being in a particular location in the argument list.

And callback isn't the only potential addition to the get call. We should consider adding a default value argument, which simplifies the common case of wanting to initialize a variable to either a stored or a default value.

My sense is that JavaScript APIs have moved away from using the arguments array in this way for a variety of reasons, including these, and we should do the same.

-myk

adw

unread,
Jun 28, 2009, 5:19:07 PM6/28/09
to mozilla-labs-jetpack
> let [foo, bar, baz] = jetpack.storage.simple.get(["foo", "bar", "baz"])

This is super nice, but the API is async only. That being the case,
which would be more useful?

1)
jetpack.storage.simple.get(["foo", "bar", "baz"], function
(valuesArray) {
// valuesArray = ["foo-value", "bar-value", "baz-value"]
});

2)
jetpack.storage.simple.get(["foo", "bar", "baz"], function
(itemsObject) {
// itemsObject = { foo: "foo-value", bar: "bar-value", baz: "baz-
value" }
});

The same question could be asked for |has|. I like 2, because it lets
me write:

jetpack.storage.simple.get(function (allItemsObject) {
// allItemsObject = dictionary of all items
});

And it also lets us extend |forEachValue| and |forEachItem| like:

jetpack.storage.simple.forEachValue(["foo", "bar", "baz"], function
(val) {
// gets "foo-value", then "bar-value", then "baz-value"
});

jetpack.storage.simple.forEachItem(["foo", "bar", "baz"], function
(item) {
// gets { foo: "foo-value" }, then { bar: "bar-value" },
// then { baz: "baz-value" }
});

Drew
> <http://hg.mozdev.org/jsmodules/file/1e5ab826e798/Preferences.js> for an

Aza

unread,
Jun 29, 2009, 2:42:43 PM6/29/09
to mozilla-la...@googlegroups.com
On Sun, Jun 28, 2009 at 2:19 PM, adw <drew.wi...@gmail.com> wrote:

2)
jetpack.storage.simple.get(["foo", "bar", "baz"], function
(itemsObject) {
 // itemsObject = { foo: "foo-value", bar: "bar-value", baz: "baz-
value" }
});

Let's go for the itemsObject method. After getting above 3 variables, it's going to be hard to remember which one is which. Even worse, you'll end up with code like "var blah = itemsArray[3];" which just isn't very readable when comparied to "items.foo".

 

And it also lets us extend |forEachValue| and |forEachItem| like:

jetpack.storage.simple.forEachValue(["foo", "bar", "baz"], function
(val) {
 // gets "foo-value", then "bar-value", then "baz-value"
});

Good point!
Reply all
Reply to author
Forward
0 new messages