Binary data (ByteArray/ByteVector) proposal on public-script-coord

# Maciej Stachowiak (16 years ago)

I pulled together a rough proposal for representing binary data in
ECMAScript and posted it on public-script-coord. I think having this
is important for many W3C specs, but it is probably best defined in
ECMAScript. I'm posting a link here in case anyone is interested and
is not on the public-script-coord mailing list yet:

lists.w3.org/Archives/Public/public-script-coord/2009OctDec/0093.html

, Maciej

# Alex Russell (16 years ago)

On Nov 5, 2009, at 2:48 PM, Maciej Stachowiak wrote:

I pulled together a rough proposal for representing binary data in
ECMAScript and posted it on public-script-coord. I think having this
is important for many W3C specs, but it is probably best defined in
ECMAScript. I'm posting a link here in case anyone is interested and
is not on the public-script-coord mailing list yet:

lists.w3.org/Archives/Public/public-script-coord/2009OctDec/0093.html

Looks promising! A couple of thoughts:

  • the middle-ground approach seems interesting, although having
    them not be "real" arrays feels like we're just kicking the can down
    the road WRT the large-ish number of things that could be thought of
    as arrays but which don't act like them (NodeList, arguments, etc.).

  • any thoughts on type conversions? what does this do/return?:

    var bits = new Data("..."); var res = bits += "?";

    will strings have a toData() protocol? Should other objects be
    able to implement such a protocol? will there be a canonical byte
    format for all strings in the language?

  • given that Data are array-like things that have the property of
    being packed (like arguments), maybe we're just missing a PackedArray
    superclass in general that could help w/ the efficiency concerns
    (irrespective of mutability).

  • what do you think about a toArray() method?

  • do you envision any provision for multi-dimensional Data
    objects? E.g., <canvas> data.

# Charles Jolley (16 years ago)

This looks like a good approach. I wonder if the Data/DataBuilder
distinction could be handled better by using the Object.freeze()
semantics. Even if the browser does not support freezing in the
general sense yet, you could borrow the ideas for data.

Probably the wrong API names, but here is the basic idea:

Data.prototype.copy() -> returns a mutable form of the Data object

Data.prototype.freeze() or Data.freeze(aDataObject) -> makes the Data object frozen if it is not frozen already

Data.prototype.frozenCopy() -> returns the data object but pre-frozen. For Data object's

already frozen can return "this"

Data.prototype.frozen - true when frozen, false otherwise.

--

Browser API's that return a data object can return pre-frozen data,
allowing for all the sharing scenarios your outlined in your mail.

This is basically a copy of the mutable/immutable API of Cocoa, btw,
just reversed. (i.e. you get frozenCopy() instead of a mutableCopy())

# David-Sarah Hopwood (16 years ago)

Charles Jolley wrote:

This looks like a good approach. I wonder if the Data/DataBuilder distinction could be handled better by using the Object.freeze() semantics. Even if the browser does not support freezing in the general sense yet, you could borrow the ideas for data.

Probably the wrong API names, but here is the basic idea:

Data.prototype.copy() -> returns a mutable form of the Data object

Data.prototype.freeze() or Data.freeze(aDataObject) -> makes the Data object frozen if it is not frozen already

Data.prototype.frozenCopy() -> returns the data object but pre-frozen. For Data object's already frozen can return "this"

Data.prototype.frozen - true when frozen, false otherwise.

I don't know why we wouldn't just use Object.freeze. It is not unreasonable to require support for the ES5 APIs as a prerequisite for the Data type.

# Oliver Hunt (16 years ago)

On Nov 5, 2009, at 4:01 PM, David-Sarah Hopwood wrote:

Charles Jolley wrote:

This looks like a good approach. I wonder if the Data/DataBuilder distinction could be handled better by using the Object.freeze() semantics. Even if the browser does not support freezing in the
general sense yet, you could borrow the ideas for data.

Probably the wrong API names, but here is the basic idea:

Data.prototype.copy() -> returns a mutable form of the Data object

Data.prototype.freeze() or Data.freeze(aDataObject) -> makes the Data object frozen if it is not frozen already

Data.prototype.frozenCopy() -> returns the data object but pre-frozen. For Data object's
already frozen can return "this"

Data.prototype.frozen - true when frozen, false otherwise.

