toString Method with Parameters

G

Gene Wirchenko

Dear JavaScripters:

Is it legal to define a toString() for an object with the
toString() having one or more parameters?

I am going to be defining a date type that does more than the
usual implementation does. (I use certain functionalities fairly
heavily in my existing app and would like to have them in the Web
version.) One of the things that I need is multiple formats. I could
have:
toString() like Date's toString()
ISO8601DateFormat() date in ISO 8601 format
IMADateFormat() date in IMA (internal) format
or I could have:
toString() (no parm)
toString(1) or toString(ISO8601)
toString(2) or toString(IMADate)

I tried it in IE9, and it gives me the results that I want, but
all that says it that it can work, not that it should. Is it, in
fact, legal to overload toString() like this?

Here is my code:

***** Start of Experimental Code *****
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<meta http-equiv="Content-Type" content="text/html;
charset=iso-8859-1" />
<title>try8.html</title>
</head>

<script type="text/javascript">

function NewDate(Year,Month,Day)
{
this.Year=Year;
this.Month=Month;
this.Day=Day;
NewDate.prototype.toString=NewDateToString;
}

function NewDateToString
(
Selector
)
{
if (NewDateToString.arguments.length==0)
{
var theDate=new Date(this.Year,this.Month,this.Day);
return theDate.toString();
}
if (Selector==1)
return this.Year+"-"+this.Month+"-"+this.Day;
if (Selector==2)
{
var RetVal="";
var Piece="0000"+this.Year;
RetVal+=Piece.substring(Piece.length-4);
Piece="00"+this.Month;
RetVal+=Piece.substring(Piece.length-2);
Piece="00"+this.Day;
RetVal+=Piece.substring(Piece.length-2);
return RetVal;
}
return "Invalid NewDate toString() selector.";
}

</script>

<body>

<script type="text/javascript">

var SomeDay=new NewDate(2011,12,25); // Christmas 2011
alert("Date toString(): "+SomeDay.toString());
alert("ISO 8601 Date: "+SomeDay.toString(1));
alert("IMA Date: "+SomeDay.toString(2));

</script>

</body>

</html>
***** End of Experimental Code *****

Sincerely,

Gene Wirchenko
 
A

Andreas Bergmaier

Gene said:
Dear JavaScripters:

Is it legal to define a toString() for an object with the
toString() having one or more parameters?

I can see no drawbacks. The ECMA Scripts specification says that the
toString method is called "with the object as the this value and an
empty argument list", and I don't know any browser that doesn't follow that.
So overloading a toString() method should be no problem.
Here is my code:

function NewDate(Year,Month,Day)
{
[...]
NewDate.prototype.toString=NewDateToString;
Do this outside of the constructor, your code would assign it each time
a new NewDate is generated.
}

function NewDateToString
(
Selector
)
{
[...]
}
Why do you define the function in the global scope? Also please spell
method names lowercase (camelCase is OK), function names starting with
capitals are considered beeing constructors. Just use

function NewDate(Year,Month,Day) {
[...]
}
NewDate.prototype.toString = function newDateToString(Selector) {
[...]
}

Bergi
 
T

Thomas 'PointedEars' Lahn

Yes. Number.prototype.toString() is such a useful method.
(591861).toString(36) :)
I can see no drawbacks. The ECMA Scripts specification says that the

_ECMAScript (Language) Specification_
toString method is called "with the object as the this value and an
empty argument list", and I don't know any browser that doesn't follow
that.

It is a matter of the *implementation*, not of the browser.

So overloading a toString() method should be no problem.

That applies for *implicit* string conversion only. IOW, all arguments of a
toString() method should be implemented as being optional, and when they are
not present, perform a simple conversion (unless for some reason conversion
to string should be forbidden, in which case you should throw an exception).
[…] Just use

function NewDate(Year,Month,Day) {
[...]
}
NewDate.prototype.toString = function newDateToString(Selector) {
[...]
}

