Re: ES3.1 Object static methods rationale document

2008-07-17 Thread Garrett Smith
On Thu, Jul 17, 2008 at 8:37 AM, John Resig <[EMAIL PROTECTED]> wrote:
>
> I wanted to bring up some further evidence for the widespread use of an 
> extend() method. Here are the top 5 JavaScript libraries and their associated 
> versions of "Object.extend()":
>

> There are a couple points that are very important here:
> 1) They all extend the base object with the enumerable properties at least 
> one other object.

Not true. YAHOO.lang.extend uses prototypal inheritance.

> 2) There is very little done to prevent properties coming in from 
> [SomeObject].prototype - this is mostly because libraries opt not to use 
> .hasOwnProperty() in favor of speed and/or cross-browser compatibility (older 
> versions of Safari and IE Mac don't have hasOwnProperty).

Carelessness could be another reason. It is not hard to find bugs by
looking at the latest version of YAHOO.lang.extend, for example.

Garrett

> --John

[snip top post]
___
Es4-discuss mailing list
Es4-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es4-discuss


Surprising semantics

2008-07-17 Thread Ingvar von Schoultz
These are some impressions looking at what I expect from the
language, and how some things in the specification can cause
confusion.

I would have contributed here during the discussions, but I
discovered the mailing lists just a couple of days ago.

I expect the compiler's interpretation of program-code text
to be close to my intuitive understanding of what the text
says. It's very unfortunate if keywords have unexpected
meanings that cause mysterious side effects.

If I learn that ECMAScript will let me change my var(iables)
into const(ants) I expect this to turn them into constants, in
the sense that trying to change their value will be considered
an error. It's very disappointing that by default they are
instead defined to have the baffling and mysterious behavior
of silently ignoring an attempt to change them, acting as if
no error had occurred.

You'll have to keep this oddity in mind at all times, and even
then errors related to this will sometimes cause symptoms to
appear far from where the error is, costing quite some time
to explore. Why doesn't my program change its behavior even
though I'm provoking changes? Where in this big program's
complicated sequence of events is the change silently, secretly
lost?

If instead you use var, at least the problems that can come
from this will tend to give symptoms closely connected to the
incorrect change in the value.

So this is a disappointing red flag: Don't use const, it is
likely to cause baffling problems and unlikely to help.

Unfortunately there's another problem with const that is much
more important. I often use constants for conditional settings:

 if (Debugging)
 {   var DatabaseName = "TestDatabase";
 var DisplayCount = 5;
 }
 else
 {   var DatabaseName = "RealDatabase";
 var DisplayCount = 15;
 }

The redundant "var"s are a defensive habit, omitting them would
be a warning about accesses outside the current scope.

If I haven't been warned, and hear that ECMAScript understands
"const", I expect that replacing "var" with "const" will change
the above from variables into constants. The keyword in no way
suggests that it will hide them from view. If they disappear
I'll inevitably consider such a completely unrelated side effect
a compiler bug.

Because of this I'm unhappy about the conclusions of ES3.1 that
the visibility scope of "const" should be the enclosing brace-
delimited block. Such intricate semantics hidden in words that
express something completely unrelated will make the language
seem difficult and fraught with hidden surprises.

I much prefer what ES4 says in various places on the website:
that you express this localness with "let const" and "let function".
One block-scope keyword for all block-scope visibility. Consistency
and clarity.

However this brings me to the unfortunate word "let". Although
this word has a precise and clear technical meaning for the
initiate, for us in the unwashed masses I can't see that the
English word "let" gives even the remotest suggestion of local
containment. In fact it suggests very clearly that it's related
to the "=" that so often follows:

 if (x == 5)
 {   let y = 3;
 }

"If x is 5, then let y equal 5." There's an almost inescapably
strong suggestion that "let" is a phrasing of the assignment
expression, and therefore can't have anything to do with the
braces.

I think ECMAScript should be easily accessible to us in the
unwashed masses. It becomes much more intuitively accessible
if it uses a word that strongly implies localness:

 {   if (x == 5)
 {   local y = 3;
 }
 local const Debugging = false;
 for (local Key in List)
 ++List [Key];
 }

You get plain English sentences that express quite accurately
what they're supposed to mean. The programmer won't be the
least surprised if a value gets hidden by "local".

When people want to write let expressions, if they have to
write "local" instead of "let" I don't think this will cause
problems. I'm sure the initiate are sophisticated enough that
they can adapt to this.

Apart from this, I think the scoping arrangements would
become significantly simpler and clearer if the language
made a very clear, really visible, intuitively accessible
distinction between two different types of block, and allowed
you to choose either type of block wherever this made sense.

My suggestion is to introduce a clearly distinct new and
better block. This block should be delimited by {{ and }}
if it's at all possible, and I think it is. No keyword,
just {{ and }}. This better block would bind vars, consts
and functions, just like function scopes do. In fact function
scopes and {{ }} would be the same thing, as seen by the
programmer.

An important advantage with {{ }} is that you can keep
everything contained without tedious and error-prone
repetition of local (or let) everywhere. And the scoping
is prominently visible and clearly structured.

It may seem odd that I say

Re: ES3.1 Object static methods rationale document

2008-07-17 Thread Ingvar von Schoultz
John Resig wrote:
> I wanted to bring up some further evidence for the widespread use of an 
> extend() method.

I always need both these functions. However my ObjectClone
function is just a single statement that calls the other function:
return ObjectMerge (Source, {}). So I see Clone as trivial syntactic
sugar. Merge is necessary and costs work and processing time.

Ingvar





> Here are the top 5 JavaScript libraries and their associated versions of 
> "Object.extend()":
> 
> 
> == jQuery.js:
> 
> (jQuery also does deep extend - but that isn't relevant here.)
> 
> jQuery.extend = jQuery.fn.extend = function() {
>   var target = arguments[0] || {}, i = 1, length = arguments.length, 
> options;
> 
>   if ( typeof target != "object" && typeof target != "function" )
>   target = {};
> 
>   if ( length == i ) {
>   target = this;
>   --i;
>   }
> 
>   for ( ; i < length; i++ ) {
>   if ( (options = arguments[ i ]) != null ) {
>   for ( var name in options ) {
>   target[ name ] = options[ name ];
>   }
>   }
>   }
> 
>   return target;
> };
> 
> 
> == Prototype.js:
> 
> Object.extend = function(destination, source) {
>   for (var property in source)
> destination[property] = source[property];
>   return destination;
> };
> 
> == Mootools.js:
> 
> var $extend = function(){
>   var args = arguments;
>   if (!args[1]) args = [this, args[0]];
>   for (var property in args[1]) args[0][property] = args[1][property];
>   return args[0];
> };
> 
> == Dojo Toolkit:
> 
> dojo._mixin = function(obj, props){
>   var tobj = {};
>   for(var x in props){
>   if(tobj[x] === undefined || tobj[x] != props[x]){
>   obj[x] = props[x];
>   }
>   }
>   // IE doesn't recognize custom toStrings in for..in
>   if(d["isIE"] && props){
>   var p = props.toString;
>   if(typeof p == "function" && p != obj.toString && p != 
> tobj.toString &&
>   p != "\nfunction toString() {\n[native code]\n}\n"){
>   obj.toString = props.toString;
>   }
>   }
>   return obj; // Object
> }
> 
> dojo.mixin = function(obj){
>   for(var i=1, l=arguments.length; i   d._mixin(obj, arguments[i]);
>   }
>   return obj; // Object
> }
> 
> == Yahoo UI:
> 
> YAHOO.lang.augmentObject = function(r, s) {
> if (!s||!r) {
> throw new Error("Absorb failed, verify dependencies.");
> }
> var a=arguments, i, p, override=a[2];
> if (override && override!==true) { // only absorb the specified 
> properties
> for (i=2; i r[a[i]] = s[a[i]];
> }
> } else { // take everything, overwriting only if the third parameter 
> is true
> for (p in s) { 
> if (override || !(p in r)) {
> r[p] = s[p];
> }
> }
> 
> L._IEEnumFix(r, s);
> }
> };
> 
> There are a couple points that are very important here:
> 1) They all extend the base object with the enumerable properties at least 
> one other object.
> 2) There is very little done to prevent properties coming in from 
> [SomeObject].prototype - this is mostly because libraries opt not to use 
> .hasOwnProperty() in favor of speed and/or cross-browser compatibility (older 
> versions of Safari and IE Mac don't have hasOwnProperty).
> 3) A couple of the implementations take multiple source objects with which to 
> extend the base object.
> 
> The implementations in the libraries don't deal with nearly as many edge 
> cases as they should (such as the aforementioned hasOwnProperty - or getters 
> and setters) which is something that can be done in a language 
> implementation. A language implementation of .extend() should certainly also 
> allowing non-enumerable properties to be extended, as well (considering that 
> this wont be possible - or will be very difficult to implement - from a 
> pure-script perspective).
> 
> While Object.clone will certainly be useful in, and of, itself - it's not a 
> replacement for an extend method.
> 
> I have a pure-JavaScript version of Object.extend() that I'm working on - and 
> I'm building a test suite for it, as well (to make sure all edge cases are 
> properly defined and handled):
> http://ejohn.org/files/object-extend.js
> 
> I'll be updating this file throughout the day. I'll post back when I feel as 
> if I have a reasonable test suite.
> 
> --John
> 
> - Original Message -
> From: "Allen Wirfs-Brock" <[EMAIL PROTECTED]>
> To: "Robert Sayre" <[EMAIL PROTECTED]>, "Mark S. Miller" <[EMAIL PROTECTED]>
> Cc: "es3 x-discuss" <[EMAIL PROTECTED]>, es4-discuss@mozilla.org
> Sent: Wednesday, July 16, 2008 7:10:21 PM GMT -05:00 US/Canada Eastern
> S

