Code Guidelines

D

Dmitry A. Soshnikov

Dmitry said:
var foo = function () {
  alert(arguments[0]);

(function () {return 'x';})()
Meanwhile, this form (where we've also "forgot" semicolon after `foo')
will throw an exception.

Thank for that example. It can be very hard to catch that, especially
if returned value from `foo` is a reference to object which have
internal [[Call]] method.

var foo = function () {
  return arguments[0];

}

(function () {return 'x';})();

Expected behavior in unexpected way.

var foo = function () {
  return function(){};

}

(function () {return 'x';})();

There are no error, and absolutely unexpected behavior in first look,
but actually is it normal and expected behavior.

Yep, absolutely right.

/ds
 
A

Asen Bozhilov

Garrett said:
Certainly it can be. IE throws errors with delete on window properties,
though not on global variables.

var x = 10;
this.y = 11;
delete x; // false;
delete y: // error.
^;
Typo correction ;~)

More suggestions for "Code Guidelines".

Doesn't have information:
- About `11.10 Binary Bitwise Operators` and how they converted
operands `ToInt32`. Which mean, with `Bitwise Operators` can loose
precision. See below:

var x = Math.pow(2, 30);
window.alert(x); //1073741824
window.alert(x & x); //1073741824

x = Math.pow(2, 34);
window.alert(x); //17179869184
window.alert(x & x); //0

- About comparison of NaN values:

window.alert(NaN === NaN); //false
window.alert(isNaN(NaN)); //true

- In which cases primitive values will be converted automatically
ToObject and ToObject with which values throw TypeError.

window.alert('str'.concat);

try {
null.foo;
}catch(e) {
window.alert(e instanceof TypeError); //true
}

try {
with(undefined);
}catch(e) {
window.alert(e instanceof TypeError); //true
}

- About for-in loops. That is related with augmentation of built-in
objects prototype chain and with my previous item.

try {
for (var i in null);
}catch(e) {
window.alert(e);
}

I'm cannot found browser ECMA-262 implementation which follow the
specification in `12.6.4 The for-in Statement` step 3 in `for
( LeftHandSideExpression in Expression ) Statement` and step 4 in `for
( var VariableDeclarationNoIn in Expression )`
| Call ToObject(GetValue(Expression))

Only in "DMD Script" i get a expected behavior in relation to ECMA
262-3 12.6.4.
 
G

Garrett Smith

Asen said:
^;
Typo correction ;~)
I added under DOM section:

Host Objects:
* Operators:
- DO not use delete operator with host object (IE Errors)
* Accessing Host objects that are or can be ActiveX objects.
These may include, but are not limited to:
- Disconnected nodes (node.offsetParent)
- XMLHttpRequest methods
- style filters

ES5 requires all Host object to implement HasProperty, along with
[[Get]], [[Delete]], [[DefaultValue]], et al (see Table 8). This is a
big step in the right direction and I'm optimistic of more such things
from the committee.
More suggestions for "Code Guidelines".

Doesn't have information:
- About `11.10 Binary Bitwise Operators` and how they converted
operands `ToInt32`. Which mean, with `Bitwise Operators` can loose
precision. See below:

I don't often see such mistake. The last I remember seeing it was John
Resig's blog around 2007 or so, related to failed ES4.

If you have an example of a piece of code that suffered a bug because of
it, I'd be happy to include it.

It would be worth recommending:-

For numeric conversion, use unary + operator, for parsing numbers from
strings, use parseInt(s, radix);
window.alert(NaN === NaN); //false
window.alert(isNaN(NaN)); //true

- In which cases primitive values will be converted automatically
ToObject and ToObject with which values throw TypeError.

window.alert('str'.concat);

try {
null.foo;
}catch(e) {
window.alert(e instanceof TypeError); //true
}

try {
with(undefined);
}catch(e) {
window.alert(e instanceof TypeError); //true
}

I don't understand. What you are suggesting?
- About for-in loops. That is related with augmentation of built-in
objects prototype chain and with my previous item.

try {
for (var i in null);
}catch(e) {
window.alert(e);
}

I'm cannot found browser ECMA-262 implementation which follow the
specification in `12.6.4 The for-in Statement` step 3 in `for
( LeftHandSideExpression in Expression ) Statement` and step 4 in `for
( var VariableDeclarationNoIn in Expression )`
| Call ToObject(GetValue(Expression))

Only in "DMD Script" i get a expected behavior in relation to ECMA
262-3 12.6.4.

No TypeError, huh? You might want to mention that observation on
es-discuss mailing list. If the major script engines are not complying
with the spec, either the spec should change or the implementations
should.
 
D

Dmitry A. Soshnikov

[snip]
  I'm cannot found browser ECMA-262 implementation which follow the
specification in `12.6.4 The for-in Statement` step 3 in `for
( LeftHandSideExpression in Expression ) Statement` and step 4 in `for
( var VariableDeclarationNoIn in Expression )`
  | Call ToObject(GetValue(Expression))

  Only in "DMD Script" i get a expected behavior in relation to ECMA
262-3 12.6.4.

Yep, implementations know about that. For example, Spidermonkey
justifies that like "web JS" ;)

/*
* Enumerating over null and undefined gives an empty enumerator.
* This is contrary to ECMA-262 9.9 ToObject, invoked from step 3 of
* the first production in 12.6.4 and step 4 of the second production,
* but it's "web JS" compatible.
*/

http://code.google.com/p/v8/source/browse/trunk/src/arm/codegen-arm.cc#1747

