<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type">
  <title></title>
</head>
<body bgcolor="#ffffff" text="#000000">
A general spec question about helper methods and the informative
namespace?<br>
<br>
My presumption that both these are not part of the normative spec.
Implementations may choose to implement the functionality without a
helper method and without the specific informative elements. Is this
correct?<br>
<br>
If so, then reading:<br>
<br>
<blockquote>"The iterator protocol makes use of a helper method <code>iterate</code>
which first collects the values that will be returned by the iterator
methods and then returns an object that provides the correct <code>next</code>
method:
"<br>
  <br>
</blockquote>
really means that an implementation could use the helper method iterate
as the RI does. If not, it must provide equivalent functionality.<br>
<br>
Am I reading the meaning of helper and informative correctly?<br>
<br>
Michael<br>
<br>
<br>
Lars Hansen wrote:
<blockquote
 cite="mid:1421FCFA117AA044B447467FDE380715012B1119@eurmail.eur.adobe.com"
 type="cite">
  <pre wrap="">I'm enclosing the draft for the Map class.  Please comment.

--lars
  </pre>
  <br>
  <hr size="4" width="90%"><br>
  <title>The class "Map"</title>
  <style>
/* -*- indent-tabs-mode: nil -*- */
.fixme { font-size: smaller; padding-left: 1em; color: red }
.note { font-size: smaller; padding-left: 1em }
.part { font-size: 24pt }
.grammar { font-style: italic }
.indented { padding-left: 3em }
.nonterm { padding-top: 1em }
.xref { border: thin solid red; }
.section { margin-bottom: -1em; font-family: sans-serif; font-size: smaller }
.implsection { margin-bottom: -1em; padding-bottom: 0.3em; font-family: sans-serif; font-size: smaller }
.literal { font-style: normal; font-weight: bold }
H1,H2,H3,H4,H5,H6 { font-family: sans-serif }
H1 { font-size: 14pt }
H2 { font-size: 12pt }
H3 { font-size: 11pt }
H4 { font-size: 10pt }

P code { font-size: 10pt }
code { font-style: normal; font-weight: normal }

pre { font-size: 10pt }

body { counter-reset: chapter section subsection subsubsection;
       font-size: 11pt; 
       margin: 0.75in }

table { font-size: inherit }

.pcounter:before {
    content: counter(para); 
}

.pcounter {
    position: absolute; left: 0.5in;
    counter-increment: para
}

H1:before {
    padding-right: 1em;
    content: counter(chapter) "  ";
    counter-increment: chapter }

H1 {
    counter-reset: section para;
}

H2:before {
    padding-right: 1em;
    content: counter(chapter) "." counter(section) "  ";
    counter-increment: section }

H2 {
    counter-reset: subsection para;
}

H3:before {
    padding-right: 1em;
    content: counter(chapter) "." counter(section) "." counter(subsection) "  ";
    counter-increment: subsection }

H3 {
    counter-reset: subsubsection para;
}

H4:before {
    padding-right: 1em;
    content: counter(chapter) "." counter(section) "." counter(subsection) "." counter(subsubsection) "  ";
    counter-increment: subsubsection }

H4 {
    counter-reset: para;
}

@media print {
/*    H1 { page-break-before: always } */
    .copyright { page-break-before: always }
}

  </style>
  <h1 id="class Map"> The class <code>Map</code> </h1>
  <pre>FILE:                       spec/library/Map.html
DRAFT STATUS:               DRAFT 1 - 2008-02-29
IMPLEMENTATION STATUS:      ES4 RI
TEST CASE STATUS:           Unknown
REVIEWED AGAINST ES3:       N/A
REVIEWED AGAINST ERRATA:    N/A
REVIEWED AGAINST BASE DOC:  N/A
REVIEWED AGAINST PROPOSALS: YES
REVIEWED AGAINST CODE:      YES
  </pre>
  <p><span class="pcounter"></span> The class <code>Map</code> is a
parameterized, dynamic, non-final, direct
subclass of <code>Object</code> that provides a reliable, efficient,
mutable,
and iterable map from keys to values. Keys and values may be of
arbitrary types.
  </p>
  <p><span class="pcounter"></span> A <code>Map</code> is realized as