No. A "named function expression" (NFE) is unnecessary here, and NFEs
should be avoided because of JScript (lately, I have rediscovered that
strict mode requires you to use NFEs for recursion as arguments.callee
throws an exception. Sacrificing compatibility here – for what?).

Use this:

NewDate.prototype.toString = function (Selector) {
// …
};


PointedEars
 
T

Thomas 'PointedEars' Lahn

Thomas said:
Use this:

NewDate.prototype.toString = function (Selector) {
// …
};

This is better as it avoids confusion between constructor name and name of
argument:

NewDate.prototype.toString = function (selector) {
// …
};


PointedEars
--
If you get a bunch of authors […] that state the same "best practices"
in any programming language, then you can bet who is wrong or right...
Not with javascript. Nonsense propagates like wildfire in this field.
-- Richard Cornford, comp.lang.javascript, 2011-11-14
 
R

Richard Cornford

Dear JavaScripters:

Is it legal to define a toString() for an object with the
toString() having one or more parameters?

Yes, and Number.prototype.toString - already accepts an argument.
I am going to be defining a date type that does more
than the usual implementation does. (I use certain
functionalities fairly heavily in my existing app and would
like to have them in the Web version.) One of the things that
I need is multiple formats. I could have:
toString() like Date's toString()
ISO8601DateFormat() date in ISO 8601 format
IMADateFormat() date in IMA (internal) format
or I could have:
toString() (no parm)
toString(1) or toString(ISO8601)
toString(2) or toString(IMADate)

Consider what the reader of the code will be able to directly deduce
from what they see. The more elaborate method names become self-
documenting because they make a statement about what they are doing. A
- toString - method with a numeric argument, in order to be
understood, requires knowing what the type of the object on which the
method is going to be called is, and then finding that types source
code or documentation in order to find out which format results from
which number argument. In the real world it is extremely rare for code
to properly commented or documented, which makes leaving as much
information in the source code as possible a generally good idea.
I tried it in IE9, and it gives me the results that I want,
but all that says it that it can work, not that it should. Is
it, in fact, legal to overload toString() like this?
<snip>

It is legal.

Richard.
 
S

Scott Sauyet

Gene said:
     Is it legal to define a toString() for an object with the
toString() having one or more parameters?
[ ... ]
Is it, in fact, legal to overload toString() like this?

Others have correctly replied that it is legal. And its certainly not
uncommon. But one warning about terminology. Don't think of this
like overloading in a statically-typed language. If you try to do
this:

NewDate.prototype.toString = function() {
// return a default string representation
}

NewDate.prototype.toString = function(selector) {
// return a string based on selector
}

the second definition will simply overwrite the first. If you call it
with

myNewDate.toString()

the later-defined function will be called, and the parameter
`selector` will have a value of undefined.

As long as you don't think of this as classical overloading, this
isn't an issue. If you do want your behavior to vary depending upon
the number of parameters and their types, you will have to do it
yourself, for example,

NewDate.prototype.toString = function(selector) {
if (typeof selector == "undefined") {
// return a default string representation
} else {
// return a string based on selector
}
}

On occasion, this manual overloading technique can be very useful,
especially for dealing with certain optional parameters. But
especially for a public interface, I would hesitate before doing so.
There are significant costs, especially for maintenance. If you ever
need to add a parameter to a method and you're already mangling the
parameter order somehow, your complexity can quickly spiral out of
control. Much of the convoluted code in the jQuery library has arisen
solely to maintain this sort of flexible API.

If all you want to do is use a single `toString` function that has a
single parameter, go ahead and set it how you will. If you want to
allow that single parameter to be optional, this can work. But the
minute you start dealing with multiple parameters, you might want to
rethink.

-- Scott
 
D

Dr J R Stockton

In comp.lang.javascript message <4g1de7t607d0sdudjmdv4mr1o4cm5hvekg@4ax.
Is it legal to define a toString() for an object with the
toString() having one or more parameters?

I am going to be defining a date type that does more than the
usual implementation does.


You have much to learn.