V8, e.g. like this (referencing on Spidermonkey and WebKit):

// Both SpiderMonkey and kjs ignore null and undefined in contrast
// to the specification. 12.6.4 mandates a call to ToObject.

http://code.google.com/p/v8/source/browse/trunk/src/arm/codegen-arm.cc#1747

/ds
 
A

Asen Bozhilov

Garrett said:
If you have an example of a piece of code that suffered a bug because of
it, I'd be happy to include it.

No. I'm not have any example from production code or popular library.
You're correct about that. Is not very often *error*.
I don't understand. What you are suggesting?

The main goal of my previous post is related to "Implicit type
conversion" and "Automatically type conversion". Perhaps for that will
be good to have separate article, if doesn't have yet.

Regards.
 
D

Dmitry A. Soshnikov

[snip]
    - DO not use delete operator with host object (IE Errors)

Again, too categorical. If you know what you are doing, it can be
useful to use `delete'. Better to write "Be carefull using delete
operator with host objects because... (IE Errors)".

/ds
 
G

Garrett Smith

Asen said:
No. I'm not have any example from production code or popular library.
You're correct about that. Is not very often *error*.


The main goal of my previous post is related to "Implicit type
conversion" and "Automatically type conversion". Perhaps for that will
be good to have separate article, if doesn't have yet.

There is an faq note about type conversion by Cornford.

http://www.jibbering.com/faq/faq_notes/type_convert.html

I have worked on cleaning that document up to have HTML 4.01 strict at:-

/faq/notes/type-conversion/
 
G

Garrett Smith

Dmitry said:
[snip]
- DO not use delete operator with host object (IE Errors)

Again, too categorical. If you know what you are doing, it can be
useful to use `delete'. Better to write "Be carefull using delete
operator with host objects because... (IE Errors)".

I suppose the same is true for `in` operator, to a lesser extent. That
can fail in a few cases.

"ownerDocument" in document; // false in BB9k its there.
"9999" in document.styleSheets; // true in IE.

Which Host object in IE does delete work on? I know it fails with
window, but have not tried with other objects.
 
G

Garrett Smith

Dmitry said:
Dmitry said:
[snip]
A public library that modifies
the built-ins can't really be trusted to work with other code.
I understand, and told myself, that's this is the only (again - the
only.) reason. And from this point of view, you should mention this
just as a warning for authors of libraries, but not as a rule for
programming on ECMAScript.
[...]

What I have as draft includes most of what I wrote in the last message.
The advice to create a top-level function advise creating a method as a
member of the global object, having the same problems.

Instead, a separate interface should be created. The interface should be
clearly defined, cohesive, and unlikely to conflict with other objects
that use the system.

Formally, there's no full protected "interface" from this point of
view. Will you name it `MyVeryOwnNamespace', and tomorrow, the same
name will be in all `libraries' and in ES itself. So, naming
collisions should not be treated as the main reason.
You can do that, but it doesn't fit what I think of as OOP. It is an
abstraction using inheritance, but it lacks encapsulation and modularity.

What exactly do you mean? Please explain.

Modifying the public interface of String changes Strings to be something
different. Any code that uses String now has that change.

Creating a separate file for string utils does not impose a global
change dependency.

Putting the captilize function in a separate separates the concern so
that only as many modules as necessary depend on that module.

This minimizes dependencies, which makes code change possible. The less
dependency you have, the easier it is to change.

There is no room for confusion in the intended interface with other
modules.

Modifying built-ins prototypes maximizes the dependency. Everything has
String.prototype, right? Well, now if you modify that, then everything
has that modification.

Instead, the code should be doing the opposite; instead of maximizing
scope, it should be minimizing scope. That way, when somebody wants to
change it, he can. And (bonus) if he did a good job at minimizing
dependency, it's easy (and he doesen't have to retest the entire system).
Yeah, it could easily be `3.45.round()' instead of `Math' I agree.


But there's no difference, will somebody put `capitalize' into the
`String.prototype' or will define own `Ext' or `Ext.string' namespace
- tomorrow, it can easily appear in all other libraries and in ES
itself. So, don't use name collision as a reason.

Moreover, I tell, people which use libraries think vice versa - they
think: "we don't not modify String.prototype as we're using 3rd-party
frameword, which can put tomorrow (in the next version) `capitalize'
method into it. So let's make our own namespace such as
OutSuperDuperNamespace.string and put `capitalize' there." And
tomorrow, OMG, that framework provides the same
`OutSuperDuperNamespace' and even `OutSuperDuperNamespace.string'
breaking down all the project. So, that's not the reason.

First off, who creates a namespace like "OutSuperDuperNamespace". Then,
of those people, who then goes on to include *another* library that also
the same (fruity) namespace?

A sensible developer would organize the coe into modules. Obviously
"DOM" (in any case) would be likely to conflict on global level. I use,
for example, APE.dom.

And that way, there is no need to worr about a getPosition or getCoords,
or getStyle function. I have the DOM module, which is all about the dom,
then within that there are modules for style, position, events, and each
aspect is organized so that it is pretty narrow, small and easy to test.

That is modularity.
The capitalize method would not localize consistently, as noted recently
on ES-Discuss[1]. If the string is translated and included literally,
this doesn't occur.

I understand, but that's completely another question, and doesn't
touch the discussing topic.
In ES5, a property can be defined has having [[Writable]] = false.

This can happen in Object.create, with Object.defineProperty, setting
writable: false.

Object.freeze seals an object and makes its properties unmodifiable by
setting [[Writable]] to false.