a hash table. When the <code>Map</code> is
constructed the caller may provide specialized functions that compare
keys and compute hash values for keys.
  </p>
  <h2>Synopsis</h2>
  <p><span class="pcounter"></span> The class <code>Map</code>
provides the following interface:
  </p>
  <pre>__ES4__ dynamic class Map.&lt;K,V&gt;
{
    public function Map(equals:   function = (function(a,b) a === b),
                        hashcode: function = intrinsic::hashcode) &#8230;

    static meta function invoke(object: Object): Map.&lt;EnumerableId,*&gt; &#8230;
    static public const length = 2;

    intrinsic function size() : uint &#8230;
    intrinsic function get(key: K) : V &#8230;
    intrinsic function put(key:K, value:V) : void &#8230;
    intrinsic function has(key:K) : boolean &#8230;
    intrinsic function remove(key:K) : boolean &#8230;

    iterator function get(deep: boolean = false) : iterator::IteratorType.&lt;K&gt; &#8230;
    iterator function getKeys(deep: boolean = false) : iterator::IteratorType.&lt;K&gt; &#8230;
    iterator function getValues(deep: boolean = false) : iterator::IteratorType.&lt;V&gt; &#8230;
    iterator function getItems(deep: boolean = false) : iterator::IteratorType.&lt;[K,V]&gt; &#8230;

    private const equals   : function = &#8230;
    private const hashcode : function = &#8230;
    private var population : uint = &#8230;
}
  </pre>
  <p><span class="pcounter"></span> The <code>Map</code> prototype
