ES4 draft: Map
Hello :)
In AS3 the flash.util.Dictionnary class contains a little argument in the constructor to control the weak references :
Exemple : www.gskinner.com/blog/archives/2006/07/as3_dictionary.html
In ES4 the garbage collector support weak references ? This feature is really important for me :)
To implement a full Event model like AS3 event model based Dom2/3 W3C event model... this feature is important for example :)
EKA+ :)
2008/2/29, Lars Hansen <lhansen at adobe.com>:
From: es4-discuss-bounces at mozilla.org
[mailto:es4-discuss-bounces at mozilla.org] On Behalf Of ekameleon Sent: 29. februar 2008 11:47 To: es4-discuss at mozilla.org Subject: Re: ES4 draft: Map
Hello :)
In AS3 the flash.util.Dictionnary class contains a little
argument in the constructor to control the weak references :
Exemple :
www.gskinner.com/blog/archives/2006/07/as3_dictionary.html
In ES4 the garbage collector support weak references ?
No.
This feature is really important for me :)
Sorry, but we've discussed this extensively in the past and have decided not to require support for weak references in ES4.
--lars
To implement a full Event model like AS3 event model based
Dom2/3 W3C event model... this feature is important for example :)
EKA+ :)
2008/2/29, Lars Hansen <lhansen at adobe.com>:
I'm enclosing the draft for the Map class. Please
comment.
--lars
_______________________________________________
Es4-discuss mailing list
Es4-discuss at mozilla.org
https://mail.mozilla.org/listinfo/es4
To me it seems like iterator::get* will not return lazy iterators. Is that intentional? I think it defeats one of the benefits of using iterators over arrays.
Anyway, if it is intentional, I think it should be documented (outside the actual code).
2008/2/29 Lars Hansen <lhansen at adobe.com>:
An HTML attachment was scrubbed... URL: esdiscuss/attachments/20080229/a483f965/attachment-0002
Sorry that this was unclear in the meta message. The helper function is normative in the sense that it defines the functionality, eg in the order of operations on a data structure. But it is not visible, not part of the api, and a real implementation does not reserve the helper namespace. Ditto for informative functions but their prose description gives the implementation more room for variation.
-----Original Message----- From: Erik Arvidsson [mailto:erik.arvidsson at gmail.com] Sent: 29. februar 2008 19:17 To: Lars Hansen Cc: es4-discuss at mozilla.org Subject: Re: ES4 draft: Map
Hi Lars,
To me it seems like iterator::get* will not return lazy iterators. Is that intentional? I think it defeats one of the benefits of using iterators over arrays.
Anyway, if it is intentional, I think it should be documented (outside the actual code).
The code that is there is intentionally written so, but it does not preclude using lazy iterators. What the code specifies (and what I would welcome debate on) is that insertions into and deletions from the Map after the iterator has been obtained are not visible during iteration. A good implementation would delay creating any intermediate data structure to hold the values yet to be returned until changes to the map makes that required. But it wouldn't be appropriate for the spec to include that optimization.
The requirement for helper::iterate in this regard is that it must not be observable (apart from time and space, perhaps) whether it creates intermediate data structures or not, and if it does, when it does it. (This is analogous to how the Reference data type is treated in the ES3 spec -- most implementations don't use it, even though it's all over the spec.)
The optional /hashcode/ argument is a function that takes a key and returns a numeric code for it. This code may be used to find associations more quickly in the map. Two calls to the /hashcode/ function on the same key value must return the same numeric code, and the /hashcode/ function must always return the same numeric code for two objects that compare equal by the /equals/ function. The default value for /hashcode/ is the intrinsic global function |hashcode|.
Dost thou desire arbitrary numeric hashcodes or integral ones?
Map( object )
When the |Map| class object is called as a function, it creates a new |Map| object from |EnumerableId| to |*|, populating the new |Map| object with the own properties of /object/.
Making Map(x) do something specialized like this seems like a bad idea. If x is already a Map, I'd expect Map(x) to be idempotent and return x.
Should thou need this functionality, use a static method to get it.
Why does get return null instead of undefined when it fails to find an instance?
A version of get with a second parameter X that returns X when the value isn't present would be useful.
Need a clear() method that deletes all bindings.
The iteration protocol makes a copy before starting to iterate. It might be implemented via copy-on-write but I'd like to see how expensive this is.
Waldemar
-----Original Message----- From: Waldemar Horwat [mailto:waldemar at google.com] Sent: 1. mars 2008 01:53 To: Lars Hansen Cc: es4-discuss at mozilla.org Subject: Re: ES4 draft: Map
The optional /hashcode/ argument is a function that takes a key and returns a numeric code for it. This code may be used to find associations more quickly in the map. Two calls to the /hashcode/ function on the same key value must return the same numeric code,
and
the /hashcode/ function must always return the same numeric code for
two objects that compare equal by the /equals/ function. The default
value for /hashcode/ is the intrinsic global function |hashcode|.
Dost thou desire arbitrary numeric hashcodes or integral ones?
Good point. intrinsic::hashcode returns uint. Since the signature of the Map constructor does not yet -- and probably should not, for compatibility with scripts -- have a very constraining signature for the hashcode argument, the most natural thing to do seems to be to require it to return a value that can be converted to uint, and require the implementation to convert the return value from the hashcode function to uint. Will fix.
Map( object )
When the |Map| class object is called as a function, it creates a
new
|Map| object from |EnumerableId| to |*|, populating the new |Map| |Map| object with the own properties of /object/.
Making Map(x) do something specialized like this seems like a bad idea. If x is already a Map, I'd expect Map(x) to be idempotent and return x.
This is what most built-ins in ES3 does, and we've agreed in the past to carry the behavior forward for several of the new classes (Map, Vector, and the primitive classes int, uint, double, decimal, string, and boolean, at least) but I agree that it would be more natural for Map(x) to return x if x is already a Map. Will fix.
Should thou need this functionality, use a static method to get it.
We've been down that road and we rejected it.
Why does get return null instead of undefined when it fails to find an instance?
No good reason that I can think of. I think undefined is at least as sensible; will fix.
A version of get with a second parameter X that returns X when the value isn't present would be useful.
I agree, and that parameter could be optional and default to undefined. Will fix.
Need a clear() method that deletes all bindings.
I always make a new hashtable, but sure, why not.
The iteration protocol makes a copy before starting to iterate. It might be implemented via copy-on-write but I'd like to see how expensive this is.
See my answer to Erik, which I believe answers this.
Following up to myself:
-----Original Message----- From: Lars Hansen Sent: 3. mars 2008 08:04 To: 'Waldemar Horwat' Cc: es4-discuss at mozilla.org Subject: RE: ES4 draft: Map
-----Original Message----- From: Waldemar Horwat [mailto:waldemar at google.com] Sent: 1. mars 2008 01:53
Why does get return null instead of undefined when it fails to find an instance?
No good reason that I can think of. I think undefined is at least as sensible; will fix.
Actually, it was for Java compatibility (the API is modelled on Java, but imperfectly). No matter.
A version of get with a second parameter X that returns X when the value isn't present would be useful.
I agree, and that parameter could be optional and default to undefined. Will fix.
There is actually a problem with an arbitrary optional parameter, and the problem also comes up if -- as somebody sent me private mail about -- we want put() to return the previous value for the key, if there is one. For strict mode we probably would like get() to be declared to returning V or at most (V|undefined). So X would be constrained likewise.
In summary, this seems reasonably simple:
function get(key:K, default:(V|undefined)=undefined):(V|undefined) ...
function put(key:K, value:V, default:(V|undefined)=undefined):(V|undefined) ...
with the proviso that if the table may associate K with the value undefined then the programmer has to be careful and use "has".
Draft 2 enclosed (changelog near the top).
On 2008-03-03, at 02:26 EST, Lars Hansen wrote:
function get(key:K, default:(V|undefined)=undefined):(V| undefined) ...
If V? is shorthand for (V|null), what is the shorthand for (V|null|
undefined)? Perhaps V?@%#$! Well, at least that expresses how I feel
about a language with 'two nulls'. :P
-----Original Message----- From: P T Withington [mailto:ptwithy at gmail.com] On Behalf Of P T Withington Sent: 3. mars 2008 13:47 To: Lars Hansen Cc: Waldemar Horwat; es4-discuss at mozilla.org Subject: Re: ES4 draft: Map
On 2008-03-03, at 02:26 EST, Lars Hansen wrote:
function get(key:K, default:(V|undefined)=undefined):(V| undefined) ...
If V? is shorthand for (V|null), what is the shorthand for (V|null| undefined)? Perhaps V?@%#$! Well, at least that expresses how I feel about a language with 'two nulls'. :P
There is no shorthand for (V|null|undefined), though if V is a nullable type then (V|undefined) works just as well.
We've talked about V~ for (V|undefined). It would have a few uses in
the RI, but not enough to close the deal.
You and Lars missed my sarcasm marks. I hope there is not a
shorthand.
You missed my invisible irony mark :-P.
Thanks, I noticed that too. Will be corrected in the next draft.
How would the 'fixed' property be used, in practice? I can see a use for fixed-length vectors, but I'm unsure about vectors that can be switched between fixed and variable length by untrusted code.
Draft 3 enclosed. Changelog near the top; the only significant change is fixing the bug Erik noted in the prototype get and put methods.
Please note one open issue; the current design is probably OK but I would appreciate comments.
I still find this bad UI for people that do not use types, and remember types are supposed to be optional. Currently there is no way to create a map without providing types (not entirely true, see below). Neither of the following works as we have speced it today:
var m = new Map; var m2 = Map();
the closest thing would be to do
var m3 = Map({});
but that is pretty ugly.
What I would like is that the type params are optional and if left out treated as the any type. Another simpler option is to make the argument to meta::invoke to be optional and if left out an empty Map.<EnumerableId, *> is returned.
2008/3/11 Lars Hansen <lhansen at adobe.com>:
-----Original Message----- From: Erik Arvidsson [mailto:erik.arvidsson at gmail.com] Sent: 11. mars 2008 11:25 To: Lars Hansen Cc: es4-discuss at mozilla.org Subject: Re: ES4 draft: Map
I still find this bad UI for people that do not use types, and remember types are supposed to be optional.
I agree, default type parameters would be nice.
Currently there is no way to create a map without providing types (not entirely true, see below). Neither of the following works as we have speced it today:
var m = new Map; var m2 = Map();
The latter should work, thanks for catching the bug.
the closest thing would be to do
var m3 = Map({});
but that is pretty ugly.
And very likely it will become illegal, since we think that class statics will only be available on instantiated classes (unlike now, when they are available only on uninstantiated classes), so you'd have to write
var m3 = Map.<string,int>()
or worse.
What I would like is that the type params are optional and if left out treated as the any type. Another simpler option is to make the argument to meta::invoke to be optional and if left out an empty Map.<EnumerableId, *> is returned.
We discussed default type parameters a few times, but it was always thrown out. I think the chief reason for that was that we always tried to make it work in the context of Array (so that Array could be both what it is in ES3 and something typed besides). That was a non-starter, and rightly so.
In any case, this was the sketch we were toying with:
class Map.<K=EnumerableId, V=*> { }
One issue that I remember was the question of the meaning of an expression that names the type without parameters. For example, if we want
new Map()
to mean
new Map.<EnumerableId,*>()
(and this is what you're asking for) then what do we mean when we say simply
Map
? Do we mean to pass the uninstantiated class object around or do we mean to instantiate it with the default parameters? The former is the obvious interpretation, but then what about
x = Map new x()
Does that instantiate, and so on? No doubt all these details could be resolved, we just thought that some things should be postponed to ES5.
I'm enclosing the draft for the Map class. Please comment.