Creating a sealed object eliminates the possibility for conflicts with
another Ext.string.capitalize.

Yep, thanks, I've also read ES-5 spec already. So, you're moving to
the way I told - better to suggest to use some static language in such
case, but not the language with dynamic mutable objects and statement
as a rule: "Do not touch your own objects".

"Do not touch your own objects" sounds like the exact opposite of what I
meant.
So, if you'll write something like: "Remember that augmenting built-
ins may cause naming conflicts, bla-bla... but the same can be with
any other name in the program - no matter where it's - in global or in
own namespace" - that's will be normal. It will sound like suggesting
from your own opinion.

It's more than conflicts. Conflicts cause errors, but rigid APIs with a
lot of interdependency make change hard.
But if you'll write - "Augmenting built-ins - is a bad practice" -
that will be categorical and wrong, and I can statement, that person
which spread that not completely understand the goal of dynamic
languages (I do not mean exactly you, I'm telling abstractly now).

I'm not completely sure what that means.
 
D

Dmitry A. Soshnikov

Dmitry said:
Dmitry A. Soshnikov wrote:
[snip]
A public library that modifies
the built-ins can't really be trusted to work with other code.
I understand, and told myself, that's this is the only (again - the
only.) reason. And from this point of view, you should mention this
just as a warning for authors of libraries, but not as a rule for
programming on ECMAScript.
[...]
What I have as draft includes most of what I wrote in the last message..
The advice to create a top-level function advise creating a method as a
member of the global object, having the same problems.
Instead, a separate interface should be created. The interface should be
clearly defined, cohesive, and unlikely to conflict with other objects
that use the system.
Formally, there's no full protected "interface" from this point of
view. Will you name it `MyVeryOwnNamespace', and tomorrow, the same
name will be in all `libraries' and in ES itself. So, naming
collisions should not be treated as the main reason.
What exactly do you mean? Please explain.

Modifying the public interface of String changes Strings to be something
different. Any code that uses String now has that change.

Nope, it hasn't. Sorry, bug that's just a demagogy. The code will have
that changes when it will *use* that changes. And please, show me, how
many changes you'll need to do for modifying method name from e.g.
`capitalize' to `capitalizeMethod', if that method uses in e.g. 10
files and doesn't matter where it is described - in
`String.prototype.capitalize' or in
`VeryOwnStringNamespace.capitalize' How many? Please count and tell
me. So, please, do not use demagogy as the logical arguments.
Creating a separate file for string utils does not impose a global
change dependency.

Does. Absolutely the same. Take the example above - please count the
changes you need - in *real* dependency - when some code *uses* that
name: 'string'.capitalize() or VeryOwnStringNamespace.capitalize
('string').
Putting the captilize function in a separate separates the concern so
that only as many modules as necessary depend on that module.

Nope, how can't you see - that the dependency is equal in case you're
describing.
This minimizes dependencies, which makes code change possible. The less
dependency you have, the easier it is to change.

It doesn't minimizes as dependency is equal. But, yep it's true that
"The less dependency you have, the easier it is to change" - but it
doesn't related to the case.
Modifying built-ins prototypes maximizes the dependency.

I've already described my meaning why augmenting of built-ins could be
the issue - only if:

(a) augmenting Object.ptototype till we haven't control of {DontEnum}/
[[Enumerable]]. This point goes without saying. But when we'll have
control of [[Enumerable]], I thinks it could be very useful.

(b) Using 3rd-party libs. But from this point of view - there's no
difference, where to describe your objects.

(c) If some, using some augmented built-ins, will have a habit to use
'string'.capitalize(), he can be confused not founding this method in
other project. But again - there's no difference which habit he has:
'string'.capitalize() or VeryOwnStringNamespace.capitalize() - there
will be no such method in other project. Or, maybe just psychological
difference - in case of 'string'.capitalize() user can think that it's
really own method - but, that's problem of the user - he first should
learn language on which he writes.

So - the dependency is equal.
Everything has
String.prototype, right?

Absolutely right.
Well, now if you modify that, then everything
has that modification.

Of cause not. "Everything" will have that modification when that
"everything" will *use* that modification. And there's no difference
between 'string'.capitalize() vs. VeryOwnStringNamespace.capitalize()
- dependency is equal.
First off, who creates a namespace like "OutSuperDuperNamespace". Then,
of those people, who then goes on to include *another* library that also
the same (fruity) namespace?

The main idea (and understand that) is to show that you don't exactly
know what will some library provide "tomorrow". So your own "APE.dom"
may be overridden by all of that libs you'll use.
A sensible developer would organize the coe into modules.

I know what modules are, be sure. `String.prototype' - is the kind of
a module itself. And if you are sure what you are doing, it's
absolutely not a bad practice to put `capitalize' into it.
Obviously
"DOM" (in any case) would be likely to conflict on global level. I use,
for example, APE.dom.

That's good, but you understand that if you'll using dozen of 3rd-
party libs combined, your "APE.dom" theoretically can just gone in one
moment - when all the libs will provide the same names and structure.
Do you see the difference in this case from augmenting built-ins for
own goals (when you know and understand what are you doing)?
And that way, there is no need to worr about a getPosition or getCoords,
or getStyle function. I have the DOM module, which is all about the dom,
then within that there are modules for style, position, events, and each
aspect is organized so that it is pretty narrow, small and easy to test.

That is modularity.