I don't know why we wouldn't just use Object.freeze. It is not
unreasonable to require support for the ES5 APIs as a prerequisite for the Data
type.

I disagree here -- i believe mutable vs. immutable data is different
from unfrozen and frozen objects (though i agree that the function
names freeze and frozen are just asking for problems in conjunction
with ES5 :D ). There are plenty of times where I would want to
provide immutable data (the UA sharing content, etc), but i may still
want to modify the object itself.

Basically i think we're attempting to conflate the ES object with the
data wrapped by the ES object.

# Maciej Stachowiak (16 years ago)

Added public-script-coord since discussion is happening here.

On Nov 5, 2009, at 3:08 PM, Alex Russell wrote:

On Nov 5, 2009, at 2:48 PM, Maciej Stachowiak wrote:

I pulled together a rough proposal for representing binary data in
ECMAScript and posted it on public-script-coord. I think having
this is important for many W3C specs, but it is probably best
defined in ECMAScript. I'm posting a link here in case anyone is
interested and is not on the public-script-coord mailing list yet:

lists.w3.org/Archives/Public/public-script-coord/2009OctDec/0093.html

Looks promising! A couple of thoughts:

  • the middle-ground approach seems interesting, although having
    them not be "real" arrays feels like we're just kicking the can down
    the road WRT the large-ish number of things that could be thought of
    as arrays but which don't act like them (NodeList, arguments, etc.).

I understand the concern. Indeed, for things like NodeList or
HTMLCollection or arguments, it's often very desirable

My claim is that Data is not much like these things. I believe it is
more like String. It happens to be a sequence (of a very specific
type), but it's specialized enough to be worth treating differently.
Do people often regret that String is not an Array? My impression is
that this is not a common concern. That's why I imagined this design
point.

But imagine we decided to go the other way and try to make these
things arrays:

(a) I believe DataBuilder could be made an Array without introducing
serious problems. (b) I think Data could be made an array, but all the mutating methods
of Array (which is a great deal of them) will always fail, so that
seems like poor API design. I'd prefer to have a design where the
immutable object lacks mutating methods entirely, rather than having
mutating methods that always fail. That being said, just the read-only
methods from the Array prototype could be provided. (c) Array methods that return a new Array may be poor fits for Data/ DataBuilder - perhaps they could return a Data or DataBuilder instead
if they are provided.

  • any thoughts on type conversions? what does this do/return?:

    var bits = new Data("..."); var res = bits += "?";

    will strings have a toData() protocol? Should other objects be
    able to implement such a protocol? will there be a canonical byte
    format for all strings in the language?

Converting a String to a Data presumably involves charset encoding/ decoding. I have not made a proposal for that in my initial strawman.
I do think charset transcoding is an extremely useful feature for many
use cases though, especially ability to encode/decode UTF-8 and
WinLatin1. Since you need a choice of charset encoding to meaningfully
convert between binary data and strings, I think it's better not to
make it implicit, but rather have explicit named methods that can take
the encoding as a parameter. At least, that's my tentative thinking.
Another possibility is to assume that in cases where you don't specify
an encoding, strings are converted to/from UTF-16.

  • given that Data are array-like things that have the property of
    being packed (like arguments), maybe we're just missing a
    PackedArray superclass in general that could help w/ the efficiency
    concerns (irrespective of mutability).

I'm not sure what you mean by being packed or the similarity to
arguments. Arguments contains arbitrary values, Data contains only
unsigned integers in the range 0-255. Data is immutable. And with
Data, it may not often be desirable

  • what do you think about a toArray() method?

That can certainly be done. I am somewhat wary, because I think the
Array version will often be much less efficient in speed and memory,
and I believe it will rarely actually be useful. Imagine getting a raw
binary JPEG over the wire. It's extremely unlikely you'd want to
convert this to an Array, or call methods like filter() or map() on it.

  • do you envision any provision for multi-dimensional Data
    objects? E.g., <canvas> data.

The proposal here is that Data just holds raw binary data, without
imposing structure. If you want to use it to hold image data or a
frame buffer, then by my proposal, you have to do the indexing math
yourself.

, Maciej

# Maciej Stachowiak (16 years ago)