(I use certain functionalities fairly
heavily in my existing app and would like to have them in the Web
version.) One of the things that I need is multiple formats. I could
have:
toString() like Date's toString()
ISO8601DateFormat() date in ISO 8601 format

But which one - basic or extended (expanded or not), common or ordinal
or week-numbering? With time? With offset indicator?
IMADateFormat() date in IMA (internal) format

Never heard of it. Describe it, and I'll be able to see whether DOBJ2
currently handles it. ... If I read your code correctly, and if your
code is correct, it's just ISO 8601 common basic format.

If you know that 1000 <= year <=9999,
that can be coded more briefly as String(Y*1e4 + M*1e2 + D);
for also 0000-0999, String(1E8 + Y*1e4 + M*1e2 + D).substring(1).

An 8-digit result converts to extended format with, IIRC,
..replace(/(....)(..)(..)/, "$1-$2-$3")

or I could have:
toString() (no parm)

The output from that is not defined. It would be better not to use it
in final code.
toString(1) or toString(ISO8601)
toString(2) or toString(IMADate)

I tried it in IE9, and it gives me the results that I want, but
all that says it that it can work, not that it should. Is it, in
fact, legal to overload toString() like this?

It is replacement, not overloading; but a reference to the original can
be saved first. In DOBJ2, .toString takes a format string argument,
default IIRC provided.

With selector 1, your code does NOT return ISO 8601 for 9 months of the
year and 9 days of each of the rest. Never claim compliance with an
unfamiliar standard lest you are thought to live south of the nearby
border.


NOTE that, if your code is essentially calendar work, not needing to
read the actual date/time much, it is faster to use the UTC methods; and
then you cannot be troubled with what Those Below quaintly call DST
changes.

I suspect, but have not verified, that you are mixing month numbers
1-12 and 0-11.

It might be wiser to require selector=0 for the Date Object date, and
make no arguments as a fatal error. That might prevent mistakes.
 
G

Gene Wirchenko

In comp.lang.javascript message <4g1de7t607d0sdudjmdv4mr1o4cm5hvekg@4ax.



You have much to learn.
Yup.

Have you considered <http://www.merlyn.demon.co.uk/js-dobj2.htm> ?
Etc.?

Nope. I need practice anyway.
But which one - basic or extended (expanded or not), common or ordinal
or week-numbering? With time? With offset indicator?

I mean YYYY-MM-DD. Today is 2011-12-13.
Never heard of it. Describe it, and I'll be able to see whether DOBJ2
currently handles it. ... If I read your code correctly, and if your
code is correct, it's just ISO 8601 common basic format.

It is a format internal to the company. It is YYMMDD. It is
used in contexts where a two-digit year is not a problem. For
example, when a shipment comes in, it is tagged as in
111213-0001
which would have been the first package in today.
If you know that 1000 <= year <=9999,
that can be coded more briefly as String(Y*1e4 + M*1e2 + D);
for also 0000-0999, String(1E8 + Y*1e4 + M*1e2 + D).substring(1).

I prefer to not use arithmetic so as to avoid rounding issues. I
am not sure when they would come in in JavaScript.
An 8-digit result converts to extended format with, IIRC,
.replace(/(....)(..)(..)/, "$1-$2-$3")

I will have to look at that.
The output from that is not defined. It would be better not to use it
in final code.

How so? I build a date and use Date's toString(). What is
undefined about that? Or do you mean that it is not specifically
defined as to format? The latter, I grant.
It is replacement, not overloading; but a reference to the original can
be saved first. In DOBJ2, .toString takes a format string argument,
default IIRC provided.

With selector 1, your code does NOT return ISO 8601 for 9 months of the
year and 9 days of each of the rest. Never claim compliance with an
unfamiliar standard lest you are thought to live south of the nearby
border.

Got me! A silly mistake considering I insert leading zeroes with
Selector==2. It's that special time of the year... when MM and DD do
not have leading zeroes.
NOTE that, if your code is essentially calendar work, not needing to
read the actual date/time much, it is faster to use the UTC methods; and
then you cannot be troubled with what Those Below quaintly call DST
changes.