I know what modularity is. Why do you mention this? Do I say something
against modules? Or do I suggest do not use modules? But keep in mind,
that `String.prototype' - is the kind of a module itself.

I'm not completely sure what that means.

That just means - that ideologically it's normal to augment built-ins
if language is constructed so and if this fact is in it's ideology.

So, I don't propagate everyone to augment built-ins (I think you think
so about my position, so I'm telling you - nope). My position is to be
fair for augmenting built-ins (which means, it against the categorical
statement "Augmenting built-ins - is a bad practice"). To augment or
not in this case - everyone choose - understanding all the issues.

/ds
 
J

John G Harris

In comp.lang.javascript message <[email protected]
8924D9443D28E23ED5CD>, Tue, 22 Dec 2009 11:04:07, John G Harris


Some like larger indents. And a good viewing system can be set to make
a tab equivalent to two or three spaces. On the Web, however, tabs will
normally be worth up to 8 spaces, and should not be used as the indent
unit since most readers will find that too big.

AFAICS, however, tabs are fine for comment and in code strings and in
simple tables.

Anyone who has set up their tab stops to view tables are not going to be
happy setting up 30 or so tabs to view a bit of javascript. Tabs are
convenient for writers but a nuisance for readers.

Two spaces are necessary and sufficient for the indent interval.

We are assuming, of course, that sensible people use a fixed-pitch font.
Anyone who uses a variable-pitch font deserves to be confused.

The primary objection is not to tabs as such, but to an over-wide indent
unit however produced.
<snip>

Very true.

John
 
D

Dr J R Stockton

In comp.lang.javascript message <[email protected]
september.org>, Tue, 29 Dec 2009 10:48:01, Garrett Smith
I added under DOM section:

Host Objects:
* Operators:
- DO not use delete operator with host object (IE Errors)
* Accessing Host objects that are or can be ActiveX objects.
These may include, but are not limited to:
- Disconnected nodes (node.offsetParent)
- XMLHttpRequest methods
- style filters

ES5 requires all Host object to implement HasProperty, along with
[[Get]], [[Delete]], [[DefaultValue]], et al (see Table 8). This is a
big step in the right direction and I'm optimistic of more such things
from the committee.

The type of person for which you ought to be writing will not understand
your jargon (host objects), and may be disconcerted by your lack of
grammar checking.

Linguistic errors can be excused, even expected, from those with Russian
names; but must not be propagated. Spelling : "loose" -> "lose". And
"lose precision" means to get the answer approximately correct, with a
moderate number of LEAST significant bits wrong. Truncation to Int32
does not do that : rather than trim the toes, it decapitates.


For numeric conversion, use unary + operator, for parsing numbers from
strings, use parseInt(s, radix);

Whatever you mean, that does not express it comprehensibly.

Note that parseInt is not a universal nostrum; consider reading the
numeric part of a line known to be of the form "Mushrooms at $6.35/lb".
One uses a RegExp to separate the numeric part; unary + will convert the
matched part, but parseInt loses 35c.
 
A

Asen Bozhilov

Garrett said:
Host Objects:
  * Operators:
    - DO not use delete operator with host object (IE Errors)

That error can you see isn't only in IE. Try it code above in Firefox
3.5:

delete window.location; //Security error" code: "1000
 
T

Thomas 'PointedEars' Lahn

kangax said:
Thomas said:
Wrong. It is Valid in HTML 4.01 Transitional only. As for the "HTML 5"
^^^^^^^^^^^^^^^^^
Are you sure about that?

<http://www.w3.org/TR/REC-html40/sgml/dtd.html>

[...]

Thanks, I stand corrected: As yet another deviation, the end tag of the TD
element (which is _not_ to be termed "the closing TD tag"!) may be omitted
in HTML 4.01 Strict, too (as specified by the `O' and the non-empty content-
model in the element declaration).


PointedEars
 
G

Garrett Smith

Dmitry said:
Dmitry said:
Dmitry A. Soshnikov wrote:
[snip]
A public library that modifies
the built-ins can't really be trusted to work with other code.
I understand, and told myself, that's this is the only (again - the
only.) reason. And from this point of view, you should mention this
just as a warning for authors of libraries, but not as a rule for
programming on ECMAScript.
[...]
What I have as draft includes most of what I wrote in the last message.
The advice to create a top-level function advise creating a method as a
member of the global object, having the same problems.
Instead, a separate interface should be created. The interface should be
clearly defined, cohesive, and unlikely to conflict with other objects
that use the system.
Formally, there's no full protected "interface" from this point of
view. Will you name it `MyVeryOwnNamespace', and tomorrow, the same
name will be in all `libraries' and in ES itself. So, naming
collisions should not be treated as the main reason.
So, again, it's absolutely normal to augmenting objects in ES,
providing good documentation of what have you augmented (and for whole
code in general).
If you still wanna to write this as a rule, please mentioned, that
it's not the rule, but *just your own suggestion and own meaning*,
meanwhile other people can choose different (good) way augmenting
object and write in OOP-style such as `string.capitalize()' instead of
long ugly `Ext.util.Format.capitalize(string)'. Especially in own
project.
You can do that, but it doesn't fit what I think of as OOP. It is an
abstraction using inheritance, but it lacks encapsulation and modularity.
What exactly do you mean? Please explain.
Modifying the public interface of String changes Strings to be something
different. Any code that uses String now has that change.

Nope, it hasn't. Sorry, bug that's just a demagogy. The code will have
that changes when it will *use* that changes. And please, show me, how
many changes you'll need to do for modifying method name from e.g.
`capitalize' to `capitalizeMethod', if that method uses in e.g. 10
files and doesn't matter where it is described - in
`String.prototype.capitalize' or in
`VeryOwnStringNamespace.capitalize' How many? Please count and tell
me. So, please, do not use demagogy as the logical arguments.