Using the freeze pattern is an interesting possibility that I hadn't
considered. Tentatively, I think having separate types for mutable and
immutable is better than using freeze(). Here are my reasons:

  • It seems like it may be useful to have an immutable Data (one that
    doesn't let you change the buffer) but which is not in other respects
    frozen.
  • The immutable type would not only freeze the types, but also not
    provide functioning mutation methods. I think it is cleaner design for
    the immutable form of the object to lack mutation methods entirely,
    rather than to have neutered mutation methods that always fail or
    always throw.

That being said, I think it's an alternative worth considering.

Is there enough interest in this topic in general to spend some of the
joint TC-39/HTML/WebApps session on it?

, Maciej

# Charles Jolley (16 years ago)

I hadn't thought about freeze affecting all other values on the
object. I agree that is not desirable.

Still, having separate object types for mutable and immutable objects
introduces a new pattern to JS. Why not follow the pattern used for
freeze(), seal() and preventExtension()? Here's another alternative
as an example:

Data.preventEdits(foo);

  • makes editable data not editable

Data.isEditable(foo);

  • returns true if editable

foo.copy();

  • returns a copy of foo, matching editable state. If foo is not
    editable, may return foo

foo.editableCopy();

  • returns an editable copy of foo, regardless of editable state

Incidentally this API above could be implemented using separate object
types as you suggest by making DataBuilder an extension of Data. This
would be an implementation detail though rather than a fundamental
part of the API.

# David-Sarah Hopwood (16 years ago)

Oliver Hunt wrote:

On Nov 5, 2009, at 4:01 PM, David-Sarah Hopwood wrote:

Charles Jolley wrote:

This looks like a good approach. I wonder if the Data/DataBuilder distinction could be handled better by using the Object.freeze() semantics. Even if the browser does not support freezing in the general sense yet, you could borrow the ideas for data.

Probably the wrong API names, but here is the basic idea:

Data.prototype.copy() -> returns a mutable form of the Data object

Data.prototype.freeze() or Data.freeze(aDataObject) -> makes the Data object frozen if it is not frozen already

Data.prototype.frozenCopy() -> returns the data object but pre-frozen. For Data object's already frozen can return "this"

Data.prototype.frozen - true when frozen, false otherwise.

I don't know why we wouldn't just use Object.freeze. It is not unreasonable to require support for the ES5 APIs as a prerequisite for the Data type.

I disagree here -- i believe mutable vs. immutable data is different from unfrozen and frozen objects [...]

Why? What would the hypothetical Data.prototype.freeze do that would be different to applying Object.freeze to a Data object?

(though i agree that the function names freeze and frozen are just asking for problems in conjunction with ES5 :D ). There are plenty of times where I would want to provide immutable data (the UA sharing content, etc), but i may still want to modify the object itself.

Oh, you mean that you want read-only Data objects backed by a mutable array. That is not the same thing as an immutable (or "frozen") Data object.

# Charles Jolley (16 years ago)

Why? What would the hypothetical Data.prototype.freeze do that would
be different to applying Object.freeze to a Data object?

For example, I might load an immutable JPG and then want to set:

imageData.name = "someimage.jpg";

to help me keep track of what the data is. Freezing would prevent
adding useful "expando" properties such as this as well as preventing
changing the data. This is equally non-JS-like IMO.

# Oliver Hunt (16 years ago)

On Nov 5, 2009, at 10:14 PM, David-Sarah Hopwood wrote:

Oliver Hunt wrote:

On Nov 5, 2009, at 4:01 PM, David-Sarah Hopwood wrote:

Charles Jolley wrote:

This looks like a good approach. I wonder if the Data/DataBuilder distinction could be handled better by using the Object.freeze() semantics. Even if the browser does not support freezing in the
general sense yet, you could borrow the ideas for data.

Probably the wrong API names, but here is the basic idea:

Data.prototype.copy() -> returns a mutable form of the Data object

Data.prototype.freeze() or Data.freeze(aDataObject) -> makes the Data object frozen if it is not frozen already

Data.prototype.frozenCopy() -> returns the data object but pre-frozen. For Data object's
already frozen can return "this"

Data.prototype.frozen - true when frozen, false otherwise.

I don't know why we wouldn't just use Object.freeze. It is not unreasonable to require support for the ES5 APIs as a prerequisite for the Data type.

I disagree here -- i believe mutable vs. immutable data is different from unfrozen and frozen objects [...]

Why? What would the hypothetical Data.prototype.freeze do that would
be different to applying Object.freeze to a Data object?

(though i agree that the function names freeze and frozen are just asking for problems in conjunction with
ES5 :D ). There are plenty of times where I would want to provide
immutable data (the UA sharing content, etc), but i may still want to modify
the object itself.

Oh, you mean that you want read-only Data objects backed by a
mutable array. That is not the same thing as an immutable (or "frozen") Data
object.

No, the issue here is that Charles has conflated object freezing with
immutable data, frozen objects and immutable data are not the same
thing -- for instance in the DOM I cannot set indices of a NodeList,
but the NodeList does not need to be frozen.

It is perfectly reasonable to have raw data that is immutable without
wanting the object that represents it to itself be immutable.

# David-Sarah Hopwood (16 years ago)

Oliver Hunt wrote:

On Nov 5, 2009, at 10:14 PM, David-Sarah Hopwood wrote:

Oliver Hunt wrote:

I disagree here -- i believe mutable vs. immutable data is different from unfrozen and frozen objects [...]

Why? What would the hypothetical Data.prototype.freeze do that would be different to applying Object.freeze to a Data object?

(though i agree that the function names freeze and frozen are just asking for problems in conjunction with ES5 :D ). There are plenty of times where I would want to provide immutable data (the UA sharing content, etc), but i may still want to modify the object itself.

Oh, you mean that you want read-only Data objects backed by a mutable array. That is not the same thing as an immutable (or "frozen") Data object.

No, the issue here is that Charles has conflated object freezing with immutable data,

That isn't conflation; they're the same.

frozen objects and immutable data are not the same thing

You are mistaken. This is a case where terminology across languages is quite consistent, and is as I've described it. "Frozen" means exactly the same thing as "immutable", and implies that the state of the object will never be observed to change [*]. An object is "read-only" if there is no means to directly change its state via a reference to it, which does not necessarily imply that its state cannot be observed to change.

-- for instance in the DOM I cannot set indices of a NodeList, but the NodeList does not need to be frozen.

NodeList objects are read-only.

[*] It is ambiguous whether indirectly referenced state can change; if it is important that it cannot, say "deep-frozen" or "deeply immutable".

# David-Sarah Hopwood (16 years ago)

David-Sarah Hopwood wrote:

Oliver Hunt wrote:

On Nov 5, 2009, at 10:14 PM, David-Sarah Hopwood wrote:

Oliver Hunt wrote:

I disagree here -- i believe mutable vs. immutable data is different from unfrozen and frozen objects [...] Why? What would the hypothetical Data.prototype.freeze do that would be different to applying Object.freeze to a Data object?

(though i agree that the function names freeze and frozen are just asking for problems in conjunction with ES5 :D ). There are plenty of times where I would want to provide immutable data (the UA sharing content, etc), but i may still want to modify the object itself. Oh, you mean that you want read-only Data objects backed by a mutable array. That is not the same thing as an immutable (or "frozen") Data object. No, the issue here is that Charles has conflated object freezing with immutable data,

That isn't conflation; they're the same.

Sorry, I understand what you meant now.

An object could of course have immutable data properties but other properties that are mutable. But that can be achieved already using Object.defineProperties, if it were considered useful. I don't see it as particularly useful, given that you can achieve a similar effect more simply by using a mutable "record" object that has an immutable Data object as one of its properties.

Remember, we have Object.freeze regardless. Therefore, if we have a mutable byte array, then applying Object.freeze to it yields an immutable byte array. So adding an extra type to represent immutable byte arrays is redundant.

# Brendan Eich (16 years ago)

On Nov 5, 2009, at 11:03 PM, David-Sarah Hopwood wrote:

No, the issue here is that Charles has conflated object freezing with immutable data,

That isn't conflation; they're the same.

Not necessarily. Counter-example: a JS String object wrapping a JS
string primitive is mutable but its character data (the primitive
string) is apparently immutable.

# Maciej Stachowiak (16 years ago)

On Nov 5, 2009, at 11:03 PM, David-Sarah Hopwood wrote:

Oliver Hunt wrote:

-- for instance in the DOM I cannot set indices of a NodeList, but
the NodeList does not need to be frozen.

NodeList objects are read-only.

But the values they return may change over time due to factors other
than manipulating the NodeList.

, Maciej

# Maciej Stachowiak (16 years ago)

On Nov 5, 2009, at 5:14 PM, Charles Jolley wrote:

I hadn't thought about freeze affecting all other values on the
object. I agree that is not desirable.

Still, having separate object types for mutable and immutable
objects introduces a new pattern to JS. Why not follow the pattern
used for freeze(), seal() and preventExtension()? Here's another
alternative as an example:

Data.preventEdits(foo);

  • makes editable data not editable

Data.isEditable(foo);

  • returns true if editable

foo.copy();

  • returns a copy of foo, matching editable state. If foo is not
    editable, may return foo

foo.editableCopy();

  • returns an editable copy of foo, regardless of editable state

Incidentally this API above could be implemented using separate
object types as you suggest by making DataBuilder an extension of
Data. This would be an implementation detail though rather than a
fundamental part of the API.

I don't think that would work, unless Data.preventEdits(foo) returns a
new value.

I think the disadvantage of this design is that it puts all the
mutation methods on immutable instances, where they are serve no
purpose other than to throw when called. I think it is cleaner design
for the immutable interface to lack mutation methods, rather than have
mutation methods that always fail. I think designs where part of the
normal workflow puts an object in a state where some methods always
throw is poor OO design.

It's true that ECMAScript has not historically had mutable/immutable
pairs of types, but this is a common pattern in other languages, such
as Objective-C (NSString vs. NSMutableString), Java (String vs.
StringBuilder), various recent Lisp dialects (where there are often
both mutable and immutable lists) and arguably event C++ (const string
and string expose different sets of method).

That being said, I can see how there is some value to aligning with
the evolving ECMAScript pattern. Personally I think of Object.freeze
as a tool for building new types that are meant to be immutable, or
for exporting partially restricted facade interfaces, not as something
one should be doing to random objects in the course of normal
programming.

, Maciej

# P T Withington (16 years ago)

On 2009-11-05, at 19:42, Maciej Stachowiak wrote:

My claim is that Data is not much like these things. I believe it is
more like String. It happens to be a sequence (of a very specific
type), but it's specialized enough to be worth treating differently.
Do people often regret that String is not an Array?

Data is like an 8-bit "null encoded" String. Which makes me wonder if
you really just want to extend String to allow different encodings.
But I also regret String not being and Array. Others must have too,
because at one point I'm sure there was a proposal to make [] on
string mean charAt?

# Breton Slivka (16 years ago)

On Sat, Nov 7, 2009 at 12:43 AM, P T Withington <ptw at pobox.com> wrote:

On 2009-11-05, at 19:42, Maciej Stachowiak wrote:

My claim is that Data is not much like these things. I believe it is more like String. It happens to be a sequence (of a very specific type), but it's specialized enough to be worth treating differently. Do people often regret that String is not an Array?

Data is like an 8-bit "null encoded" String. Which makes me wonder if you really just want to extend String to allow different encodings. But I also regret String not being and Array. Others must have too, because at one point I'm sure there was a proposal to make [] on string mean charAt?

Sorry to get philisophical here, but data is anything you happen to interpret it as, it's not any particular thing. It could be an image, it could be a string, it could be machine instructions, it could be a sequence of octets, it could be hexidecimal. Asking what data is like is a little bit useless. The question to ask is what kind of api makes the most sense for conveniently manipulating data on a low level, and in a way that isn't unfeasably slow, or awkward. What kind of api will allow the programmer to efficiently interpret that data as things other than what are built into the browser. I think the C language has possibly biased us into thinking of data as a sequence of 8-bit bytes, when that is just what happened to be convenient for C. There are other ways to think about data: even within C you can define a struct, point it at some area of memory, and the struct magically interprets that data as an object like thing. Or you can even scanf. These concepts do not depend on a byte stream, or "string" interpretation of data.

By the way, it might not be standard, but "hello world"[0] returns "h" on anything but IE, so far as I've tried.

My question is (since nobody seems to have brought it up yet) is how does this proposal fit into the html5 canvas data api? (not the data URI api).

If you call canvascontext.getImageData(0,0,width,height), you get an object with some mutable properties, and a data property holding what looks like an array of numbers between 0 and 255. The data property supposedly has an efficient implementation. There is also a putImageData function which accepts a data object, but not an array object, and a constructor, context.createImageData(width,height);

This is already in browsers, and is in the process of being standardised in html5. I just wonder what happens if ecmascript then adds its own data object, how would it interact with the canvas data apis?

# Mike Shaver (16 years ago)

On Fri, Nov 6, 2009 at 9:31 AM, Breton Slivka <zen at zenpsycho.com> wrote:

I think the C language has possibly biased us into thinking of data as a sequence of 8-bit bytes, when that is just what happened to be convenient for C.

For types called ByteArray and ByteVector, I think a byte orientation is appropriate. Doing things other than bytes brings endianness into play (ask the WebGL guys, if you know any)

My question is (since nobody seems to have brought it up yet) is how does this proposal fit into the html5 canvas data api? (not the data URI api).

I would expect that there would be some harmonization desired there, but:

If you call canvascontext.getImageData(0,0,width,height), you get an object with some mutable properties, and a data property holding what looks like an array of numbers between 0 and 255. The data property supposedly has an efficient implementation.

Using that data property may be more efficient than using an Array, but that depends a bunch on the implementation choices for the JS engine and Canvas implementation.

It was also proposed, though I don't know if it is generally accepted, that the Canvas Data object clamp its values to 255 on set, so if people feel that's a necessary behaviour (I personally don't, but my opinion carries less than the mean weight in these discussions) then ByteArray might not be suitable.

The Canvas Data object is also sort of half-mutable: you can change the values of the data elements, but can't change the size of the "array". That could turn out to be a useful property for optimized access to it, since you can amortize length checks quite well.

Mike

# Maciej Stachowiak (16 years ago)

On Nov 6, 2009, at 7:13 AM, Mike Shaver wrote:

On Fri, Nov 6, 2009 at 9:31 AM, Breton Slivka <zen at zenpsycho.com>
wrote:

I think the C language has possibly biased us into thinking of data as a sequence of 8-bit
bytes, when that is just what happened to be convenient for C.

For types called ByteArray and ByteVector, I think a byte orientation is appropriate. Doing things other than bytes brings endianness into play (ask the WebGL guys, if you know any)

At some point, if we want to make it easy and efficient for ECMAScript
to do something like decode a GIF, we may want to provide facilities
for converting between host and network byte order. My recommendation
would be to leave that out of the v1 API though.

My question is (since nobody seems to have brought it up yet) is how does this proposal fit into the html5 canvas data api? (not the data URI api).

I would expect that there would be some harmonization desired there,
but:

If you call canvascontext.getImageData(0,0,width,height), you get an object with some mutable properties, and a data property holding what looks like an array of numbers between 0 and 255. The data property supposedly has an efficient implementation.

Using that data property may be more efficient than using an Array, but that depends a bunch on the implementation choices for the JS engine and Canvas implementation.

It was also proposed, though I don't know if it is generally accepted, that the Canvas Data object clamp its values to 255 on set, so if people feel that's a necessary behaviour (I personally don't, but my opinion carries less than the mean weight in these discussions) then ByteArray might not be suitable.

The Canvas Data object is also sort of half-mutable: you can change the values of the data elements, but can't change the size of the "array". That could turn out to be a useful property for optimized access to it, since you can amortize length checks quite well.

CanvasPixelArray seems close enough to a mutable general-purpose
binary data container that maybe it's worth considering whether to
specifically serve this case (fixed length, mutable contents) at the
ECMAScript level. It would then likely be possible to change
CanvasPixelArray to inherit from a general-purpose binary data
container without breaking compat.

, Maciej

# Charles Jolley (16 years ago)

I think the disadvantage of this design is that it puts all the
mutation methods on immutable instances, where they are serve no
purpose other than to throw when called. I think it is cleaner
design for the immutable interface to lack mutation methods, rather
than have mutation methods that always fail. I think designs where
part of the normal workflow puts an object in a state where some
methods always throw is poor OO design.

Well, let me argue this for a second...

Well designed systems often have objects with an internal state.
Features become available or unavailable on that object based on the
state. If you try to use a feature while the object is in the wrong
state, the object should throw an error. This is good API. It makes
it clear to the developer when they try to use the object in the wrong
way.

The API I'm arguing for envisions the Data object having some internal
state [i.e. isEditable] and a part of the API is available or not
depending on that state.

Additionally, JavaScript often uses the duck-typing pattern [i.e.
ignore the "inheritance" of an object and just check its capabilities
before acting on it]. This pattern vastly simplifies JS code as you
don't have to shuffle references around so often and can reduce memory
allocs.

That said, I will acknowledge there are many cases where methods that
throw are often indicative of bad OO design. I see this mostly in C++
and Java where devs define abstract base classes with lots of methods
that do nothing but throw. This is the opposite of what we want.
It's ugly and leads to code bloat.

In this case though, I would argue that a few if() statements at the
front of a primitive or two would actually reduce the amount of code
in regular running applications and means you only need to implement
one object.

It's true that ECMAScript has not historically had mutable/immutable
pairs of types, but this is a common pattern in other languages,
such as Objective-C (NSString vs. NSMutableString), Java (String vs.
StringBuilder), various recent Lisp dialects (where there are often
both mutable and immutable lists) and arguably event C++ (const
string and string expose different sets of method).

Most of the examples you give here, are statically-types [to various
degrees] class-based languages where inheritance chains are integral
to the design. This is not the case with JavaScript.

The two-class pattern is more important in those cases than it is here.

That being said, I can see how there is some value to aligning with
the evolving ECMAScript pattern. Personally I think of Object.freeze
as a tool for building new types that are meant to be immutable, or
for exporting partially restricted facade interfaces, not as
something one should be doing to random objects in the course of
normal programming.

Allow me to withdraw my previous suggestion of freeze(). It's not the
right tool for this job. The general pattern though is well
established for freeze(), seal() and extensible. I think it would
work well here too.

-Charles

PS. I'm happy to have data object support at all; this isn't really
critical to the feature IMO just an argument about which API would be
most useful to developers. I think both proposed models would be
acceptable.

# David Flanagan (16 years ago)

P T Withington wrote:

I also regret String not being and Array. Others must have too, because at one point I'm sure there was a proposal to make [] on string mean charAt?

This is part of ES5. See 15.5.5.2 in the spec.

David Flanagan
# Brendan Eich (16 years ago)

On Nov 6, 2009, at 5:43 AM, P T Withington wrote:

On 2009-11-05, at 19:42, Maciej Stachowiak wrote:

My claim is that Data is not much like these things. I believe it
is more like String. It happens to be a sequence (of a very
specific type), but it's specialized enough to be worth treating
differently. Do people often regret that String is not an Array?

Data is like an 8-bit "null encoded" String. Which makes me wonder
if you really just want to extend String to allow different encodings.

Not for the Data use-cases.

Strings are used for binary data, which is tying our hands in
supporting UTF-16 properly. Separate issue but we should not
complicate String further IMHO.

But I also regret String not being and Array.

I agree with Maciej that having mutating methods be no-ops or throwers
strongly suggests we not mix Array and String directly. Being able to
apply non-mutating Array methods to string (primitive, even) arguments
is ok. Splitting a string into an Array and mutating, then joining --
very ok. But I don't see why you want String to be (is-a) an Array.

Others must have too, because at one point I'm sure there was a
proposal to make [] on string mean charAt?

David Flanagan beat me to it: in ES5 and most browsers.

# Maciej Stachowiak (16 years ago)

On Nov 6, 2009, at 5:43 AM, P T Withington wrote:

On 2009-11-05, at 19:42, Maciej Stachowiak wrote:

My claim is that Data is not much like these things. I believe it
is more like String. It happens to be a sequence (of a very
specific type), but it's specialized enough to be worth treating
differently. Do people often regret that String is not an Array?

Data is like an 8-bit "null encoded" String. Which makes me wonder
if you really just want to extend String to allow different
encodings. But I also regret String not being and Array. Others
must have too, because at one point I'm sure there was a proposal to
make [] on string mean charAt?

ES5 does have bracket index access to the individual characters. But
it does not make String inherit from Array.prototype, or add all of
the Array methods. To make it more concrete, have you ever wished you
could use methods like map(), filter(), reduce() or join() on a String?

, Maciej

# Alex Russell (16 years ago)

On Nov 5, 2009, at 11:03 PM, David-Sarah Hopwood wrote:

Oliver Hunt wrote:

On Nov 5, 2009, at 10:14 PM, David-Sarah Hopwood wrote:

Oliver Hunt wrote:

I disagree here -- i believe mutable vs. immutable data is
different from unfrozen and frozen objects [...]

Why? What would the hypothetical Data.prototype.freeze do that
would be different to applying Object.freeze to a Data object?

(though i agree that the function names freeze and frozen are just asking for problems in conjunction
with ES5 :D ). There are plenty of times where I would want to provide
immutable data (the UA sharing content, etc), but i may still want to
modify the object itself.

Oh, you mean that you want read-only Data objects backed by a
mutable array. That is not the same thing as an immutable (or "frozen") Data object.

No, the issue here is that Charles has conflated object freezing with immutable data,

That isn't conflation; they're the same.

frozen objects and immutable data are not the same thing

You are mistaken. This is a case where terminology across languages is quite consistent, and is as I've described it. "Frozen" means
exactly the same thing as "immutable", and implies that the state of the object
will never be observed to change [*]. An object is "read-only" if there
is no means to directly change its state via a reference to it, which does
not necessarily imply that its state cannot be observed to change.

-- for instance in the DOM I cannot set indices of a NodeList, but
the NodeList does not need to be frozen.

NodeList objects are read-only.

This is an artifact of the way they can be created today (no exposed
ctor for them, no exposed prototype, only alien functions can generate
them, etc.). It should not be held up as a desireable design point or
a counter to something else. Mutable NodeList's which implement Array
semantics and mutability would be extremely useful.

# Alex Russell (16 years ago)

On Nov 6, 2009, at 11:30 AM, Maciej Stachowiak wrote:

On Nov 6, 2009, at 5:43 AM, P T Withington wrote:

On 2009-11-05, at 19:42, Maciej Stachowiak wrote:

My claim is that Data is not much like these things. I believe it
is more like String. It happens to be a sequence (of a very
specific type), but it's specialized enough to be worth treating
differently. Do people often regret that String is not an Array?

Data is like an 8-bit "null encoded" String. Which makes me wonder
if you really just want to extend String to allow different
encodings. But I also regret String not being and Array. Others
must have too, because at one point I'm sure there was a proposal
to make [] on string mean charAt?

ES5 does have bracket index access to the individual characters. But
it does not make String inherit from Array.prototype, or add all of
the Array methods. To make it more concrete, have you ever wished
you could use methods like map(), filter(), reduce() or join() on a
String?

join's an oddball since it's effectively a no-op, but map() and
filter(), absolutely.

# Mike Shaver (16 years ago)

On Fri, Nov 6, 2009 at 4:39 PM, Alex Russell <alex at dojotoolkit.org> wrote:

On Nov 6, 2009, at 11:30 AM, Maciej Stachowiak wrote:

ES5 does have bracket index access to the individual characters. But it does not make String inherit from Array.prototype, or add all of the Array methods. To make it more concrete, have you ever wished you could use methods like map(), filter(), reduce() or join() on a String?

join's an oddball since it's effectively a no-op, but map() and filter(), absolutely.

I've used join too (though not with an empty separator, indeed), and map/filter for various string pack and encode operations, but I don't think that I would mind too much having to say

Array.join(strOrDataThing, "\n");

instead of

strOrData.filter(function (v) { return v.charCodeAt(0) < 128; });

Mike

# Maciej Stachowiak (16 years ago)

On Nov 6, 2009, at 1:39 PM, Alex Russell wrote:

On Nov 6, 2009, at 11:30 AM, Maciej Stachowiak wrote:

On Nov 6, 2009, at 5:43 AM, P T Withington wrote:

On 2009-11-05, at 19:42, Maciej Stachowiak wrote:

My claim is that Data is not much like these things. I believe it
is more like String. It happens to be a sequence (of a very
specific type), but it's specialized enough to be worth treating
differently. Do people often regret that String is not an Array?

Data is like an 8-bit "null encoded" String. Which makes me
wonder if you really just want to extend String to allow different
encodings. But I also regret String not being and Array. Others
must have too, because at one point I'm sure there was a proposal
to make [] on string mean charAt?

ES5 does have bracket index access to the individual characters.
But it does not make String inherit from Array.prototype, or add
all of the Array methods. To make it more concrete, have you ever
wished you could use methods like map(), filter(), reduce() or
join() on a String?

join's an oddball since it's effectively a no-op, but map() and
filter(), absolutely.

Can you give specific use cases for these, maybe with hypothetical
code examples?

Join would not be a no-op, and indeed you can use Array.prototype.join
on a String today:

javascript:alert(Array.prototype.join.call("abcde", "123")) ==>
"a123b123c123d123e"

Not a no-op but I'm not sure it's useful.

, Maciej