I want a date type, not a datetime type like Date is. I want to
be able to compare dates without worrying about the time of day being
different.
I suspect, but have not verified, that you are mixing month numbers
1-12 and 0-11.

Caught me again. Yes, I intend to use 1-12 for my type. I think
that Date's 0-11 is just asking for it. Off-by-one errors are about
the most common, and here JavaScript is making it even easier to screw
up.
It might be wiser to require selector=0 for the Date Object date, and
make no arguments as a fatal error. That might prevent mistakes.

I thought that I might get into trouble with JavaScript expecting
such a call to be valid. I might just make it equivalent to one of
the Selector values and never use it.

Thank you for your time.

Sincerely,

Gene Wirchenko
 
D

Dr J R Stockton

In comp.lang.javascript message <[email protected]>,
Tue, 13 Dec 2011 02:41:52, Thomas 'PointedEars' Lahn
Yes. Number.prototype.toString() is such a useful method.
(591861).toString(36) :)

BEWARE - in at least one current browser, for non-integer Numbers and
the less popular bases, one can get strings of about 1000 characters
from .toString.

One browser recently frequently gave the last digit a Unicode value one
higher than that for the character representing (base-1), for example
binary fractions with a final digit 2.
 
D

Dr J R Stockton

In comp.lang.javascript message <o1vfe7l0gbc4nu2ievgf2849qk5hc66228@4ax.
On Tue, 13 Dec 2011 20:42:33 +0000, Dr J R Stockton


Nope. I need practice anyway.

But we don't need practice in sorting out your date problems.


I mean YYYY-MM-DD. Today is 2011-12-13.

Best described as YYYY-MM-DD, perhaps with "(ISO 8601)".
It is a format internal to the company. It is YYMMDD. It is
used in contexts where a two-digit year is not a problem. For
example, when a shipment comes in, it is tagged as in
111213-0001
which would have been the first package in today.

That YY date is not ISO 8601, of course. The originators of that format
will be cursed in under 90 years time.

I prefer to not use arithmetic so as to avoid rounding issues. I
am not sure when they would come in in JavaScript.

In JavaScript, integer arithmetic is exact so long as all intermediate
and final results are integers not exceeding 2^53 (just over 9e15) in
magnitude. And, approximately, non-integer arithmetic is expected to be
exact between 1e-303 and 1e+308, provided that, expressed as fixed-
point, no values need "one" bits more than about 53 apart. All Numbers
are IEEE Doubles.

I want a date type, not a datetime type like Date is. I want to
be able to compare dates without worrying about the time of day being
different.

If you only want to compare, not to add or subtract, then YYYY-MM-DD or
YYYYMMDD, but not mixed, work for AD 0000-9999, comparing as strings -
or, for YYYY-MM-DD, as Numbers.