Given a piece of code M that has:-

String.prototype.capitalize = 1;

Another piece of code O that uses M now has capitalize method available.

<script src="m.js"></script>
<script src="o.js"></script>

So m.js creates a dependency from everything, to modification to
String.prototype.

If m.js were to define something else:-

M.capitalize= 1;

- then the exact same problem occurs. I think this is what you were
getting at.
Does. Absolutely the same. Take the example above - please count the
changes you need - in *real* dependency - when some code *uses* that
name: 'string'.capitalize() or VeryOwnStringNamespace.capitalize
('string').

A separate *file* would be depended on where it is included.

<script src="p.js"></script>
<script src="o.js"></script>

If p.js does not contain m.js (this could happen in a build), there
would be no dependency on M.capitalize.

If m.js is an author file (not using a build tool), is not about
built-in String/String.prototype, and is about formatting strings, then
m is defining two things:-
1) user defined string formatting
2) built in String

The user-defined String formatting routines could becomes properties of
one object, maybe stringFormat. That is clearly about one thing.
Nope, how can't you see - that the dependency is equal in case you're
describing.

A module that adds a property to something it doesn't own introduces
something globally accessible that unrelated to the module itself. It is
doing more than it should. It is not really modular.
It doesn't minimizes as dependency is equal. But, yep it's true that
"The less dependency you have, the easier it is to change" - but it
doesn't related to the case.
A way to reduce change dependency would be to do less in each module.
Modifying built-ins prototypes maximizes the dependency.

I've already described my meaning why augmenting of built-ins could be
the issue - only if:

(a) augmenting Object.ptototype till we haven't control of {DontEnum}/
[[Enumerable]]. This point goes without saying. But when we'll have
control of [[Enumerable]], I thinks it could be very useful.

(b) Using 3rd-party libs. But from this point of view - there's no
difference, where to describe your objects.

On this point, there is a huge difference where the object is defined.
If the client of the API defines String.prototype.capitalize, and the
library defines the same, there will be a conflict.

The library new version could define `YourCompanyNameSpace`, but why
would it?
(c) If some, using some augmented built-ins, will have a habit to use
'string'.capitalize(), he can be confused not founding this method in
other project. But again - there's no difference which habit he has:
'string'.capitalize() or VeryOwnStringNamespace.capitalize() - there
will be no such method in other project. Or, maybe just psychological
difference - in case of 'string'.capitalize() user can think that it's
really own method - but, that's problem of the user - he first should
learn language on which he writes.

On point (c), I see an issue with shared codebase; not necessarily
another project, per se, but elsewhere in the same application that is
using your module.
So - the dependency is equal.

With either VeryOwnStringNamespace.capitalize, or
String.prototype.capitalize, yes, they both introduce globally
accessible method where they are included.

I want to look at Ext.util.Format.capitalize, then consider an
alterantive String.prototype.capitalize and compare alternatives. First
look at the Ext version.

First off, the package `Ext.util.Format` is not specific. Is `Format` a
verb or a noun? `Format` as a noun would seem to be a constructor, so
it shouldn't be that. If Format is a verb, then is it a method? What
does `Format` format? Does it format HTML code? Dates? Numbers?
Templates? As lengthy as that namespace is, it does not describe string
formatting. Indeed, format seems in the verb sense here, but it is not a
method; it is an object. The object has methods that perform many types
of formatting. None of the methods have much to do with each other;
they're categorized to work with strings and return strings. Instead, I
would prefer to shorten that to have just:-

Ext.formatString
Ext.formatHTML
Ext.formatDate

I've reformatted `Ext.util.Format.capitalize` function to wrap:

capitalize : function(value){
return !value ? value : value.charAt(0).toUpperCase() +
value.substr(1).toLowerCase();
}

There are a few problems with that function. When passed a falsish
value, the value itself is returned.

The non-standard substr method should be replaced with a call to the
standard String.prototype.substring.

The method does not consider strings that begin with non-characters,
such as leading whitespace or tic marks. For example, If input is "
higiri" and it is desired to have the method return the first
non-whitespace to upper-case, so " Higiri".

Here's a prototype'd version of Ext-js's "Ext.util.Format.capitalize":

if(!String.prototype.capitalize) { // Should we add a safety check?
return this.charAt(0).toUpperCase() + this.substr(1).toLowerCase();
}

Should there be a safety check? What if the safety check fails?

What about a piece of code that has access to the change to
String.prototype.capitalize, and wants to change it? Is that okay to
redefine String.prototype.capitalize? Is capitalization in a certain way
something that all strings should have, and should the method name be
`capitalize`?

Or what about:

String.prototype.startsWith?

What should that do?

If startsWith does something that is purely related to a *String*, and
not how *your application* is *using* strings, then it may be a good
candidate for a Standard in ES Harmony. For example,
String.prototype.trim that was added in ES5. Perhaps
String.prototype.startsWith could be a candidate for ES6.

If something is a good candidate for a Standard, then it is best to not
create a potential conflict. If ES6 defines String.prototype.startsWith,
but slightly differently, then the code that is defining
String.prototype.trim would want to avoid the safety check. It would
have to hide the built-in startsWith method and would want to avoid any
safety checks like:-

// No good if it is defined (in ES6, etc)
if(!String.prototype.startsWith) {

}