Re: ES3.1 Object static methods rationale document

2008-07-17 Thread liorean
2008/7/16 Allen Wirfs-Brock <[EMAIL PROTECTED]>:
> I've up loaded to the wiki a new document titled:  "Proposed ECMAScript 3.1
> Static Object Functions: Use Cases and Rationale"

I've got one objection to Object.getPrototypeOf: It allows inspection
and modification of prototype chains established like this:

function F(){}
/* add some prototype properties here */
newObj=new F;
F.prototype={constructor:F};

In ES3.0, this allows you to create unexposed and protected prototype
chains. There's no way to recover newObj.[[Prototype]] once
F.prototype has been changed in ES3.0 code. Granted, I've never seen
this pattern used in production code except incidentally, but it's a
guarantee that ES3.0 does have nonetheless and I could see myself
using it if I really wanted to protect an object's prototype from
being modified.
-- 
David "liorean" Andersson
___
Es4-discuss mailing list
Es4-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es4-discuss


Re: ES3.1 Object static methods rationale document

2008-07-17 Thread John Resig

I wanted to bring up some further evidence for the widespread use of an 
extend() method. Here are the top 5 JavaScript libraries and their associated 
versions of "Object.extend()":


== jQuery.js:

(jQuery also does deep extend - but that isn't relevant here.)

jQuery.extend = jQuery.fn.extend = function() {
var target = arguments[0] || {}, i = 1, length = arguments.length, 
options;

if ( typeof target != "object" && typeof target != "function" )
target = {};

if ( length == i ) {
target = this;
--i;
}

for ( ; i < length; i++ ) {
if ( (options = arguments[ i ]) != null ) {
for ( var name in options ) {
target[ name ] = options[ name ];
}
}
}

return target;
};


== Prototype.js:

Object.extend = function(destination, source) {
  for (var property in source)
destination[property] = source[property];
  return destination;
};

== Mootools.js:

var $extend = function(){
var args = arguments;
if (!args[1]) args = [this, args[0]];
for (var property in args[1]) args[0][property] = args[1][property];
return args[0];
};

== Dojo Toolkit:

dojo._mixin = function(obj, props){
var tobj = {};
for(var x in props){
if(tobj[x] === undefined || tobj[x] != props[x]){
obj[x] = props[x];
}
}
// IE doesn't recognize custom toStrings in for..in
if(d["isIE"] && props){
var p = props.toString;
if(typeof p == "function" && p != obj.toString && p != 
tobj.toString &&
p != "\nfunction toString() {\n[native code]\n}\n"){
obj.toString = props.toString;
}
}
return obj; // Object
}

dojo.mixin = function(obj){
for(var i=1, l=arguments.length; ihttp://ejohn.org/files/object-extend.js

I'll be updating this file throughout the day. I'll post back when I feel as if 
I have a reasonable test suite.

--John

- Original Message -
From: "Allen Wirfs-Brock" <[EMAIL PROTECTED]>
To: "Robert Sayre" <[EMAIL PROTECTED]>, "Mark S. Miller" <[EMAIL PROTECTED]>
Cc: "es3 x-discuss" <[EMAIL PROTECTED]>, es4-discuss@mozilla.org
Sent: Wednesday, July 16, 2008 7:10:21 PM GMT -05:00 US/Canada Eastern
Subject: RE: ES3.1 Object static methods rationale document

As far as I can recall, we didn't discuss a specific formulation that 
corresponds to Object.extend but we have considered (and arguably provided) 
pretty much equivalent functionality in our proposal. I assume that at least 
Doug, Adam, or Kris were specifically aware of Object.extend and would have 
broad it up if it was relevant.  One reason, it probably wasn't was that the 
starting point of our design was the full reification and control of properties 
and their attributes rather than just copying properties. By the time we got 
around to cloning/copying issues we already had establish some core elements of 
our overall design.

Doing a bit of search I've found several different variants of the extend 
function.  Some are defined on Object, some on Object.prototype.  Some use a 
single source object and some use multiple source objects.  What they all seem 
to have in common is that they copy the enumerable methods from one (or more) 
object to another.

The most common use case seems to be the one where the target object is a newly 
instantiated object without any properties of its own. That use case (at least 
for variants of extend that only take a single source object) is most directly 
supported by the Object.clone function in our proposal. However, Object.clone 
is defined to be a more comprehensive object duplication process than is 
performed by extend.  It duplicates all own properties and their attributes and 
any internal properties such as its [[Value]] property if it has one.

I have personally considered whether there should be some sort of mechanism to 
filter the properties copied by Object.clone.  For example, you might only copy 
non getter/setter properties, or only enumerable properties, or perhaps filter 
out ReadOnly properties. However, I never proposed any of these for the ES3.1 
spec. because I have yet to find a use case that was sufficiently compelling or 
pervasive enough to justify making the interface to Object.clone more complex 
(in contrast, see the explanation in the rationale document for why we added a 
second argument to Object.create).  If you want to do that sort of filtering 
you can do it using Object.wontbecalledgetProperty and Object.defineProperty.  
If you just want a fast and comprehensive copy use Object.clone.

The other obvious use case would seem to be adding some "mix-in" behavior to an 
object (some of the descriptions of extend on the web call this "inheritance"