An alternative would be to use integers for daycount, setting them with
DC = new Date(Date.UTC(Y, M', D)) / 864e5 // from memory
reversed by
D = new Date(DC * 864e5)
then using the UTC methods to get Y, M', D.

Alternatively, my site includes for doing those by pure arithmetic, at
least in Pascal.
 
G

Gene Wirchenko

In comp.lang.javascript message <o1vfe7l0gbc4nu2ievgf2849qk5hc66228@4ax.
com>, Tue, 13 Dec 2011 17:48:53, Gene Wirchenko <[email protected]> posted:
[snip]
It is a format internal to the company. It is YYMMDD. It is
used in contexts where a two-digit year is not a problem. For ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
example, when a shipment comes in, it is tagged as in
111213-0001
which would have been the first package in today.

That YY date is not ISO 8601, of course. The originators of that format
will be cursed in under 90 years time.

Nope. Note the carets above. It would not be long enough were
it just date and month, but 100 years is more than enough to conclude
any business with that shipment number. For dates where YYYY is
needed, they are entered in YYMMDD but with a window, and internally,
the full year is stored.

[snip]
In JavaScript, integer arithmetic is exact so long as all intermediate
and final results are integers not exceeding 2^53 (just over 9e15) in
magnitude. And, approximately, non-integer arithmetic is expected to be
exact between 1e-303 and 1e+308, provided that, expressed as fixed-
point, no values need "one" bits more than about 53 apart. All Numbers
are IEEE Doubles.

Thank you.
If you only want to compare, not to add or subtract, then YYYY-MM-DD or
YYYYMMDD, but not mixed, work for AD 0000-9999, comparing as strings -
or, for YYYY-MM-DD, as Numbers.

I do need to add and subtract. I have worked out those routines.
I borrow Date just a bit when adding/subtracting days.

I have to add and subtract months, too. Date arithmetic can be
rather interesting when dealing with the end of the month. What is
one month after September 29? October 29. What is one month after
September 30? One can argue October 30 or October 31. I go with the
latter.

My code is probably rather ornate. It is currently sitting at
about 500 lines.

[snip]

Sincerely,

Gene Wirchenko
 
D

Dr J R Stockton

In comp.lang.javascript message <74fle7tvc61qitmcrhv85mq0ovi1qpf11g@4ax.
I have to add and subtract months, too. Date arithmetic can be
rather interesting when dealing with the end of the month. What is
one month after September 29? October 29. What is one month after
September 30? One can argue October 30 or October 31. I go with the
latter.

No justification for choosing Oct 31, unless you have it in writing
signed by the Boss. The last day of September is really October 0,
which works for all Gregorian months.

One month ahead of August 31 is more interesting - September 30 or
October 1. IIRC, I have a month-incrementing routine to handle that.

You should persuade the company to use ISO 8601 Week-Numbering dates
instead. It saves a digit, and years have only two lengths in days
whereas months have four.

You probably know that an IE page can include both JavaScript and
VBscript. VBScript has DatePart, which can give ISO 8601 Week Numbers,
and gets it right for all but 13 dates in every 400 years. MS have
known about this for years, and have a truly horrible piece of code to
use instead. Of course, ISO is International, which means Foreign Down
South, and true American coders don't care for foreign standards. Any
of them who wants a standard just makes his own.
 
G

Gene Wirchenko

In comp.lang.javascript message <74fle7tvc61qitmcrhv85mq0ovi1qpf11g@4ax.


No justification for choosing Oct 31, unless you have it in writing
signed by the Boss. The last day of September is really October 0,
which works for all Gregorian months.

You are over confidently that you understand the situation that I
deal with.

We have work orders for clients under which various work
transactions are done. Many of these work orders are billed monthly
or semi-monthly, and they recur so new work orders are required for
the next month. When generating the next month's work orders, it is
significant that a date is the last day of the month. September 30 +
1 month is October 31 for us.
One month ahead of August 31 is more interesting - September 30 or
October 1. IIRC, I have a month-incrementing routine to handle that.

For us, it would be September 30.
You should persuade the company to use ISO 8601 Week-Numbering dates
instead. It saves a digit, and years have only two lengths in days
whereas months have four.

Since we do not deal in weeks but in months and half-months, that
would not work for us.

[snip]

Sincerely,

Gene Wirchenko
 
E

Evertjan.

Gene Wirchenko wrote on 19 dec 2011 in comp.lang.javascript:
You are over confidently that you understand the situation that I
deal with.

We have work orders for clients under which various work
transactions are done. Many of these work orders are billed monthly
or semi-monthly, and they recur so new work orders are required for
the next month.

And you do those things with clientside scripting?
When generating the next month's work orders, it is
significant that a date is the last day of the month. September 30 +
1 month is October 31 for us.

So if you tell Javascript
[I would urge you to use serverside (Java)script], this is a Javascript NG]
to add one month and to set the day to zero, you get the last day of the
month.

Try:

alert( new Date(2011, 12-1+1, 0) );

will return the last day of month 12 [December 2011]

============

Are al clients and the server in the same timezone, btw?
 

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,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top