An alternative is the code could instead redefine
String.prototype.startsWith to String.prototype.myVeryOwnStartsWith.

But then we are getting to the point where the method name is trying
hard to have an identifier that identifies it as being something added
not built in.
Absolutely right.


Of cause not. "Everything" will have that modification when that
"everything" will *use* that modification. And there's no difference
between 'string'.capitalize() vs. VeryOwnStringNamespace.capitalize()
- dependency is equal.

By "use", I believe you mean to describe code that is accessing the
`capitalize` method, and not code that exists where the script that
defines `capitalize` exists.

Either way, I don't think it matters much. Once the API is published,
you don't get to decide who calls what. You can say: "I defined this
property, but don't use it," and if there is no value in using it, then
probably nobody will use it. If there is some value in using that
feature, then it has a better chance of being used. How would you know
who is using `capitalize`?

Either way, the method is globally accessible.
The main idea (and understand that) is to show that you don't exactly
know what will some library provide "tomorrow". So your own "APE.dom"
may be overridden by all of that libs you'll use.

I think we are arguing the same point.

That is, you don't know what may be defined tomorrow.

That public interface, is a property of global object, and so it could
be replaced by a simple assignment.

Anyone using that namespace could be expected to not redeclare that
namespace and to not use another piece of code that does.

YUI's YAHOO.namespace method fails on this account.

YAHOO.namespace fails because it adds user-defined properties to the
YAHOO object. Calling YAHOO.namespace("example") creates YAHOO.example,
if it does not exist alreay. YUI's namespace strategy makes it easy for
conflits to occur. Consider a client using YUI that wants to define
YAHOO.touchevent namespace. Will a future release of YUI have its own
YAHOO.touchevent object? YAHOO has no way to be certain that a client of
YAHOO had not followed YUI's advice and used
YAHOO.namespace("touchevent"). If YUI decides to use YAHOO.touchevent =
{}, then the namespace will be obliterated.
I know what modules are, be sure. `String.prototype' - is the kind of
a module itself. And if you are sure what you are doing, it's
absolutely not a bad practice to put `capitalize' into it.

String.prototype is a built-in. If it is to be called a "module", then
it is a built-in module. If you've modified it, then it is a built-in
module with a mix of user-defined properties.

If user-defined properties are defined, then where should these
definitions occur?

If the definition of user-defined additions to String.prototype is
defined in a author file that is defining another module, then the
author is defining two things in that file instead of one. So those
modifications should not occur in same author file as another module's code.

By "author file" I mean the file the author edits, not necessarily the
same file the http client receives.

The author file should be defining one thing only.
That's good, but you understand that if you'll using dozen of 3rd-
party libs combined, your "APE.dom" theoretically can just gone in one
moment - when all the libs will provide the same names and structure.
Do you see the difference in this case from augmenting built-ins for
own goals (when you know and understand what are you doing)?

The only user-defined identifier that is ReadOnly is the Identfier for
FunctionExpression. And that doesn't work in JScript, as you probably know.

By that fact, you are are right; any one library can replace APE.dom.

A conflict can occur when *one* external module or library also modifies
the property String.prototype.capitalize.

The point is to not do that; to not modify objects you don't own.

Instead, I am suggesting that methods exist as part of units or modules
and with an easily identifiable role.

This can be achieved by defining one global namespace and hanging
properties off that.

If it is OK to modify String.prototype, is it okay for everyone to do
that, or just an internal organization?

Is it ok to modify objects you don't own in general? If so, are there
exceptions to that rule?

[...]
That just means - that ideologically it's normal to augment built-ins
if language is constructed so and if this fact is in it's ideology.

The language allowing something does not make that thing ideal. The
language makes assignment to identifier end up with globals. How many
times have you seen a missing - var - statement.

for(i - 0; i < 10; i++)

?

One useful way to modify built-ins is to add the standard feature for
implementations that have not yet implemented it, or have implemented it
wrong, but preceeding that with a feature test, e.g.
if(!String.prototype.trim) ... .

If the rule "don't modify objects you don't own", is followed, and the
only exception to that rule is to add a global property, then conflicts
should not occur.
So, I don't propagate everyone to augment built-ins (I think you think
so about my position, so I'm telling you - nope). My position is to be
fair for augmenting built-ins (which means, it against the categorical
statement "Augmenting built-ins - is a bad practice"). To augment or
not in this case - everyone choose - understanding all the issues.
I got that. I don't see a good reason for modifying objects you don't
own. I see a few downsides:-
1) increases potential conflict with
* new standard
* new version of 3rd party library
* code defined somewhere else in the organization

2) Method presence doesn't provide indication where that method is
likely to be defined.
 
D

Dr J R Stockton

In comp.lang.javascript message <[email protected]
8924D9443D28E23ED5CD>, Wed, 30 Dec 2009 16:22:09, John G Harris
Anyone who has set up their tab stops to view tables are not going to be
happy setting up 30 or so tabs to view a bit of javascript. Tabs are
convenient for writers but a nuisance for readers.

Two spaces are necessary and sufficient for the indent interval.

We are assuming, of course, that sensible people use a fixed-pitch font.
Anyone who uses a variable-pitch font deserves to be confused.

I think that you need to read what I wrote more slowly.

The proportion of people whose Web browsers and/or newsreaders are
routinely set up to have tab stops at other than 8N+1 must be
negligible.

Remember :
the most important reader must be the writer,
the code as written is not necessarily the code as transmitted.
 
G

Garrett Smith

Asen said:
That error can you see isn't only in IE. Try it code above in Firefox
3.5:

