Separating a Hash type from Object
On Monday 30 April 2007 11:59 am, Brad Fults wrote:
As has been previously noted [1] and should be general knowledge, the confusion and collision between Object-as-hash and Object-as-inherited-from is sometimes painful in ES3.
I looked through the latest ES4 spec and proposals [2] but didn't see anything about changing the way hashes are handled. Are there any plans to derive a Hash type from Object which would handle what are now object literals (as hash literals)? If not, can there be?
There has been a proposal regarding this:
http://developer.mozilla.org/es4/proposals/enumerability.html
ISTM that exposing ES3's internal [DontEnum] to user-set properties fixes the issue without removing the (useful) flexibility of the object/hash duality.
This would solve many of the contemporary problems with Object (like extending Object.prototype to include methods like .keys(), .values(), etc.). I'm interested to hear others' thoughts on this.
Idiomatic ES3 code uses the object/hash duality to good effect. It's one of the things I miss most when returning to a language without it (e.g., Python).
On 4/30/07, Alex Russell <alex at dojotoolkit.org> wrote:
There has been a proposal regarding this:
http://developer.mozilla.org/es4/proposals/enumerability.html
Ah, yes, DontEnum seems to solve the immediate problem of extending Object.prototype. Thanks.
the (useful) flexibility of the object/hash duality. [...snip...] Idiomatic ES3 code uses the object/hash duality to good effect.
I'm (honestly) curious to see some examples of useful flexibility and good effects of the object/hash duality. I think I'm looking at the issue from a different perspective and would benefit from a different and concrete viewpoint that supports the duality.
Thanks.
On Apr 30, 2007, at 2:20 PM, Alex Russell wrote:
There has been a proposal regarding this:
developer.mozilla.org/es4/proposals/enumerability.html
ISTM that exposing ES3's internal [DontEnum] to user-set properties fixes the issue without removing the (useful) flexibility of the object/hash duality.
This fixes for-in loops, more or less. I'd also like to see a Hash
class with a custom iterator::get that yields only instance
properties. Relying only on propertyIsEnumerable is not enough, I
think, because naive script-writers won't necessarily know to mark
their extensions to Object so as to keep their chocolate out of your
peanut butter.
However, it doesn't fix the lack of key safety.
var foo = {}; foo + ""; //-> "[object Object]"
foo.toString = "bar"; foo + ""; //-> Error: Can't convert foo to primitive type
This bothers me. The original "toString" property can still be
accessed with an intrinsic:call, but that doesn't help with the
automatic string coercion in the example above.
I think this has been discussed before on this ML, but nobody has
come up with an easy answer here. Ideally, speaking from a narrow
perspective, I'd like to be able to distinguish dot notation from
bracket notation...
foo["toString"]; //-> "bar";
foo.toString; //-> function() {}
... but I fear that's too large a can of worms to open.
On 2007-04-30, at 17:43 EDT, Andrew Dupont wrote:
On Apr 30, 2007, at 2:20 PM, Alex Russell wrote:
There has been a proposal regarding this:
developer.mozilla.org/es4/proposals/enumerability.html
ISTM that exposing ES3's internal [DontEnum] to user-set properties fixes the issue without removing the (useful) flexibility of the object/hash duality.
Alex, can you say more about how this duality is useful? An example,
perhaps?
This fixes for-in loops, more or less. I'd also like to see a Hash class with a custom iterator::get that yields only instance properties. Relying only on propertyIsEnumerable is not enough, I think, because naive script-writers won't necessarily know to mark their extensions to Object so as to keep their chocolate out of your peanut butter.
Agreed. This solution relies on everyone behaving.
Would another approach be to have a way to tell for to enumerate only
hasOwnProperty
properties?
for (var k in own foo) ... foreach (var i in own foo) ...
?
[This has the drawback that you cannot create 'inherited' hashes
using prototypes.]
However, it doesn't fix the lack of key safety.
var foo = {}; foo + ""; //-> "[object Object]"
foo.toString = "bar"; foo + ""; //-> Error: Can't convert foo to primitive type
This bothers me. The original "toString" property can still be accessed with an intrinsic:call, but that doesn't help with the automatic string coercion in the example above.
I think this has been discussed before on this ML, but nobody has come up with an easy answer here. Ideally, speaking from a narrow perspective, I'd like to be able to distinguish dot notation from bracket notation...
foo["toString"]; //-> "bar"; foo.toString; //-> function() {}
... but I fear that's too large a can of worms to open.
Yow! I have a better idea: generic functions -- get methods out of
instances altogether!
On Apr 30, 2007, at 2:43 PM, Andrew Dupont wrote:
However, it doesn't fix the lack of key safety.
var foo = {}; foo + ""; //-> "[object Object]"
foo.toString = "bar"; foo + ""; //-> Error: Can't convert foo to primitive type
This bothers me. The original "toString" property can still be accessed with an intrinsic:call, but that doesn't help with the automatic string coercion in the example above.
use namespace intrinsic;
does help there.
I think this has been discussed before on this ML, but nobody has come up with an easy answer here. Ideally, speaking from a narrow perspective, I'd like to be able to distinguish dot notation from bracket notation...
foo["toString"]; //-> "bar"; foo.toString; //-> function() {}
... but I fear that's too large a can of worms to open.
How about a magic namespace:
foo.direct::["toString"]
or some such? Then 'use namespace direct' would result in foo.toString
() or an implicit conversion failing if there were a foo.direct::
["toString"]. So a magic namespace may be the wrong UI. How about
special syntax?
foo#.toString foo#["toString"]
and of course
let dict = #{a:1, b:2, c:3};
?
Brendan Eich wrote:
How about a magic namespace:
foo.direct::["toString"]
or some such? Then 'use namespace direct' would result in foo.toString() or an implicit conversion failing if there were a foo.direct::["toString"]. So a magic namespace may be the wrong UI. How about special syntax?
foo#.toString foo#["toString"]
and of course
let dict = #{a:1, b:2, c:3};
?
/be
I like it. Let me think out loud...
var foo = {}; foo.toString; //-> function() {}
foo#.toString; //-> undefined
foo.toString = "bar"; foo + "" //-> Error
foo#.["toString"]; //-> undefined
foo#.toString = "bar"; foo#.toString; //-> "bar";
delete foo.toString; //-> true
foo#.toString; //-> "bar";
delete foo#.toString; foo#.toString; //-> undefined
If I'm correct in all these assumptions, then this seems like a good solution. I also like PT's "for..in own" syntax for discovering which keys are defined this way.
On May 1, 2007, at 9:41 PM, Andrew Dupont wrote:
Brendan Eich wrote:
How about a magic namespace:
foo.direct::["toString"]
or some such? Then 'use namespace direct' would result in foo.toString() or an implicit conversion failing if there were a foo.direct::["toString"]. So a magic namespace may be the wrong UI. How about special syntax?
foo#.toString foo#["toString"]
and of course
let dict = #{a:1, b:2, c:3};
?
/be I like it. Let me think out loud...
var foo = {}; foo.toString; //-> function() {} foo#.toString; //-> undefined
So far so good.
foo.toString = "bar";
This must create a direct property in the object referenced by foo,
which shadows Object.prototype.toString. So:
foo + "" //-> Error
agreed...
foo#.["toString"]; //-> undefined
This isn't right, given the shadowing rule of JS/ES.
foo#.toString = "bar"; foo#.toString; //-> "bar"; delete foo.toString; //-> true foo#.toString; //-> "bar";
I'm confused -- do you intend that foo#.toString name a property in
no namespace with identifier 'toString' in some object, or a property
in a hidden namespace with local name 'toString'?
delete foo#.toString; foo#.toString; //-> undefined
This seems consistent no matter what.
If I'm correct in all these assumptions, then this seems like a good solution. I also like PT's "for..in own" syntax for discovering which keys are defined this way.
That thought has occurred, but it doesn't match the |in| operator. A
custom iterator factory might be better; there are lots of ways to
iterate.
Brendan Eich wrote:
I'm confused -- do you intend that foo#.toString name a property in
no namespace with identifier 'toString' in some object, or a property
in a hidden namespace with local name 'toString'?
The latter was my interpretation. But you're saying that the #. operator would simply look at the subset of an object's properties that are defined on the instance?
That's more reasonable than creating a whole new property namespace. It doesn't solve the string coercion problem, though. Combining the #. operator with "use namespace intrinsic;" would, but that means the developer would have to opt into key safety.
I still think the idea is promising, though, and would be useful even with this drawback -- and far more practical than what I originally thought you meant.
On May 1, 2007, at 10:14 PM, Andrew Dupont wrote:
Brendan Eich wrote:
I'm confused -- do you intend that foo#.toString name a property in no namespace with identifier 'toString' in some object, or a property in a hidden namespace with local name 'toString'?
The latter was my interpretation. But you're saying that the #.
operator would simply look at the subset of an object's properties that are defined on the instance?
Yes -- hence the direct:: namespace conceit that lost to #. #[ #{.
That's more reasonable than creating a whole new property
namespace. It doesn't solve the string coercion problem, though. Combining the #. operator with "use namespace intrinsic;" would, but that means the developer would have to opt into key safety.
The key safety problems you cite are (a) matching toString or another
indirect (prototype-owned) property; (b) setting toString in the
directly referenced object to some value not a toString function.
You're right, #. addresses only (a).
To address (b) would seem to require opting in as you note, or
changing the usual rules for hashes (objects created via #{...}) to
look for methods in a special namespace (intrinsic, or perhaps
function as in SpiderMonkey).
This is a fair amount of magic for the Hash class, and some of it
(the function namespace) might want to be abstracted over any class,
since E4X's XML class in SpiderMonkey wants the ability to access XML
methods via, e.g., function::elements.
Leaving (b) unsolved without opt-in (use namespace intrinsic), we
could avoid a Hash class with magic method lookup rules altogether,
and add #. #[ #{ as shorthand, where obj#.ident, obj#[expr] ,
obj#.ns::ident, and obj#.ns::[expr] would be variations on the
corresponding unsharp (hash-free) operators, which would work on any
kind of object by looking only in the directly referenced object, not
any prototype.
Brendan Eich wrote:
How about a magic namespace:
foo.direct::["toString"]
or some such? Then 'use namespace direct' would result in foo.toString () or an implicit conversion failing if there were a foo.direct:: ["toString"]. So a magic namespace may be the wrong UI. How about
special syntax?foo#.toString foo#["toString"]
and of course
let dict = #{a:1, b:2, c:3};
?
/be
As elegant as it is to use # for hashes, I'm not sure if a special syntax is needed for it, since I imagine it's usage would be limited to only certain classes. It doesn't introduce any new functionality, since we already have hasOwnProperty(). Perhaps a better way would be to allow the author to override the "[]" and "." operator in some coherent way (the approach C++ and Python take).
-Yuh-Ruey Chen
On May 1, 2007, at 11:28 PM, Yuh-Ruey Chen wrote:
As elegant as it is to use # for hashes, I'm not sure if a special syntax is needed for it, since I imagine it's usage would be
limited to only certain classes. It doesn't introduce any new functionality,
since we already have hasOwnProperty(). Perhaps a better way would be to
allow the author to override the "[]" and "." operator in some coherent way (the approach C++ and Python take).
Indeed, #. etc. is just a thought experiment. But just providing the
ability to override . and [] wouldn't help so much without a default
implementation -- it would force everyone wanting a hash unpolluted
by Object.prototype to reinvent the wheel.
So let's say there's a standard Hash or Dictionary class, with
operator static functions for . and []. Then the missing piece is
initializer syntax. We've talked about the thin nature of any #{...}
syntax, since
let myDict : Dictionary = {...};
could perhaps optimize to avoid constructing an Object instance, then
converting it to the Dictionary type due to the type annotation on
myDict (perhaps, because object initialiser evaluation in ES3 is
observable if one wraps or overrides the Object constructor -- see
the recent JSON security blog threads).
None of this is yet compelling enough, or coherent/general enough, to
add to ES4. But work with me here...
use namespace intrinsic;
does help there.
I don't think this is an answer. It solves the problem, but I doubt most JS developers would think of doing that until after they actually encountered the problem with live data. A dedicated hash object would solve the problem simply by being the obvious tool to use.
Peter
for me I see that as duality between strict and non-strict mode
in strict mode we have statement as internal/private/public/etc..
but for non-strict mode we don't have such things so to handdle those object as hash I would prefer to have access to DontEnum() / ReadOnly() / DontDelete() kind of functions
and maybe using something as ASSetPropflags from flash implementation could be more practical (see: osflash.org/flashcoders/undocumented/assetpropflags )
for the record, one thing I hated a lot from the JScript.NET implementation was to access such hash with [] and impossible to use .
maybe I don't see all the implications, but on object Object we should keep the shadowing mecanism as it was in ES3 and just use DontEnum() (or more powerfull functions) to hide what we don't want to be enumerable.
If it may be of any use, in environments like AS1/AS2 I use the ASSetPropflags to change the enumerability in JS, I just use hasOwnProperty to be sure the prop is defined on the instance and not inherited.
zwetan
On 2007-05-02, at 02:40 EDT, Brendan Eich wrote: [...]
Indeed, #. etc. is just a thought experiment.
I do think there needs to be a primitive Hash type. Otherwise we
doom users to trying to invent their own and hitting all the various
pitfalls that have been enumerated on this thread.
The safety issue is that methods are visible as properties of an
instance. Putting the methods in a special namespace seems kludgey
to me. What is the benefit of methods being properties of an
instance? What if they were not?
Another thought experiment:
What if foo.bar(...)
was syntactic sugar for bar[typeof foo].apply (foo, ...)
. Oh, wait, that's not quite right. Guess I have to
invent generic functions. Hm.
On May 2, 2007, at 1:40 AM, Brendan Eich wrote:
Indeed, #. etc. is just a thought experiment. But just providing
the ability to override . and [] wouldn't help so much without a
default implementation -- it would force everyone wanting a hash
unpolluted by Object.prototype to reinvent the wheel.
And there's the rub: how do we make a default implementation without
introducing too much magic? No matter how we do it, a Hash class
would introduce a completely different relationship between an object
and its properties.
Reinventing the wheel is less surprising to developers because it's
their wheel and they know how it works. But I think the initial
unpleasantness of special-casing Hash is better than the ongoing pain
of each developer writing his own implementation of hashes.
I'm entirely in favor of a way to override "." and "[]", whether or
not ES4 introduces a magic Hash class. That, at least, gives the
developer a chance to solve the problem on her own.
Andrew
On May 2, 2007, at 4:58 AM, P T Withington wrote:
On 2007-05-02, at 02:40 EDT, Brendan Eich wrote: [...]
Indeed, #. etc. is just a thought experiment.
I do think there needs to be a primitive Hash type. Otherwise we doom users to trying to invent their own and hitting all the various pitfalls that have been enumerated on this thread.
I've agreed repeatedly, but without a sufficiently winning proposal
(which I'm explicitly seeking here with help from y'all), it's not
going to happen for ES4.
The safety issue is that methods are visible as properties of an instance. Putting the methods in a special namespace seems kludgey to me. What is the benefit of methods being properties of an instance? What if they were not?
Backward incompatible, requiring opt-in versioning and doubling
brainprint. Why is this important to change incompatibly? Note that
it's not just methods that make for the safety issue. There may be
properties with other than function value in a prototype object.
Another thought experiment:
What if
foo.bar(...)
was syntactic sugar forbar[typeof foo].apply (foo, ...)
. Oh, wait, that's not quite right. Guess I have to invent generic functions. Hm.
We have generic functions (Array.map, etc.). That's not the issue.
Compatibility with ES1-3, as well as with standard OOP dogma, says
that methods are called via obj.foo(). You could argue that should be
sugar for some different dispatch mechanism, but ES1-3 do not
distinguish methods from other properties. It doesn't matter whether
they're delegated to a prototype, or directly in the object at hand.
On May 2, 2007, at 3:35 AM, Peter Hall wrote:
use namespace intrinsic;
does help there.
I don't think this is an answer. It solves the problem, but I doubt most JS developers would think of doing that until after they actually encountered the problem with live data. A dedicated hash object would solve the problem simply by being the obvious tool to use.
You're right.
I'm wondering what is so wrong with Hash.set(key, value) and Hash.get(key)....
Peter
On May 2, 2007, at 11:44 AM, Peter Hall wrote:
I'm wondering what is so wrong with Hash.set(key, value) and
Hash.get(key)....
Nothing's wrong, but the "rightness" of object literals in
particular, and . or [] for accessing values by key, will make
anything like this less successful than you might hope. Syntax is the
UI, it matters.
We actually started down this road at a recent meeting, and ran into
another, non-syntactic issue: often one wants weak reference support
for keys, and sometimes even for values. Flash's Dictionary class has
a "weakKeys" flag parameter to its ctor. There's lots of prior art
here -- Allen Wirfs-Brock cited Barry Hayes's Ephemerons (http://
portal.acm.org/citation.cfm?id=263733&coll=portal&dl=ACM), for example.
This complexity again made us shy away from any late-breaking
significant feature. Adding GC requirements on all implementations
needs to be done with care, and with enough time to implement and test.
On 2007-05-02, at 13:53 EDT, Brendan Eich wrote:
On May 2, 2007, at 4:58 AM, P T Withington wrote:
On 2007-05-02, at 02:40 EDT, Brendan Eich wrote: [...]
Indeed, #. etc. is just a thought experiment.
I do think there needs to be a primitive Hash type. Otherwise we doom users to trying to invent their own and hitting all the various pitfalls that have been enumerated on this thread.
I've agreed repeatedly, but without a sufficiently winning proposal (which I'm explicitly seeking here with help from y'all), it's not going to happen for ES4.
Have you considered Hash being a new native type with its own rules
for ToPrimitive, ToString, and ToObject?
On May 2, 2007, at 12:56 PM, P T Withington wrote:
Have you considered Hash being a new native type with its own rules for ToPrimitive, ToString, and ToObject?
We have considered a native Dictionary class, as I reported recently.
It lacked sugar; it didn't support weak refs. We stepped back and
deferred it.
Because Dictioinary required users to call has, get and set methods,
no changes to avoid bad shadowing of toString and valueOf arose with
the proposal.
On May 2, 2007, at 9:40 AM, Andrew Dupont wrote:
I'm entirely in favor of a way to override "." and "[]", whether or not ES4 introduces a magic Hash class. That, at least, gives the developer a chance to solve the problem on her own.
Wouldn't catchalls effectively serve this purpose?
dynamic class Hash { function set *(ident, val) { this["" + ident] = val; } function get *(ident) { return this["" + ident]; } }
Has this thread dropped again? That's too bad. It seems like we
keep going in this circle:
- we need a base Dictionary class
- in order to be successful, it needs "good UI" and perhaps weak refs
- there's no syntax proposed for this
- it's awfully late for any big changes anyway
- but we need a Dictionary class
I take issue with #2. It's my impression that the veteran JS
developers on this list have all stated a strong desire for key-safe
storage, and I believe that they would all agree that a Dictionary
without syntactic sugar and weak refs is better than nothing at all.
Do any JS hackers here disagree?
What is the danger in specifying a hobbled Dictionary class for now,
with the hope that better syntactical goodness and weak refs can be
added in a later version?
I agree with Neil. A sugarless dictionary is better than no
dictionary at all.
On 5/5/07, P T Withington <ptw at pobox.com> wrote:
I agree with Neil. A sugarless dictionary is better than no dictionary at all.
On 2007-05-05, at 17:40 EDT, Neil Mix wrote:
Has this thread dropped again? That's too bad. It seems like we keep going in this circle:
- we need a base Dictionary class
- in order to be successful, it needs "good UI" and perhaps weak refs
- there's no syntax proposed for this
- it's awfully late for any big changes anyway
- but we need a Dictionary class
I take issue with #2. It's my impression that the veteran JS developers on this list have all stated a strong desire for key-safe storage, and I believe that they would all agree that a Dictionary without syntactic sugar and weak refs is better than nothing at all. Do any JS hackers here disagree?
What is the danger in specifying a hobbled Dictionary class for now, with the hope that better syntactical goodness and weak refs can be added in a later version?
I'm pretty sure I agree as well, but would like to see a clean proposal for how exactly a "hobbled Dictionary class" would work.
Thanks.
Neil Mix wrote:
Has this thread dropped again? That's too bad. It seems like we keep going in this circle:
- we need a base Dictionary class
- in order to be successful, it needs "good UI" and perhaps weak refs
- there's no syntax proposed for this
- it's awfully late for any big changes anyway
- but we need a Dictionary class
I take issue with #2. It's my impression that the veteran JS developers on this list have all stated a strong desire for key-safe storage, and I believe that they would all agree that a Dictionary without syntactic sugar and weak refs is better than nothing at all.
Do any JS hackers here disagree?
No, not at all. To dissect this further: I don't mind having to "opt into" key safety by adopting an uglier syntax, but I wouldn't want to give up the convenience of an Object when I don't need to be that cautious.
There are ten thousand ways to make key-safe Dictionaries in ES3
and what about the Dictionary class in the Tamarin project ? lxr.mozilla.org/mozilla/source/js/tamarin/extensions/Dictionary.as
this one could go in the builtin class no ?
Zwetan, This is what we are talking about. But the es4 spec cannot make assumptions about an implementation's GC, which may (or may not) be necessary - at least for weak keys - but it's getting late in the game to have to find that out. That's a summary, but search the list archives...
In general ES4 cannot take things, just because they have been implemented in Tamarin. ES4 is supposed to be implementation-independant. There are many factors that could make a feature harder or easier (or just more or less desirable) to implement in a given implementation - choice of GC seems to be a big factor in this instance, but there are plenty of others.
Peter
On 5/7/07, Peter Hall <peter.hall at memorphic.com> wrote:
Zwetan, This is what we are talking about. But the es4 spec cannot make assumptions about an implementation's GC, which may (or may not) be necessary - at least for weak keys - but it's getting late in the game to have to find that out. That's a summary, but search the list archives...
In general ES4 cannot take things, just because they have been implemented in Tamarin. ES4 is supposed to be implementation-independant. There are many factors that could make a feature harder or easier (or just more or less desirable) to implement in a given implementation - choice of GC seems to be a big factor in this instance, but there are plenty of others.
ok fair enougth, I was under the assumption that Tamarin will become a de facto block for any ES4 implementation.
But what I was sugesting is merely add a predefined Dictionary class as what have been done with the ByteArray class developer.mozilla.org/es4/proposals/bytearray.html
On 5/7/07, zwetan <zwetan at gmail.com> wrote:
On 5/7/07, Peter Hall <peter.hall at memorphic.com> wrote:
Zwetan, This is what we are talking about. But the es4 spec cannot make assumptions about an implementation's GC, which may (or may not) be necessary - at least for weak keys - but it's getting late in the game to have to find that out. That's a summary, but search the list archives...
In general ES4 cannot take things, just because they have been implemented in Tamarin. ES4 is supposed to be implementation-independant. There are many factors that could make a feature harder or easier (or just more or less desirable) to implement in a given implementation - choice of GC seems to be a big factor in this instance, but there are plenty of others.
ok fair enougth, I was under the assumption that Tamarin will become a de facto block for any ES4 implementation.
But what I was sugesting is merely add a predefined Dictionary class as what have been done with the ByteArray class developer.mozilla.org/es4/proposals/bytearray.html
That is what is being discussed. There is at present no credible proposal for new syntax or a new primitive "Hash" type.
Peter Hall succinctly make the two important points: there are design issues to be resolved (notably whether weak refs are required to make a Dictionary useful), and probably more importantly, we're way past any reasonable feature deadline. (ByteArray was arguably accepted after the feature deadline; but ByteArray was special, and violating the deadline again does not make a bad situation good ;-)
Following is the proposed API for the dictionary class, note this proposal has been rejected for ES4. It would be rejected even without the provision for weak refs. I'm including it only to make the point that, like a lot of other data structures, it can be implemented in portable ES4 and does not need to be part of the language. (That happens not to be the case for ByteArray, whose entire reason for existence is storage efficiency coupled with performance.)
class Dictionary.<K,V> { function Dictionary(weak: boolean = false) public function from(x : Object!) public function size() : uint public function get(key: K) : V? public function put(key:K, value:V) : void public function has(key:K) : boolean public function remove(key:K) : boolean iterator function get(deep: boolean = false) : iterator::IteratorType.<K> iterator function getKeys(deep: boolean = false) : iterator::IteratorType.<K> iterator function getValues(deep: boolean = false) : iterator::IteratorType.<V> iterator function getItems(deep: boolean = false) : iterator::IteratorType.<[K,V]> }
On 2007-05-07, at 07:47 EDT, Lars T Hansen wrote:
it can be implemented in portable ES4 and does not need to be part of the language.
Could you expand on this tantalizing hint? Do you mean because es4
provides intrisic::hashcode
? But doesn't this solution fail the
efficiency test that got ByteArray in?
Could you expand on this tantalizing hint? Do you mean because es4 provides
intrisic::hashcode
? But doesn't this solution fail the efficiency test that got ByteArray in?
But was efficiency ever argued as an essential part of the feature? I haven't seen any discussion around that...
Peter
On 2007-05-07, at 08:37 EDT, Peter Hall wrote:
Could you expand on this tantalizing hint? Do you mean because es4 provides
intrisic::hashcode
? But doesn't this solution fail the efficiency test that got ByteArray in?But was efficiency ever argued as an essential part of the feature? I haven't seen any discussion around that...
Obliquely: because Object is native, (hence efficient), and looks
like a Dictionary, but is a garden path.
On 5/7/07, Lars T Hansen <lth at acm.org> wrote: [snip..]
Following is the proposed API for the dictionary class, note this proposal has been rejected for ES4. It would be rejected even without the provision for weak refs. I'm including it only to make the point that, like a lot of other data structures, it can be implemented in portable ES4 and does not need to be part of the language. (That happens not to be the case for ByteArray, whose entire reason for existence is storage efficiency coupled with performance.)
class Dictionary.<K,V> { function Dictionary(weak: boolean = false) public function from(x : Object!) public function size() : uint public function get(key: K) : V? public function put(key:K, value:V) : void public function has(key:K) : boolean public function remove(key:K) : boolean iterator function get(deep: boolean = false) : iterator::IteratorType.<K> iterator function getKeys(deep: boolean = false) : iterator::IteratorType.<K> iterator function getValues(deep: boolean = false) : iterator::IteratorType.<V> iterator function getItems(deep: boolean = false) : iterator::IteratorType.<[K,V]> }
so if this API can be implemented in ES4, where is the problem ?
it's hard to follow here why people even discussing all that, as I see it if such API has been rejected, what are the chances for a new syntax as obj.#toString to be accepted ?
maybe adding to catchall ( developer.mozilla.org/es4/proposals/catchalls.html ) would have better chances to be accepted ?
for ex: function get *(ident), the catchall getter. (return the value) -> function get2 *(val) (return the ident)
function intrinsic::get(ident), the non-overridable universal property getter. -> function intrinsic::get2(val)
afaik, the Dictionary class in AS3 is very usefull to avoid O(n) search of ident, maybe I don't fully understand the whole problem here, but for hashes speed sake some magic O(1) access to the ident would be more than welcome.
On 5/7/07, zwetan <zwetan at gmail.com> wrote:
Hi Lars, I don't know if your answer was mean only to me or the list, but as I don't see it on the list I answer to you directly.
I'm not always convinced that gmail's "reply" defaults are right, but anyhow it's my fault, it was intended for the list (hereby cc'd).
On 5/7/07, Lars T Hansen <lth at acm.org> wrote:
On 5/7/07, zwetan <zwetan at gmail.com> wrote:
On 5/7/07, Lars T Hansen <lth at acm.org> wrote: [snip..]
Following is the proposed API for the dictionary class, note this proposal has been rejected for ES4. It would be rejected even without the provision for weak refs. I'm including it only to make the point that, like a lot of other data structures, it can be implemented in portable ES4 and does not need to be part of the language. (That happens not to be the case for ByteArray, whose entire reason for existence is storage efficiency coupled with performance.)
class Dictionary.<K,V> { function Dictionary(weak: boolean = false) public function from(x : Object!) public function size() : uint public function get(key: K) : V? public function put(key:K, value:V) : void public function has(key:K) : boolean public function remove(key:K) : boolean iterator function get(deep: boolean = false) : iterator::IteratorType.<K> iterator function getKeys(deep: boolean = false) : iterator::IteratorType.<K> iterator function getValues(deep: boolean = false) : iterator::IteratorType.<V> iterator function getItems(deep: boolean = false) : iterator::IteratorType.<[K,V]> }
so if this API can be implemented in ES4, where is the problem ?
It depends on whose job you think it is to provide a Dictionary, I guess. The language spec will almost certainly not contain this class, so every user will have to build his own or rely on some third-party library. Some people probably do not like that (I'm not sure I do). But at least that's possible.
my main concern is to be able to build such Dictionary class with the ES4 language itself.
And if I take the only real-world example that I know of now, which is AS3 compiled with Flex, if the Dictionary class was not there, it would be kind of difficult to implement one.
Right. The AS3 Dictionary class was discussed a little in the committee, and we weren't unanimously sure that it has the interface you want to have in that kind of a class, even though -- as I remember it -- it allows you to access the object using convenient dereferencing a la obj[name].
As I see it now, ES4 just define the basis of the language, not a standard framework or standard library around it, and it can be fine, if developers can build their own library, provided the language give them enougth access to do that.
That's the hope.
Some people also don't like that you have to write code that looks a lot like Java instead of using super-convenient syntax, and that seems to be what much of the discussion is about. For as much as I like JS syntax conveniences and would enjoy seeing one here we've been around that track several times now and we're not really getting anywhere as far as I can tell.
Personally, I think the two style can be combined, if something is missing or can not be done in a non-strict JS dynamic style, I see no problem to implement it ala Java in a strict static style, so it can be used later in a non-strict dynamic style. (hope I'm clear here)
it's hard to follow here why people even discussing all that, as I see it if such API has been rejected, what are the chances for a new syntax as obj.#toString to be accepted ?
I wouldn't put a lot of money on it.
maybe adding to catchall ( developer.mozilla.org/es4/proposals/catchalls.html ) would have better chances to be accepted ?
Not likely.
for ex: function get *(ident), the catchall getter. (return the value) -> function get2 *(val) (return the ident)
function intrinsic::get(ident), the non-overridable universal property getter. -> function intrinsic::get2(val)
afaik, the Dictionary class in AS3 is very usefull to avoid O(n) search of ident, maybe I don't fully understand the whole problem here, but for hashes speed sake some magic O(1) access to the ident would be more than welcome.
I'm sure there's something I don't understand in what you write, because a hash table (dictionary) provides O(1) access time, and no magic is necessary for that, provided you have an efficient means of generating hash codes for a value. For many applications you don't even need intrinsic::hashcode().
well, right now, with what I can access in a language as AS3, or better with some tests compiling with ASC for avmplus.exe if I try to define my own Dictionary class I can not obtain a O(1) access time, so my comment is surely flawed because I can not connect all the dots of what ES4 can really do as I got no final implementation to test with.
the same is true with hashcodes, I implemented in AS3 some hashcode routines based on Fowler/Noll/Vo, and basically it works but when it comes to object Object it can be tricky.
Yes, that's why intrinsic::hashcode has been proposed. You need that to do general object hashing efficiently.
Granted that AS3 is limited compared to what ES4 can do, but for ex if intrinsic::hashcode() did not make it into the spec, for a reason like very few application use it, people wanting to use hashcodes will be stuck and/or have to do some nasty hacks like serializing an object to bytearray, and generate the hash from that.
My point here is : if a Dictionary class can be implemented in portable ES4, great, but what if we don't have enought efficient means in the language to handle weak refs for exemple ?
Well, as it stands you don't have the tools in ES4 to implement weak refs. The most you can hope for on the user level right now is efficient, general hashing, but weak refs require machinery we have not been willing to spec.
There are lots of candidates for that machinery but (a) picking one is work we are not willing/able to do right now and (b) it's an open question whether you want to place the burden of this mechanism on the implementers. Nobody disputes the utility of weak refs, just the cost (calculated several ways).
On 07/05/07, Peter Hall <peter.hall at memorphic.com> wrote:
implemented in Tamarin. ES4 is supposed to be implementation-independant. There are many factors that could make a feature harder or easier (or just more or less desirable) to implement in a given implementation - choice of GC seems to be a big factor in this instance, but there are plenty of others.
Yet ES4 adds intrinsic::hashcode which imposes more overhead when implementation uses GC then a native Dictionary class. See recent discussion about that.
So why it is so? I.e why rejecting Dictionary while requiring intrinsic::hashcode?
, Igor
On 07/05/07, Igor Bukanov <igor at mir2.org> wrote:
On 07/05/07, Peter Hall <peter.hall at memorphic.com> wrote:
implemented in Tamarin. ES4 is supposed to be implementation-independant. There are many factors that could make a feature harder or easier (or just more or less desirable) to implement in a given implementation - choice of GC seems to be a big factor in this instance, but there are plenty of others.
Yet ES4 adds intrinsic::hashcode which imposes more overhead when implementation uses GC then a native Dictionary class. See recent ^^^^^^^^^^^^^^^^^ I meant copying Garbage Collector.
Just out of curiosity does Tamarin currently use copying GC? Kris
On May 5, 2007, at 11:40 PM, Neil Mix wrote:
Has this thread dropped again? That's too bad. It seems like we keep going in this circle:
- we need a base Dictionary class
- in order to be successful, it needs "good UI" and perhaps weak refs
- there's no syntax proposed for this
- it's awfully late for any big changes anyway
- but we need a Dictionary class
Good analysis, and thanks for keeping this pot boiling.
I take issue with #2. It's my impression that the veteran JS developers on this list have all stated a strong desire for key-safe storage, and I believe that they would all agree that a Dictionary without syntactic sugar and weak refs is better than nothing at all. Do any JS hackers here disagree?
I do. I think users will gravitate to Object because of the
initialiser syntax. I may be wrong, but it's definitely a trap that
JS hackers fall into.
So I've been arguing for a week or so, mostly with myself, that we
have just about enough in the current ES4 proposals to "do almost
everything", and with a neat syntactic sugar proposal from Lars, I
think we're done. Here's the scoop:
-
Start by satisfying the thirst for object initialiser syntax: let
dict = {a:1, b:2, ...}. -
To avoid collisions with prototype properties, use a private/ unique namespace:
private namespace u; let dict = {u::a: 1, u::b: 2, ...};
-
Since the repeated u:: defeats the purpose of (1), allow a default
namespace to be specified for all unqualified property names in the
initialiser:private namespace u; let dict = u::{a:1, b:2, ...};
-
Key-safe membership testing: dict.u::[key] or 'use namespace u;
dict[key]'.
Comments?
On 5/23/07, Brendan Eich <brendan at mozilla.org> wrote:
Start by satisfying the thirst for object initialiser syntax: let dict = {a:1, b:2, ...}.
To avoid collisions with prototype properties, use a private/ unique namespace:
private namespace u; let dict = {u::a: 1, u::b: 2, ...};
Since the repeated u:: defeats the purpose of (1), allow a default namespace to be specified for all unqualified property names in the initialiser:
private namespace u; let dict = u::{a:1, b:2, ...};
Key-safe membership testing: dict.u::[key] or 'use namespace u; dict[key]'.
Comments?
Assuming that your proposal is for actual end use of dicts and not just implementation details, very simply, that's far more complex than:
var d = {a: 1, b: 2};
and therefore won't be used as much and will be abused gratuitously. In the eyes of the novice (and in JS even the intermediate developer) your proposal looks something like:
voodoo voodoo voodoo
let dict = voodoo{a:1, b:2, ...};
I don't mean to be caustic, I simply mean to represent the novice in a case that I think should be accessible to all developers (dicts/hashes). It also has the notable pitfall of applying the namespace to the entire code block, something that would cause even more confusion among novice developers.
Would it be at all possible to handle the key safety in the Dictionary type itself (a bit of magic), leaving us with something like:
let dict:Dictionary = {a:1, b:2, ...};
This simpler and more intuitive syntax would (I think) be much more likely to be used and not abused by all levels of developers. Though if this syntax were feasible I'd advocate for naming the type either Dict or Hash for brevity's sake:
let myHash:Hash = {a:1, b:2, ...};
So, {a:1} would still represent an Object literal, but when a type hint of Dict/Hash is used it becomes a Dict/Hash initializer which has key safety.
Thoughts? Let me know if I'm completely off base.
Thanks.
On May 5, 2007, at 11:40 PM, Neil Mix wrote:
- in order to be successful, it needs "good UI" and perhaps weak refs [- - -]
I take issue with #2. It's my impression that the veteran JS developers on this list have all stated a strong desire for key-safe storage, and I believe that they would all agree that a Dictionary without syntactic sugar and weak refs is better than nothing at all. Do any JS hackers here disagree?
On 23/05/07, Brendan Eich <brendan at mozilla.org> wrote:
I do. I think users will gravitate to Object because of the initialiser syntax. I may be wrong, but it's definitely a trap that JS hackers fall into.
The initialiser syntax is certainly better than having to do many separate assignments to an object, that's for sure.
On 23/05/07, Brendan Eich <brendan at mozilla.org> wrote:
So I've been arguing for a week or so, mostly with myself, that we have just about enough in the current ES4 proposals to "do almost everything", and with a neat syntactic sugar proposal from Lars, I think we're done. Here's the scoop:
Start by satisfying the thirst for object initialiser syntax: let dict = {a:1, b:2, ...}.
To avoid collisions with prototype properties, use a private/ unique namespace:
private namespace u; let dict = {u::a: 1, u::b: 2, ...};
Since the repeated u:: defeats the purpose of (1), allow a default namespace to be specified for all unqualified property names in the initialiser:
private namespace u; let dict = u::{a:1, b:2, ...};
Key-safe membership testing: dict.u::[key] or 'use namespace u; dict[key]'.
Comments?
Would it be possible to somehow make that into something that works in expression contexts too, instead of just statement context? Object initialisers are very handy in expression contexts, and I feel you'd want this to be usable in the same way too.
Also, you'd want to be able to send a dictionary to some function that have no idea about the setting up of the dictionary, including the namespace. I've not read up about the namespace handling, so I don't know if this is already provided somehow, but I'd like to have a way to access dictionary keys that is universal.
On 23/05/07, Brad Fults <bfults at gmail.com> wrote:
Assuming that your proposal is for actual end use of dicts and not just implementation details, very simply, that's far more complex than:
var d = {a: 1, b: 2};
and therefore won't be used as much and will be abused gratuitously. In the eyes of the novice (and in JS even the intermediate developer) your proposal looks something like:
voodoo voodoo voodoo let dict = voodoo{a:1, b:2, ...};
Well, the added complexity isn't that very large if you ask me. As soon as a developer gets used to namespaces, they would understand it perfectly well. The problem I see with it is that we want to be able to make functions that can take any dictionary and do some work on it, without having any special knowledge of which namespace that particular dictionary uses.
I don't mean to be caustic, I simply mean to represent the novice in a case that I think should be accessible to all developers (dicts/hashes). It also has the notable pitfall of applying the namespace to the entire code block, something that would cause even more confusion among novice developers.
If the syntax still allow making specific properties in the literal belong to another namespace, is it that much different? That is, if it simply changes the default namespace properties are placed in?
On 5/23/07, Brendan Eich <brendan at mozilla.org> wrote:
private namespace u; let dict = u::{a:1, b:2, ...};
Earlier you suggested this... let dict : Dictionary = {a:1, b:2, ...};
...which is shorter.
- Key-safe membership testing: dict.u::[key] or 'use namespace u; dict[key]'.
Comments?
Again, dict.get(key) is clearer and just as short.
If I'm writing a function that takes a dictionary as a parameter (e.g. "options"), how do I know what namespace to use when accessing it?
What would be the equivalent of Java's keys() and containsKey() methods?
I think a Dictionary class is the right thing.
On May 23, 2007, at 6:11 PM, Brad Fults wrote:
Assuming that your proposal is for actual end use of dicts and not just implementation details, very simply, that's far more complex than:
var d = {a: 1, b: 2};
That's already defined by ES3 and can't be changed compatibly.
and therefore won't be used as much and will be abused gratuitously. In the eyes of the novice (and in JS even the intermediate developer) your proposal looks something like:
voodoo voodoo voodoo let dict = voodoo{a:1, b:2, ...};
I don't mean to be caustic, I simply mean to represent the novice in a case that I think should be accessible to all developers (dicts/hashes).
Since we cannot redefine object initialiser syntax, I'm not sure what
alternative you would prefer. It's one thing to say "we need a
Dictionary nominal type". It's another to say "we want incompatible
change to object initialiser syntax". The latter will get you nowhere
fast. The former may be good for some cases, but it runs into the
weak keys or ephemerons issue quickly.
It also has the notable pitfall of applying the namespace to the entire code block, something that would cause even more confusion among novice developers.
How so?
Would it be at all possible to handle the key safety in the Dictionary type itself (a bit of magic), leaving us with something like:
let dict:Dictionary = {a:1, b:2, ...};
This simpler and more intuitive syntax would (I think) be much more likely to be used and not abused by all levels of developers. Though if this syntax were feasible I'd advocate for naming the type either Dict or Hash for brevity's sake:
let myHash:Hash = {a:1, b:2, ...};
Sure, we've been over this ground. It can be done with something like
catchalls and a private namespace, in ES4 itself (no native magic
required). If you ignore the weak reference questions that it begs,
the only remaining challenge for ES4 is to agree on the API.
So, {a:1} would still represent an Object literal, but when a type hint of Dict/Hash is used it becomes a Dict/Hash initializer which has key safety.
Thoughts? Let me know if I'm completely off base.
I think you are right to argue that a short type annotation is better
than both a private namespace and a u:: in front of the opening
brace. But how much better, without other support such as weak keys
(and values) and API elaboration that is probably best left to the
library ecosystem.
We aren't going to fit weak refs into ES4, so if we can converge on
the minimal API and implement it using namespaces and catchalls (not
hashcode and chained hash tables implemented on top of objects!),
then it perhaps could make ES4 on a wing and a prayer.
On 2007-05-23, at 09:54 EDT, Brendan Eich wrote:
Comments?
I don't like the namespace hack -- it's too whacky. Looks like a
hammer in search of a nail. Quoting from an earlier message to the
list:
On 2007-05-02, at 02:40 EDT, Brendan Eich wrote:
So let's say there's a standard Hash or Dictionary class, with operator static functions for . and []. Then the missing piece is initializer syntax. We've talked about the thin nature of any #{...} syntax, since
let myDict : Dictionary = {...};
could perhaps optimize to avoid constructing an Object instance, then converting it to the Dictionary type due to the type annotation on myDict (perhaps, because object initialiser evaluation in ES3 is observable if one wraps or overrides the Object constructor -- see the recent JSON security blog threads).
None of this is yet compelling enough, or coherent/general enough, to add to ES4. But work with me here...
I think you already answered your own question. The length of this
thread seems compelling enough.
Personally, I would prefer a built-in, efficient Dict class with get/
set (and the possibility of . and [] being overridden) and hints
about how to optimize instantiating a Dict from an object literal
(taking only the objects 'own' properties) over the 'namespace voodoo'.
That's my 2p.
On May 24, 2007, at 3:37 AM, P T Withington wrote:
On 2007-05-23, at 09:54 EDT, Brendan Eich wrote:
Comments?
I don't like the namespace hack -- it's too whacky. Looks like a hammer in search of a nail.
Or a hammer you want in your toolbox for other reasons (object
initialisers with all ids in a certain namespace -- otherwise you''ll
use the :: hammer on each and every property initialiser, and hit
your thumb).
However implemented, a standard Dict class does seem inevitable.
Personally, I would prefer a built-in, efficient Dict class with get/ set (and the possibility of . and [] being overridden) and hints about how to optimize instantiating a Dict from an object literal (taking only the objects 'own' properties) over the 'namespace
voodoo'.
The meta static function convert for that class could do the
conversion, but it wouldn't be able to optimize away the object
initialiser. It would use hasOwnProperty carefully to avoid prototype
pollution.
Weak keys worries?
On 2007-05-24, at 02:36 EDT, Brendan Eich wrote:
Weak keys worries?
I would rather have a built-in Dict without weakness than no Dict at
all.
We're working on it. Goals and anti-goals are
- initialisation from any object, including an object initialiser
- no guarantee that an otherwise unused initialiser will be
optimized away
- no guarantee that an otherwise unused initialiser will be
- key/value type parameterization, hashcode callback function
parameterization - defaults to intrinsic::=== and intrinsic::hashcode for identity and
hashing - has/get/set/remove methods (no magic . or [] syntax), iteration
protocol standard methods - no weak reference support
No promises, but it's getting attention. I think the es4-discuss list
has been invaluable on this matter, so I wanted to give an update
quickly after last week's face-to-face meeting. Comments welcome.
On 2007-05-29, at 16:29 EDT, Brendan Eich wrote:
We're working on it. Goals and anti-goals are
- initialisation from any object, including an object initialiser
- no guarantee that an otherwise unused initialiser will be
optimized away- key/value type parameterization, hashcode callback function
parameterization- defaults to intrinsic::=== and intrinsic::hashcode for identity
and hashing- has/get/set/remove methods (no magic . or [] syntax), iteration
protocol standard methods- no weak reference support
No promises, but it's getting attention. I think the es4-discuss
list has been invaluable on this matter, so I wanted to give an
update quickly after last week's face-to-face meeting. Comments
welcome.
Great news. Thanks for the update.
We're working on it. Goals and anti-goals are
- initialisation from any object, including an object initialiser
- no guarantee that an otherwise unused initialiser will be
optimized away- key/value type parameterization, hashcode callback function
parameterization- defaults to intrinsic::=== and intrinsic::hashcode for identity
and hashing- has/get/set/remove methods (no magic . or [] syntax), iteration
protocol standard methods- no weak reference support
No promises, but it's getting attention. I think the es4-discuss
list has been invaluable on this matter, so I wanted to give an
update quickly after last week's face-to-face meeting. Comments
welcome.Great news. Thanks for the update.
Agreed. Looks like a nice balance between conservative feature set
and useful functionality.
Neil Mix scripsit:
We're working on it. Goals and anti-goals are
- initialisation from any object, including an object initialiser
Does this mean that only the local slots from the initializing object are used?
On 5/30/07, John Cowan <cowan at ccil.org> wrote:
Neil Mix scripsit:
We're working on it. Goals and anti-goals are
- initialisation from any object, including an object initialiser
Does this mean that only the local slots from the initializing object are used?
That's the plan, and there are some details to be worked out re: which properties with non-empty namespaces that are picked up, if any -- I'm guessing probably none.
On 5/29/07, Brendan Eich <brendan at mozilla.org> wrote:
We're working on it. Goals and anti-goals are [...]
Looks very good.
- defaults to intrinsic::=== and intrinsic::hashcode for identity and hashing
Perfect.
There is one sort of value that isn't === itself in 3rd Edition: NaN. This means that hashTable.put(NaN, x) will always add a new entry, even if there's already a NaN entry; and the entry can't be retrieved! Maybe either intrinsic::hashcode() or Hash.put() should detect NaN and throw an exception.
On May 30, 2007, at 9:01 AM, Jason Orendorff wrote:
On 5/29/07, Brendan Eich <brendan at mozilla.org> wrote:
We're working on it. Goals and anti-goals are [...]
Looks very good.
- defaults to intrinsic::=== and intrinsic::hashcode for identity and hashing
Perfect.
There is one sort of value that isn't === itself in 3rd Edition: NaN. This means that hashTable.put(NaN, x) will always add a new entry, even if there's already a NaN entry; and the entry can't be retrieved! Maybe either intrinsic::hashcode() or Hash.put() should detect NaN and throw an exception.
Good point -- we talked about this (it came up on python-dev too, for
the same reason), but I forgot to note that the way
intrinsic::hashcode is specified allows for a!==b but
intrinsic::hashcode(a)===intrinsic::hashcode(b). So in Newton in
April, we agreed face-to-face that all NaNs could hash to 0 (if
memory serves). This avoids hardship computing disting codes on each
NaN presented as input, but it doesn't help retrieval or bound table
space.
We did not talk for long about throwing an exception for
intrinsic::hashcode(NaN), but we certainly could do that. IIRC that's
what Python does/will-do. Comments?
On May 30, 2007, at 2:32 PM, Brendan Eich wrote:
Good point -- we talked about this (it came up on python-dev too, for the same reason), but I forgot to note that the way intrinsic::hashcode is specified allows for a!==b but intrinsic::hashcode(a)===intrinsic::hashcode(b). So in Newton in April, we agreed face-to-face that all NaNs could hash to 0 (if memory serves). This avoids hardship computing disting codes on each
Typo: "distinct codes", of course.
On 5/29/07, Brendan Eich <brendan at mozilla.org> wrote:
- key/value type parameterization, hashcode callback function parameterization
- defaults to intrinsic::=== and intrinsic::hashcode for identity and hashing
OK, it strikes me as a little weird, now, to use intrinsic::=== and intrinsic::hashcode() here.
Java, Python, and Ruby let individual classes (rather than individual hash tables) override hash() and equals(). I think this supports generic code better.
function uniq(values) { var d : Dict = {}; // nothing special here for each (var v in values) d.put(v, true); return d.keys(); }
Also, if I were distributing a JavaScript library, I would be happier saying "you can use FooBar objects as hash table keys" than "if you want to use a FooBar as a hash table key, you need to pass these two magic functions to the Dictionary constructor when you create the Dictionary: new Dictionary(FooBar.eq, FooBar.hash)".
Jason Orendorff wrote:
OK, it strikes me as a little weird, now, to use intrinsic::=== and intrinsic::hashcode() here.
Java, Python, and Ruby let individual classes (rather than individual hash tables) override hash() and equals(). I think this supports generic code better.
Not all objects in ES4 are of an interesting class, or implement an interesting interface. Think structural types: the nearest class of the type "{a:int}" is "Object".
Still, it's pretty easy to have both:
function defaultHash.<K>(k:K) : uint { switch type (k) { case (h:Hashable) { return h.hash(); } default { intrinsic::hashcode(k); } } }
function defaultEq.<K>(a:K, b:K) : bool { switch type (k) { case (h:Equality) { return a.equals(b); } default { return a === b; } } }
class Dict.<K,V> { function Dict(hash=defaultHash.<K>, eq=defaultEq.<K>) { ... } ... }
On May 30, 2007, at 5:20 PM, Jason Orendorff wrote:
On 5/29/07, Brendan Eich <brendan at mozilla.org> wrote:
- key/value type parameterization, hashcode callback function parameterization
- defaults to intrinsic::=== and intrinsic::hashcode for identity and hashing
OK, it strikes me as a little weird, now, to use intrinsic::=== and intrinsic::hashcode() here.
You are racing ahead of us here :-). Lars raised this issue in the
wiki, we haven't resolved it.
Java, Python, and Ruby let individual classes (rather than
individual hash tables) override hash() and equals(). I think this supports generic code better.function uniq(values) { var d : Dict = {}; // nothing special here for each (var v in values) d.put(v, true); return d.keys(); }
Also, if I were distributing a JavaScript library, I would be happier saying "you can use FooBar objects as hash table keys" than "if you want to use a FooBar as a hash table key, you need to pass these two magic functions to the Dictionary constructor when you create the Dictionary: new Dictionary(FooBar.eq, FooBar.hash)".
There aren't two magic funargs, because === is part of the Key type
parameter, if you want it to be, via the
developer.mozilla.org/es4/proposals/operators.html
proposal, as a static operator function. But there is no static or
member/prototype hashcode method to match ===. Instead, in the latest
Dict write-up, there is a hashfn constructor funarg, defaulting to
the intrinsic::hashcode global function, or another like it you can
supply as the hashfn funarg's non-default value when constructing a
Dict.
The developer.mozilla.org/es4/proposals/hashcodes.html
proposal was all about minimalism in ES4 to support a self-hosted
collections ecosystem, but built with objects as hash table chain
items, arrays as bucket vectors, etc.
Perhaps that is useful still -- it allows hashing null and undefined,
which are not objects so can't be denoted by a variable x and hashed
via a method call x.hashcode() -- but it seems an
Object.prototype.hashcode or (to match the operators proposal) a
static hashcode method would be better for Dict and similar
collection types.
So yeah, this sucks. We will fix it.
On May 30, 2007, at 5:50 PM, Graydon Hoare wrote:
Jason Orendorff wrote:
OK, it strikes me as a little weird, now, to use intrinsic::=== and intrinsic::hashcode() here.
Java, Python, and Ruby let individual classes (rather than
individual hash tables) override hash() and equals(). I think this supports generic code better.Not all objects in ES4 are of an interesting class, or implement an interesting interface. Think structural types: the nearest class of
the type "{a:int}" is "Object".Still, it's pretty easy to have both:
function defaultHash.<K>(k:K) : uint { switch type (k) { case (h:Hashable) { return h.hash(); } default { intrinsic::hashcode(k);
Don't you (I) wish it were an expression language, like ML ;-).
}
} }
function defaultEq.<K>(a:K, b:K) : bool { switch type (k) { case (h:Equality) { return a.equals(b); } default { return a === b; } } }
class Dict.<K,V> { function Dict(hash=defaultHash.<K>, eq=defaultEq.<K>) { ... } ... }
We could provide all this in the standard Dict.es, for sure. Good use
of type, function, and optional parameters. But then we'd have to
define Hashable and Equality too. Could be done, but these imply
further design decisions (perhaps there should be only one type with
hash and equals methods, instead of two types).
Brendan Eich-2 wrote:
On May 1, 2007, at 10:14 PM, Andrew Dupont wrote:
Brendan Eich wrote:
I'm confused -- do you intend that foo#.toString name a property in no namespace with identifier 'toString' in some object, or a property in a hidden namespace with local name 'toString'?
The latter was my interpretation. But you're saying that the #.
operator would simply look at the subset of an object's properties that are defined on the instance?Yes -- hence the direct:: namespace conceit that lost to #. #[ #{.
That's more reasonable than creating a whole new property
namespace. It doesn't solve the string coercion problem, though. Combining the #. operator with "use namespace intrinsic;" would, but that means the developer would have to opt into key safety.The key safety problems you cite are (a) matching toString or another
indirect (prototype-owned) property; (b) setting toString in the
directly referenced object to some value not a toString function.
You're right, #. addresses only (a).To address (b) would seem to require opting in as you note, or
changing the usual rules for hashes (objects created via #{...}) to
look for methods in a special namespace (intrinsic, or perhaps
function as in SpiderMonkey).This is a fair amount of magic for the Hash class, and some of it
(the function namespace) might want to be abstracted over any class,
since E4X's XML class in SpiderMonkey wants the ability to access XML
methods via, e.g., function::elements.Leaving (b) unsolved without opt-in (use namespace intrinsic), we
could avoid a Hash class with magic method lookup rules altogether,
and add #. #[ #{ as shorthand, where obj#.ident, obj#[expr] ,
obj#.ns::ident, and obj#.ns::[expr] would be variations on the
corresponding unsharp (hash-free) operators, which would work on any
kind of object by looking only in the directly referenced object, not
any prototype.
I see this as two issues.
- The need for Collections/Data Structures.
- The desire for shorthand access to these.
Issue #1: The need for Collections/Data Structures. a. A public interface for Dict has already been posted up. A link for ByteArray was posted. I would also like to see more collection types (SortedSet collection, and some sort of Enum). b. The need for hashCode and equals methods on Object.prototype (DontEnum). c. The need for overridden implementations of toJSONString on a Collection. Method hashCode is more suitable for valueOf for hashes; valueOf is not required to return an int does not return an int for string or Function objects. I would really like to see these issues addressed in further discussion.
Issue #2: The desire for shorthand access to a HashMap. HashMap is a better name. "Dict" just doesn't roll off the tongue nicely. Sad to say, this could get a smart programmer in deep trouble.
HashMap (Dictionary) shorthand delegates to a HashMap's get/set methods.
The set method is called in a literal expression syntax by specifying a property name.
var foo =
#<String>{
"toString" : "i'm a monkey."
// ,boo : 1 // TypeError.
,flavor : "banana"
};
foo.toString( ); // Returns String representation of a Dict (presuming foo is error-free). foo.hasOwnProperty( "flavor" ); // false. foo.flavor; // undefined. foo.get( "flavor" ); // "banana" foo.get("toString"); // returns "i'm a monkey."
/* fooTwo has no type specified. Here, we
- default behavior using ToObject, et c for literals. */ var fooTwo = #{ "toString" : function meowLikeADoggy(){ return this.sound; } ,"sound" : "moo" ,"hasOwnProperty" : function alwaysWrong( prop ) { return !this.hasOwnProperty( prop ); // This function is not bound at this point. } };
fooTwo.get( "hasOwnProperty" ); // function. fooTwo.hasOwnProperty( "hasOwnProperty" ); // false. fooTwo[ "hasOwnProperty" ]; // Do we look in HashMap's keys or look in the object itself?
var bar = { "toString" : "a monkey's uncle" // don't call me. };
bar.toString(); // Error
Creating a HashMap with literal syntax would create one of these: (by Lars T Hansen)
class HashMap.<Type> { function HashMap(weak: boolean = false) public function from(x : Object!) public function size() : uint public function get(key: String) : Type? public function put(key:String, value:Type) : void public function has(key:String) : boolean public function remove(key:String) : boolean iterator function get(deep: boolean = false) : iterator::IteratorType.<String> iterator function getKeys(deep: boolean = false) : iterator::IteratorType.<String> iterator function getValues(deep: boolean = false) : iterator::IteratorType.<Type> iterator function getItems(deep: boolean = false) : iterator::IteratorType.<[String,Type]> } I would like to not have the delete operator call the remove() method; this would seem to add confusion.
/be
Es4-discuss mailing list Es4-discuss at mozilla.org, mail.mozilla.org/listinfo/es4-discuss
Quoted from: www.nabble.com/Separating-a-Hash-type-from-Object-tf3671328.html#a10280414
On 7/25/07, Garrett <dhtmlkitchen at gmail.com> wrote:
I see this as two issues.
- The need for Collections/Data Structures.
- The desire for shorthand access to these.
Indeed. We've decided to support (1) but not (2), but to sweeten our solution by providing constructions and conversions from arbitrary objects, so you can say
new Dict.<Name,int>({a: 1, b: 2, c: 3})
or
{ a:1, b:2, c:3 } to Dict
and get what you want, namely, a map from names to integers initialized with the three maps in the object literal.
We're discussing whether to accomodate a hashcode/equals protocol on keys, but if so this is guaranteed not to be the only protocol, and we're not putting these protocols into Object, which will likely reduce their utility a little.
We're not providing weak refs. In fact, Dict is implementable in ES4 without any implementation hooks at all.
(I don't much care for "Dict" as a name myself, but BiCaptialized suggestions like HashMap and hashCode won't get you anywhere with this committee ;-)
On 7/25/07, Lars T Hansen <lth at acm.org> wrote:
On 7/25/07, Garrett <dhtmlkitchen at gmail.com> wrote:
I see this as two issues.
- The need for Collections/Data Structures.
- The desire for shorthand access to these.
Indeed. We've decided to support (1) but not (2),
I should say, the current proposal supports (1) but not (2), and has the features outlined below, but has not yet been approved.
Lars T Hansen-2 wrote:
On 7/25/07, Garrett <dhtmlkitchen at gmail.com> wrote:
I see this as two issues.
- The need for Collections/Data Structures.
- The desire for shorthand access to these.
Indeed. We've decided to support (1) but not (2), but to sweeten our solution by providing constructions and conversions from arbitrary objects, so you can say
new Dict.<Name,int>({a: 1, b: 2, c: 3})
What is Name? Is that a new type that I haven't seen yet? Looks like an Identifier. I don't see Name here: developer.mozilla.org/es4/spec/chapter_19_native_objects.html (That page could benefit from a TOC and alphabetization.)
or
{ a:1, b:2, c:3 } to Dict
and get what you want, namely, a map from names to integers initialized with the three maps in the object literal.
We're discussing whether to accomodate a hashcode/equals protocol on keys, but if so this is guaranteed not to be the only protocol, and we're not putting these protocols into Object, which will likely reduce their utility a little.
The reason for adding them to Object.prototype is to have a common interface for collections to compare objects with. The default behavior would be strict equality.
set.add( new CaseInsensitiveString( "garrett" ) );
A comparator would also work. In absence of a comparator, sort objects by their natural order and do equality checking.
The case for HashMap: HashMap is that it is the most common type of collection that will be used. Dictionary is more flexible, but since the keys are not, by default, strings, it will require more work to serialize toJSONString. In most cases users will want Strings for keys.
We're not providing weak refs. In fact, Dict is implementable in ES4 without any implementation hooks at all.
(I don't much care for "Dict" as a name myself, but BiCaptialized suggestions like HashMap and hashCode won't get you anywhere with this committee ;-)
What about ByteArray, toString, toJSONString, valueOf, et c? If that's not camelCase, I'm confused.
How does "Dictionary" sound?
On 7/25/07, Garrett <dhtmlkitchen at gmail.com> wrote:
Lars T Hansen-2 wrote:
On 7/25/07, Garrett <dhtmlkitchen at gmail.com> wrote:
I see this as two issues.
- The need for Collections/Data Structures.
- The desire for shorthand access to these.
Indeed. We've decided to support (1) but not (2), but to sweeten our solution by providing constructions and conversions from arbitrary objects, so you can say
new Dict.<Name,int>({a: 1, b: 2, c: 3})
What is Name? Is that a new type that I haven't seen yet? Looks like an Identifier. I don't see Name here: developer.mozilla.org/es4/spec/chapter_19_native_objects.html (That page could benefit from a TOC and alphabetization.)
Indeed it could.
The wiki is pretty much out of sync with reality at this point; we need to republish the internal wiki but haven't for a while, for various reasons having to do with manpower etc. Hopefully soon.
A Name is a data structure that holds a namespace and an identifier as separate entities. I misspoke above, there is a more general type called EnumerableId that covers all the valid cases for a property name in an object (Name, uint, int, and string), so the type in question is Dict.<EnumerableId,int> in the example.
We're discussing whether to accomodate a hashcode/equals protocol on keys, but if so this is guaranteed not to be the only protocol, and we're not putting these protocols into Object, which will likely reduce their utility a little.
The reason for adding them to Object.prototype is to have a common interface for collections to compare objects with. The default behavior would be strict equality.
I understand the motivation, but I don't think we'll be adding new names to Object -- it's far too easy to break existing content, even if these are DontEnum. The global object probably needs to be an Object of some sort, and suddenly "equals" and "hashcode" will show up in the global environment because of that. Tests for "'equals' in <anything>" will suddenly return true. etc. It's a tough sell. What
I have proposed for Dict is that we make it possible for clients who want to use this OOP-like protocol to use it, and since we define what that protocol would be then at least there's a standard for it, but there will necessarily be some facility for supplying hashcode and equality functions to the Dict constructor as well (defaulting to intrinsic::hashcode and intrinsic::===) in cases where the protocol is impossible or undesirable.
The case for HashMap: HashMap is that it is the most common type of collection that will be used. Dictionary is more flexible, but since the keys are not, by default, strings, it will require more work to serialize toJSONString. In most cases users will want Strings for keys.
I think you have an uphill battle in restricting the functionality of Dict, esp since one can say
type HashMap.<T> = Dict.<String,T>;
and be done with it. Not hard for the user, really. Although I suppose it is an interesting idea to provide that type by default, in addition to Dict.
It's a good point that Dict ought to have a reasonable toJSONString, and it's true that for String keys it can do a particularly good job. I'll be sure to add that to the proposal.
(It actually opens up interesting questions about JSON -- the current JSON code from Doug Crockford relies on enumeration to get property names, but then filters the enumerated properties through hasOwnProperty. So even when Dict provides an iterator, it would need to provide an override for hasOwnProperty to work correctly with the default JSON protocol, if it does not want to override toJSONString.)
(I don't much care for "Dict" as a name myself, but BiCaptialized suggestions like HashMap and hashCode won't get you anywhere with this committee ;-)
What about ByteArray, toString, toJSONString, valueOf, et c? If that's not camelCase, I'm confused.
I'm sorry, I was being flip. We've been deriding Java's choice of "hashCode" for a method name (vs "hashcode" in ES4), but the examples you cite are just as awful. The splinter in your brother's eye and the beam in your own and all that.
How does "Dictionary" sound?
I love it, but I lost an informal vote :-)
Garrett wrote:
How does "Dictionary" sound?
I like "Hash" myself. Just as short as "Dict," but easier to pronounce, and sidesteps the camelCase ugliness. Prior art in Ruby (and many other languages, I'm sure).
I can take maximum blame for advocating Dict over Dictionary, based
on brevity and the Python type, transliterated appropriately
(capitalized, I mean ;-).
But Hash is just as good by that crude metric.
We'll have another straw poll. Hash was mooted early on, but then
Dictionary stuck, and later I urged brevity. Thanks for the reminder.
On 2007-07-25, at 13:36 EDT, Brendan Eich wrote:
We'll have another straw poll. Hash was mooted early on, but then Dictionary stuck, and later I urged brevity. Thanks for the reminder.
So a Dict is not a Map? It's keys must be identifiers, not Objects?
See Lars's post today. It's a parameterized type. So you can map
however you please: Dict.<Object,Object> or even Dict.<,>.
On 7/25/07, Brendan Eich <brendan at mozilla.org> wrote:
I can take maximum blame for advocating Dict over Dictionary, based on brevity and the Python type, transliterated appropriately (capitalized, I mean ;-).
But Hash is just as good by that crude metric.
We'll have another straw poll. Hash was mooted early on, but then Dictionary stuck, and later I urged brevity. Thanks for the reminder.
If it wasn't clear from the subject line of this thread, I also vote for "Hash" over "Dict" for similar reasons to those already mentioned.
On 7/25/07, Brad Fults <bfults at gmail.com> wrote:
On 7/25/07, Brendan Eich <brendan at mozilla.org> wrote:
I can take maximum blame for advocating Dict over Dictionary, based on brevity and the Python type, transliterated appropriately (capitalized, I mean ;-).
But Hash is just as good by that crude metric.
We'll have another straw poll. Hash was mooted early on, but then Dictionary stuck, and later I urged brevity. Thanks for the reminder.
If it wasn't clear from the subject line of this thread, I also vote for "Hash" over "Dict" for similar reasons to those already mentioned.
The nice thing about "Dictionary" or "Dict" or "Map" is that it says something about functionality, whereas "Hash" or "HashMap" says something about implementation. On the other hand, the interface is plainly hashcode-based, so it's possible it's only fair to emphasize that fact in the name.
If so, I vote for "Hashtable": "Hash" is ugly and overly short; "HashMap" is BiCapitalized and "map" is less common than "table" in the context of hash structures. (Java has both, unsurprisingly, and they are essentially the same, Hashtable being synchronized and HashMap not.)
On 2007-07-25, at 16:11 EDT, Lars T Hansen wrote:
On 7/25/07, Brad Fults <bfults at gmail.com> wrote:
On 7/25/07, Brendan Eich <brendan at mozilla.org> wrote:
I can take maximum blame for advocating Dict over Dictionary, based on brevity and the Python type, transliterated appropriately (capitalized, I mean ;-).
But Hash is just as good by that crude metric.
We'll have another straw poll. Hash was mooted early on, but then Dictionary stuck, and later I urged brevity. Thanks for the
reminder.If it wasn't clear from the subject line of this thread, I also vote for "Hash" over "Dict" for similar reasons to those already
mentioned.The nice thing about "Dictionary" or "Dict" or "Map" is that it says something about functionality, whereas "Hash" or "HashMap" says something about implementation. On the other hand, the interface is plainly hashcode-based, so it's possible it's only fair to emphasize that fact in the name.
If so, I vote for "Hashtable": "Hash" is ugly and overly short; "HashMap" is BiCapitalized and "map" is less common than "table" in the context of hash structures. (Java has both, unsurprisingly, and they are essentially the same, Hashtable being synchronized and HashMap not.)
If this is the poll:
- Map (because it maps one thing to another)
- Dictionary (not as good because it makes me think keys must be
strings) - Dict (dorky Unixese for an English word) -°. Hash (only nerds would have a clue what this means)
On 7/25/07, P T Withington <ptw at pobox.com> wrote:
If this is the poll:
- Map (because it maps one thing to another)
This seems reasonable until you consider the conflict between Map and Array.prototype.map. I think this confusion is enough to knock Map way down on the list.
- Dictionary (not as good because it makes me think keys must be strings)
Agreed with the reasoning and I'd add that its length doesn't help.
- Dict (dorky Unixese for an English word)
Agreed; clunky, difficult to say, rather obscure.
-∞. Hash (only nerds would have a clue what this means)
Disagree. In computer science these data structures are taught as "hash tables". Anyone who is even casually acquainted with computer science will know what hash tables are and thus this seems like an acceptable shortening. For those without previous computer science experience, it's a single term to learn among the myriad others in ES4 and has already been successful in other language markets (see Perl, Ruby).
Hashtable is another option as the more verbose description of the data structures that we learn in computer science, but it dis the JS convention of camel casing multiple words in objects (see RegExp and virtually all methods in the core language).
HashTable is the obvious solution to the problem of camel casing. This is a fine option, but I see no reasonable argument to use this over the shorter, simpler "Hash". Likewise for HashMap.
HashTable is the obvious solution to the problem of camel casing. This is a fine option, but I see no reasonable argument to use this over the shorter, simpler "Hash". Likewise for HashMap.
You don't like Table or Map?
FWIW Flash calls it Dictionary.
Peter
Just a little comment, maybe thinking of a name for that "Dictionary" that would not support weak keys for the final spec but could evolve supporting weak keys later could help to decide for the name.
exemple: in AS3 now Dictionnary support weak keys could we imagine having a hash! type not supporting weak keys available to everyone/spec compliant and a Dictionnary inheriting from hash! to show that it supports weak keys for a particular implementation even if not part of the spec ?
Could we imagine to extend that to any implementation based on Tamarin ? (as Tamarin do define such Dictionary class)
Hello :)
For me Dictionnary it's a helper primitive object to implements Maps...
For example in my framework (VEGAS) i use a Map interface like in JAVA to implements my HashMap, ArrayMap, MultiHashMap, MultiHashSet etc.... class.
Interface : svn1.cvsdude.com/osflash/vegas/AS3/trunk/src/vegas/data/Map.as
Implementations : svn1.cvsdude.com/osflash/vegas/AS3/trunk/src/vegas/data/map
The Map implementation are important to creates models etc... but we can't limit the hash map implementation with only one class for me...
The question with the ADT in ECMAScript... it's important to creates a full primitive and native ADT library ? The linked list, collections, queue etc... are important too but it's difficult to implement all the primitive object for this implementations ?
EKA+ :)
2007/7/29, eka <ekameleon at gmail.com>:
On 7/25/07, Lars T Hansen <lth at acm.org> wrote:
On 7/25/07, Garrett <dhtmlkitchen at gmail.com> wrote:
Lars T Hansen-2 wrote:
On 7/25/07, Garrett <dhtmlkitchen at gmail.com> wrote:
I see this as two issues.
- The need for Collections/Data Structures.
- The desire for shorthand access to these.
Indeed. We've decided to support (1) but not (2), but to sweeten our solution by providing constructions and conversions from arbitrary objects, so you can say
new Dict.<Name,int>({a: 1, b: 2, c: 3})
What is Name? Is that a new type that I haven't seen yet? Looks like an Identifier. I don't see Name here: developer.mozilla.org/es4/spec/chapter_19_native_objects.html (That page could benefit from a TOC and alphabetization.)
Indeed it could.
The wiki is pretty much out of sync with reality at this point; we need to republish the internal wiki but haven't for a while, for various reasons having to do with manpower etc. Hopefully soon.
A Name is a data structure that holds a namespace and an identifier as separate entities. I misspoke above, there is a more general type called EnumerableId that covers all the valid cases for a property name in an object (Name, uint, int, and string), so the type in question is Dict.<EnumerableId,int> in the example.
We're discussing whether to accomodate a hashcode/equals protocol on keys, but if so this is guaranteed not to be the only protocol, and we're not putting these protocols into Object, which will likely reduce their utility a little.
The reason for adding them to Object.prototype is to have a common interface for collections to compare objects with. The default behavior would be strict equality.
I understand the motivation, but I don't think we'll be adding new names to Object -- it's far too easy to break existing content, even if these are DontEnum. The global object probably needs to be an Object of some sort, and suddenly "equals" and "hashcode" will show up in the global environment because of that. Tests for "'equals' in <anything>" will suddenly return true. etc. It's a tough sell. What I have proposed for Dict is that we make it possible for clients who want to use this OOP-like protocol to use it, and since we define what that protocol would be then at least there's a standard for it, but there will necessarily be some facility for supplying hashcode and equality functions to the Dict constructor as well (defaulting to intrinsic::hashcode and intrinsic::===) in cases where the protocol is impossible or undesirable.
The case for HashMap: HashMap is that it is the most common type of collection that will be used. Dictionary is more flexible, but since the keys are not, by default, strings, it will require more work to serialize toJSONString. In most cases users will want Strings for keys.
I think you have an uphill battle in restricting the functionality of Dict, esp since one can say
type HashMap.<T> = Dict.<String,T>;
and be done with it. Not hard for the user, really. Although I suppose it is an interesting idea to provide that type by default, in addition to Dict.
It's a good point that Dict ought to have a reasonable toJSONString, and it's true that for String keys it can do a particularly good job. I'll be sure to add that to the proposal.
(It actually opens up interesting questions about JSON -- the current JSON code from Doug Crockford relies on enumeration to get property names, but then filters the enumerated properties through hasOwnProperty.
That's for ES3.
So even when Dict provides an iterator, it would need
to provide an override for hasOwnProperty to work correctly with the default JSON protocol, if it does not want to override toJSONString.)
var stuff = new HashTable.<String, *>();
stuff.add( "one", 1 );
stuff.hasOwnProperty( "one" ); // false. stuff.one;// undefined. "one" in stuff; // false.
if( "one" in stuff.keys ) stuff.get( "one" ); // 1.
for( var key in stuff.keys ) { print( key + ": " + stuff[ key ] ); } // one: 1.
Should all Collections have a toJSONString?
Collection | +HashTable, SortedSet TreeMap ?
(I don't much care for "Dict" as a name myself, but BiCaptialized suggestions like HashMap and hashCode won't get you anywhere with this committee ;-)
The current JS spec is camelCasing everything. I usually like it when an API does one thing consistently. If it's underscores, then always use underscore, et c. JavaScript (hey, that's camel'd, too!) alway uses camelCase. The DOM stuff is consistent, too (textContent, nodeValue, et c). Will adding an inconsistency add confusion?
On Jul 30, 2007, at 8:54 AM, Garrett Smith wrote:
[overquoting deleted]
var stuff = new HashTable.<String, *>();
stuff.add( "one", 1 );
s/add/put/
stuff.hasOwnProperty( "one" ); // false. stuff.one;// undefined. "one" in stuff; // false.
Right.
if( "one" in stuff.keys ) stuff.get( "one" ); // 1.
for( var key in stuff.keys ) { print( key + ": " + stuff[ key ] ); } // one: 1.
Note: for (var key in stuff) is enough; for (let key in iterator::keys (stuff)) also works. You can iterate over values with
for each (let val in stuff) ...
And you can destructure items via
for (let [key, val] in iterator::items(stuff)) ...
for example. But this is all generic due to iterators and generators
(whose last exported wiki page is way out of date).
Should all Collections have a toJSONString?
Not necessarily, but that method delegates to Array.prototype or
Object.prototype anyway, and as Lars noted the one in
Object.prototype is generic. If it leaves out important properties
due to the DontEnum attribute, that might be a clue that an override
is needed. On the other hand there's no JSON type for Map, so you
can't deserialize directly to a Map instance. You would have to
convert using the |to| operator or a Map call or construction.
Collection | +HashTable, SortedSet TreeMap ?
This is up to the larger ecosystem, but as with Python, the JS way,
and the Web way (cf. mashups, which are not planned ahead of time to
share named "types" broadly construed) favors protocols over single-
inheritance nominal type trees. So collections might implement
interfaces (either nominal, or more likely structural, types such as
type iterator::IterableType).
(I don't much care for "Dict" as a name myself, but BiCaptialized suggestions like HashMap and hashCode won't get you anywhere
with this committee ;-)The current JS spec is camelCasing everything. I usually like it when an API does one thing consistently. If it's underscores, then always use underscore, et c. JavaScript (hey, that's camel'd, too!) alway uses camelCase. The DOM stuff is consistent, too (textContent, nodeValue, et c). Will adding an inconsistency add confusion?
There's no inconsistency at all -- types are InterCaps, methods are
true camelCaps. Just like Java, after Smaltalk.
As has been previously noted [1] and should be general knowledge, the confusion and collision between Object-as-hash and Object-as-inherited-from is sometimes painful in ES3.
I looked through the latest ES4 spec and proposals [2] but didn't see anything about changing the way hashes are handled. Are there any plans to derive a Hash type from Object which would handle what are now object literals (as hash literals)? If not, can there be?
This would solve many of the contemporary problems with Object (like extending Object.prototype to include methods like .keys(), .values(), etc.). I'm interested to hear others' thoughts on this.
Thanks.
[1] - erik.eae.net/archives/2005/06/06/22.13.54 [2] - developer.mozilla.org/es4