ES4 draft: Map

# Lars Hansen (18 years ago)

I'm enclosing the draft for the Map class. Please comment.

# ekameleon (18 years ago)

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>:

# Lars Hansen (18 years ago)

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
# ekameleon (18 years ago)

Hello :)

Ok sorry :)

I'm going to search the old discussions about this in the mailing list :)

EKA+ :)

2008/2/29, Lars Hansen <lhansen at adobe.com>:

# Erik Arvidsson (18 years ago)

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>:

# Michael O'Brien (18 years ago)

An HTML attachment was scrubbed... URL: esdiscuss/attachments/20080229/a483f965/attachment-0002

# Lars T Hansen (18 years ago)

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.

# Lars Hansen (18 years ago)

-----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.)

# Waldemar Horwat (18 years ago)

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
# Lars Hansen (18 years ago)

-----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.

# Lars Hansen (18 years ago)

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".

# Lars Hansen (18 years ago)

Draft 2 enclosed (changelog near the top).

# P T Withington (18 years ago)

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

# Lars Hansen (18 years ago)

-----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.

# Brendan Eich (18 years ago)

We've talked about V~ for (V|undefined). It would have a few uses in
the RI, but not enough to close the deal.

# P T Withington (18 years ago)

You and Lars missed my sarcasm marks. I hope there is not a
shorthand.

# Brendan Eich (18 years ago)

You missed my invisible irony mark :-P.

# Erik Arvidsson (18 years ago)

prototype get and put are missing the new optional notfound param

2008/3/3 Lars Hansen <lhansen at adobe.com>:

# Lars Hansen (18 years ago)

Thanks, I noticed that too. Will be corrected in the next draft.

# Jon Zeppieri (18 years ago)

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.

# Lars Hansen (18 years ago)

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.

# Erik Arvidsson (18 years ago)

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>:

# Lars Hansen (18 years ago)

-----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.