delete window.location; //Security error" code: "1000

OK, but Firefox, or Gecko implement that as a native JSObject with
Object.prototype on the prototype chain. It is a little different in IE,
where the object is not a JScript object.

location.valueOf(); // Error in IE.

location instanceof Object; // False in IE
 
D

Dmitry A. Soshnikov

Dmitry said:
Dmitry A. Soshnikov wrote:
Dmitry A. Soshnikov wrote:
[snip]
A public library that modifies
the built-ins can't really be trusted to work with other code.
I understand, and told myself, that's this is the only (again - the
only.) reason. And from this point of view, you should mention this
just as a warning for authors of libraries, but not as a rule for
programming on ECMAScript.
[...]
What I have as draft includes most of what I wrote in the last message.
The advice to create a top-level function advise creating a method as a
member of the global object, having the same problems.
Instead, a separate interface should be created. The interface should be
clearly defined, cohesive, and unlikely to conflict with other objects
that use the system.
Formally, there's no full protected "interface" from this point of
view. Will you name it `MyVeryOwnNamespace', and tomorrow, the same
name will be in all `libraries' and in ES itself. So, naming
collisions should not be treated as the main reason.
So, again, it's absolutely normal to augmenting objects in ES,
providing good documentation of what have you augmented (and for whole
code in general).
If you still wanna to write this as a rule, please mentioned, that
it's not the rule, but *just your own suggestion and own meaning*,
meanwhile other people can choose different (good) way augmenting
object and write in OOP-style such as `string.capitalize()' instead of
long ugly `Ext.util.Format.capitalize(string)'. Especially in own
project.
You can do that, but it doesn't fit what I think of as OOP. It is an
abstraction using inheritance, but it lacks encapsulation and modularity.
What exactly do you mean? Please explain.
Modifying the public interface of String changes Strings to be something
different. Any code that uses String now has that change.
Nope, it hasn't. Sorry, bug that's just a demagogy. The code will have
that changes when it will *use* that changes. And please, show me, how
many changes you'll need to do for modifying method name from e.g.
`capitalize' to `capitalizeMethod', if that method uses in e.g. 10
files and doesn't matter where it is described - in
`String.prototype.capitalize' or in
`VeryOwnStringNamespace.capitalize' How many? Please count and tell
me. So, please, do not use demagogy as the logical arguments.

Given a piece of code M that has:-

String.prototype.capitalize = 1;

Another piece of code O that uses M now has capitalize method available.

<script src="m.js"></script>
<script src="o.js"></script>

So m.js creates a dependency from everything, to modification to
String.prototype.

If m.js were to define something else:-

M.capitalize= 1;

- then the exact same problem occurs. I think this is what you were
getting at.

Yep.
Does. Absolutely the same. Take the example above - please count the
changes you need - in *real* dependency - when some code *uses* that
name: 'string'.capitalize() or VeryOwnStringNamespace.capitalize
('string').

A separate *file* would be depended on where it is included.

<script src="p.js"></script>
<script src="o.js"></script>

If p.js does not contain m.js (this could happen in a build), there
would be no dependency on M.capitalize.

If m.js is an author file (not using a build tool), is not about
built-in String/String.prototype, and is about formatting strings, then
m is defining two things:-
1) user defined string formatting
2) built in String

The user-defined String formatting routines could becomes properties of
one object, maybe stringFormat. That is clearly about one thing.

Unclear. You correctly mentioned that "the exact same problem occurs"
with `String.prototype.capitalize' and `M.capitalize' in previous
part. Now you're talking about some "build tool" which builds
dependencies. What again difference do you see in that will "m.js"
contain `String.prototype.capitalize' or `M.capitalize', please
explain?