object provides these direct properties:
  </p>
  <pre>    size:   function () &#8230;
    get:    function (key) &#8230;
    put:    function (key, value) &#8230;
    has:    function (key) &#8230;
    remove: function (key) &#8230;
  </pre>
  <h2>Methods on the <code>Map</code> class object</h2>
  <h3>new&nbsp;Map.&lt;K,V&gt;(&nbsp;equals=&#8230;,&nbsp;hashcode=&#8230;&nbsp;)</h3>
  <p class="section"><b>Description</b> </p>
  <p><span class="pcounter"></span> The <code>Map</code> constructor
creates a new map for key type <i>K</i>
and value type <i>V</i>.
  </p>
  <p><span class="pcounter"></span> The optional <i>equals</i>
argument is a function that compares two
keys and returns <b>true</b> if they are equal and <b>false</b> if
they are
not. This function must implement a reflexive, transitive, and
symmetric relation, and <i>equals(k1,k2)</i> must be constant for any
two
actual keys <i>k1</i> and <i>k2</i>. The default value for <i>equals</i>
is a
function that compares the two keys using the <code>===</code>
operator.
  </p>
  <p><span class="pcounter"></span> The optional <i>hashcode</i>
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 <i>hashcode</i>
function on the same key value must return the same numeric code, and
the <i>hashcode</i> function must always return the same numeric code
for
two objects that compare equal by the <i>equals</i> function. The
default value for <i>hashcode</i> is the intrinsic global function
  <code>hashcode</code>.
  </p>
  <p class="note"><b>NOTE</b>&nbsp;&nbsp; The constraint that <i>equals</i> and <i>hashcode</i>
return
constant values does not apply to key values that are not in a <code>Map</code>
nor referenced from an activation of any method on <code>Map</code>.
  </p>
  <p class="note"><b>NOTE</b>&nbsp;&nbsp; There is no requirement that the values
returned from
  <i>hashcode</i> for two unequal keys must be different.
  </p>
  <p class="implsection"><b>Implementation</b> </p>
  <p><span class="pcounter"></span> The <code>Map</code> constructor
initializes the <code>Map</code> object by
saving its parameters in private storage and initializing the count of
the number of associations in the table to zero.
  </p>
  <pre>public function Map(equals   /*: function*/ = (function (x,y) x === y),
                    hashcode /*: function*/ = intrinsic::hashcode)
    : equals = equals
    , hashcode = hashcode
    , population = 0
{
}
  </pre>
  <p class="fixme"><b>FIXME</b>&nbsp;&nbsp; (Ticket #153) The parameters to the <code>Map</code>
constructor should
be constrained to be <code>function</code>, but not any more than that
(because
that would be bad UI for scripts). Currently the RI does not support
  <code>function</code> as a type annotation, so the current
implementation of
the constructor is unconstrained.
  </p>
  <h3>Map(&nbsp;object&nbsp;)</h3>
  <p class="section"><b>Description</b> </p>
  <p><span class="pcounter"></span> When the <code>Map</code> class
object is called as a function, it
creates a new <code>Map</code> object from <code>EnumerableId</code>
to <code>*</code>,
populating the new <code>Map</code> object with the own properties of
  <i>object</i>.
  </p>
  <p class="section"><b>Returns</b> </p>
  <p><span class="pcounter"></span> The <code>Map</code> class object
called as a function returns a new
  <code>Map</code> object.
  </p>
  <p class="implsection"><b>Implementation</b>
  </p>
  <pre>static meta function invoke(object: Object): Map.&lt;EnumerableId,*&gt; {
    let d = new Map.&lt;EnumerableId,*&gt;;
    for (let n in object)
        if (object.intrinsic::hasOwnProperty(n))
            d.put(n, object[n]);
    return d;
}
  </pre>
  <p class="fixme"><b>FIXME</b>&nbsp;&nbsp; (Tickets #247, #289, and e-mail
discussion.) This method may
change if we change the meaning of statics in parameterized classes:
the map would be to the type <code>V</code> instead of to <code>*</code>.
  </p>
  <h2>Methods on <code>Map</code> instances</h2>
  <h3>size&nbsp;(&nbsp;)</h3>
  <p class="section"><b>Returns</b> </p>
  <p><span class="pcounter"></span> The intrinsic method <code>size</code>
returns the number of associations in the map.
  </p>
  <p class="implsection"><b>Implementation</b>
  </p>
  <pre>intrinsic function size() : uint
    population;
  </pre>
  <h3>get&nbsp;(&nbsp;key&nbsp;)</h3>
  <p class="section"><b>Returns</b> </p>
  <p><span class="pcounter"></span> The intrinsic method <code>get</code>
returns the value associated with <i>key</i>, or <b>null</b> if
there is no such association.
  </p>
  <p class="implsection"><b>Implementation</b>
  </p>
  <pre>intrinsic function get(key: K) : V {
    let probe = informative::find(key);
    return probe ? probe.value : null;
}
  </pre>
  <p><span class="pcounter"></span> The informative function <code>find</code>
searches for <i>key</i> in the
  <code>Map</code> and returns an object containing at least the
properties
  <code>key</code> and <code>value</code> if the association was
found, or otherwise
  <b>null</b>. (The returned object is part of the <code>Map</code>
data structure,
and writing to it updates the association in the <code>Map</code>.)
  </p>
  <pre>informative function find(key: K): like { key: K, value: V } &#8230;
  </pre>
  <h3>put&nbsp;(&nbsp;key,&nbsp;value&nbsp;)</h3>
  <p class="section"><b>Description</b> </p>
  <p><span class="pcounter"></span> The intrinsic method <code>put</code>
creates an association between
  <i>key</i> and <i>value</i>, or overwrites an existing association
if there
is one.
  </p>
  <p class="section"><b>Returns</b> </p>
  <p><span class="pcounter"></span> The <code>put</code> method
returns nothing.
  </p>
  <p class="implsection"><b>Implementation</b>
  </p>
  <pre>intrinsic function put(key:K, value:V) : void {
    let probe = informative::find(key);
    if (probe)
        probe.value = value;
    else {
        ++population;
        informative::insert(key, value);
    }
}
  </pre>
  <p><span class="pcounter"></span> The informative function <code>insert</code>
adds a new association between
  <i>key</i> and <i>value</i> to the <code>Map</code>.
  </p>
  <pre>informative function insert(key: K, value: V): void &#8230;
  </pre>
  <h3>has&nbsp;(&nbsp;key&nbsp;)</h3>
  <p class="section"><b>Returns</b> </p>
  <p><span class="pcounter"></span> The intrinsic method <code>has</code>
returns <b>true</b> if there exists an association for <i>key</i>,
or <b>false</b> otherwise.
  </p>
  <p class="implsection"><b>Implementation</b>
  </p>
  <pre>intrinsic function has(key:K) : boolean {
    let probe = informative::find(key);
    return probe ? true : false;
}
  </pre>
  <h3>remove&nbsp;(&nbsp;key&nbsp;)</h3>
  <p class="section"><b>Description</b> </p>
  <p><span class="pcounter"></span> The intrinsic method <code>remove</code>
removes any association for <i>key</i>.
  </p>
  <p class="section"><b>Returns</b> </p>
  <p><span class="pcounter"></span> The <code>remove</code> method
returns <b>true</b> if there was an association for <i>key</i>,
or <b>false</b> otherwise.
  </p>
  <p class="implsection"><b>Implementation</b>
  </p>
  <pre>intrinsic function remove(key:K) : boolean {
    let probe = informative::find(key);
    if (probe) {
        --population;
        informative::eject(probe);
        return true;
    }
    return false;
}
  </pre>
  <p><span class="pcounter"></span> The informative function <code>eject</code>
removes the association for
  <i>key</i> from the <code>Map</code>.
  </p>
  <pre>informative function eject(box: like { key: K, value: V }): void &#8230;
  </pre>
  <h2>Iteration protocol on <code>Map</code> instances</h2>
  <p><span class="pcounter"></span> The iterator protocol makes use of
a helper method <code>iterate</code>
which first collects the values that will be returned by the iterator
methods and then returns an object that provides the correct <code>next</code>
method:
  </p>
  <pre>helper function iterate.&lt;T&gt;(f: function(*,*,*):*) {
    let a = [];
    informative::allElements(function (k,v) { f(a,k,v) });
    return {
        next: let (i=0, limit=a.length)
                function () : T {
                    if (i &lt; limit)
                        return a[i++];
                    throw iterator::StopIteration;
                }
    };
}
  </pre>
  <p><span class="pcounter"></span> The informative function <code>allElements</code>
calls its function
argument on every key/value pair in the <code>Map</code>:
  </p>
  <pre>informative function allElements(fn: function): void &#8230;
  </pre>
  <p><span class="pcounter"></span> The iterator methods <code>getKeys</code>,
  <code>getValues</code>, and <code>getItems</code>
return iterator objects that iterate over keys, values, and key/value
pairs, respectively. The iterator method <code>get</code> iterates
over keys
(like <code>getKeys</code>).
  </p>
  <p class="implsection"><b>Implementation</b>
  </p>
  <pre>iterator function getKeys(deep: boolean = false) : iterator::IteratorType.&lt;K&gt;
    helper::iterate.&lt;K&gt;(function (a,k,v) { a.push(k) });

iterator function getValues(deep: boolean = false) : iterator::IteratorType.&lt;V&gt;
    helper::iterate.&lt;V&gt;(function (a,k,v) { a.push(v) });

iterator function getItems(deep: boolean = false) : iterator::IteratorType.&lt;[K,V]&gt;
    helper::iterate.&lt;[K,V]&gt;(function (a,k,v) { a.push([k,v]) });

iterator function get(deep: boolean = false) : iterator::IteratorType.&lt;K&gt;
    iterator::getKeys(deep);
  </pre>
  <h2>Methods on the <code>Map</code> prototype object</h2>
  <p><span class="pcounter"></span> The methods on the <code>Map</code>
prototype object are constrained to
being called on instances of <code>Map</code>. They all delegate to
the
corresponding intrinsic method on their <code>this</code> object.
  </p>
  <pre>prototype function size(this: Map.&lt;*,*&gt;)
    this.intrinsic::size();

prototype function get(this: Map.&lt;*,*&gt;, key)
    this.intrinsic::get(key);

prototype function put(this: Map.&lt;*,*&gt;, key, value)
    this.intrinsic::put(key, value);

prototype function has(this: Map.&lt;*,*&gt;, key)
    this.intrinsic::has(key);

prototype function remove(this: Map.&lt;*,*&gt;, key)
    this.intrinsic::remove(key);
  </pre>
  <pre wrap="">
<hr size="4" width="90%">
_______________________________________________
Es4-discuss mailing list
<a class="moz-txt-link-abbreviated" href="mailto:Es4-discuss@mozilla.org">Es4-discuss@mozilla.org</a>
<a class="moz-txt-link-freetext" href="https://mail.mozilla.org/listinfo/es4-discuss">https://mail.mozilla.org/listinfo/es4-discuss</a>
  </pre>
</blockquote>
</body>
</html>