Let me again to mention the real dependency (regardless some "build
tools") - the dependency *is*, when some code uses that `.capitalize'
method, regardless how was it described.

If to take in mind you "build tool", I think augmenting of some built-
in object you'd like to put in some "global/general/built-in/common
-.js" which includes to *every* file. Meanwhile, "m.js" with own
namespace `M' and method `M.capitalize' will be included only in
needed files, right? Do I understand you correctly? Is this you want
to tell me? If so, let me again to mention about real dependency -
when code will *use* concrete and exact `.capitalize' method,
regardless *including* by some "build tool". Moreover, nothing
prevents to place `String.prototype.capitalize' also "m.js".
A module that adds a property to something it doesn't own introduces
something globally accessible that unrelated to the module itself. It is
doing more than it should. It is not really modular.

First, not exactly "globally". Second, it's not the module who puts
"something" into the "something". That *you* augment the built-in
module with new functionality to make more readable and useful code (I
remind, `String.prototype' is a module itself - so you put new
functionality into it. But not "some module is doing more than it
should").
I've already described my meaning why augmenting of built-ins could be
the issue - only if:
(a) augmenting Object.ptototype till we haven't control of {DontEnum}/
[[Enumerable]]. This point goes without saying. But when we'll have
control of [[Enumerable]], I thinks it could be very useful.
(b) Using 3rd-party libs. But from this point of view - there's no
difference, where to describe your objects.

On this point, there is a huge difference where the object is defined.
If the client of the API defines String.prototype.capitalize, and the
library defines the same, there will be a conflict.

The library new version could define `YourCompanyNameSpace`, but why
would it?

Not a huge - on practice, and equal on theory (why not for
`YourCompanyNameSpace`?). And again, that exactly users of a library
who will afraid and will not touch the `String.prototype' because they
think that they depend on library (and new version of library may do
everything). In other case users are independent from any library and
can augment everything they want, right? And that's not a bad practice
at all.
On point (c), I see an issue with shared codebase; not necessarily
another project, per se, but elsewhere in the same application that is
using your module.

Yep, and it can be with any other own code shared anywhere, when some
will have a habit to use it. I mentioned that exactly to show that
there's no difference.
With either VeryOwnStringNamespace.capitalize, or
String.prototype.capitalize, yes, they both introduce globally
accessible method where they are included.

Yep.

I want to look at Ext.util.Format.capitalize, then consider an
alterantive String.prototype.capitalize and compare alternatives. First
look at the Ext version.

First off, the package `Ext.util.Format` is not specific. Is `Format` a
verb or a noun? `Format` as a noun would seem to be a constructor, so
it shouldn't be that. If Format is a verb, then is it a method? What
does `Format` format? Does it format HTML code? Dates? Numbers?
Templates? As lengthy as that namespace is, it does not describe string
formatting. Indeed, format seems in the verb sense here, but it is not a
method; it is an object. The object has methods that perform many types
of formatting. None of the methods have much to do with each other;
they're categorized to work with strings and return strings. Instead, I
would prefer to shorten that to have just:-

Ext.formatString
Ext.formatHTML
Ext.formatDate

I've reformatted `Ext.util.Format.capitalize` function to wrap:

capitalize : function(value){
return !value ? value : value.charAt(0).toUpperCase() +
value.substr(1).toLowerCase();
}

There are a few problems with that function. When passed a falsish
value, the value itself is returned.

The non-standard substr method should be replaced with a call to the
standard String.prototype.substring.

The method does not consider strings that begin with non-characters,
such as leading whitespace or tic marks. For example, If input is "
higiri" and it is desired to have the method return the first
non-whitespace to upper-case, so " Higiri".

Here's a prototype'd version of Ext-js's "Ext.util.Format.capitalize":

if(!String.prototype.capitalize) { // Should we add a safety check?
return this.charAt(0).toUpperCase() + this.substr(1).toLowerCase();

}

Should there be a safety check? What if the safety check fails?

What about a piece of code that has access to the change to
String.prototype.capitalize, and wants to change it? Is that okay to
redefine String.prototype.capitalize? Is capitalization in a certain way
something that all strings should have, and should the method name be
`capitalize`?

Or what about:

String.prototype.startsWith?

What should that do?

If startsWith does something that is purely related to a *String*, and
not how *your application* is *using* strings, then it may be a good
candidate for a Standard in ES Harmony. For example,
String.prototype.trim that was added in ES5. Perhaps
String.prototype.startsWith could be a candidate for ES6.

If something is a good candidate for a Standard, then it is best to not
create a potential conflict. If ES6 defines String.prototype.startsWith,
but slightly differently, then the code that is defining
String.prototype.trim would want to avoid the safety check. It would
have to hide the built-in startsWith method and would want to avoid any
safety checks like:-

// No good if it is defined (in ES6, etc)
if(!String.prototype.startsWith) {

}

An alternative is the code could instead redefine
String.prototype.startsWith to String.prototype.myVeryOwnStartsWith.

But then we are getting to the point where the method name is trying
hard to have an identifier that identifies it as being something added
not built in.

Here you're describing something concrete and already regardless topic
(it's not so interesting how `capitalize' is implemented in ExtJS or
in Prototype.js, this method was taken only for an abstract example of
augmenting) - is it a good or bad practice to augment built-ins. So I
let myself to answer shortly - even regardless is a "good" or "bad"
candidate for "some next Standard", it's absolutely not a bad practice
from my point of view - if you understand what are you doing. That
will let to write more clear and useful code.

Ok, I've "appreciated" this demagogy in this part of your answer ;)

So, concluding this ('cause I don't wanna to make a useless dispute -
I see what see, I know what I know), some questions I have to you:

1. Do you understand that your *statement* about augmentations of
built-ins - is just your own (humble) opinion? (Actually, exactly the
same as mine. But in difference from yours, mine doesn't forbid, but
explain why it's good and when it can be the issue).

Also, I'd like to mention, that firstly your statement sounded as
"Don't modify objects you don't own". There you didn't talk about
"built-ins" bug about abstract "not own" objects. Although, in our
talk I found out that you mean also built-ins. For me, touching some
*other* objects that I don't own (but not a built-ins) - is also can
be useless practice (although, I don't use words "bad practice",
'cause even regarding not to built-ins but to some other - it could be
useful to make some patch on some 3rd-party code, although, they can
do it themselves in new version of library).

2. I'd like to hear how exactly your position sounds. I've already
mentioned my position about this question: "I don't force anyone to
augment built-ins, I don't spread this idea, I'm just not agree with
the statement that augmenting of built-ins in dynamic language with
mutable objects - is a bad practice. Again - it's normal practice and
let to write more useful code against that long ugly as in ExtJS for
`.capitalize'".

So whatever you write (for whom this "Code Guidelines"?) - will you
write it or not (that it's a "bad practice") - I don't mind. But if
some using this "Code Guidelines" will (or will try to) judge anyone
by that question (about augmenting of built-ins) - I'll tell again,
that that people don't understand why they are judging so and they
don't think with their own head. Also that will be a bad practice of
using such "Code Guidelines" for *novices*, which will think that
everything written there (in statement manner!) - is conclusive true.
But it's not so.

P.S.: Happy New Year ;) Regards.

/ds
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,228
Members
46,818
Latest member
SapanaCarpetStudio

Latest Threads

Top