Extending Error

R

Robert

Hi,

I thought it would be a good idea to make specialised error objects. So
I did something like this:

function IndexOutOfBoundsException(message)
{
Error.call(this, message);
}

IndexOutOfBoundsException.prototype = new Error();
....
throw new IndexOutOfBoundsException("bla");

I expected that I could use error.message after throwing
IndexOutOfBoundsException to retrieve the error message, but that
doesn't work. I just get an uncaught exception: Error.

Of course I can do
function IndexOutOfBoundsException(message)
{
this.message = message;
}

But I felt that the first example was better because
IndexOutOfBoundsException should have everything that an Error has.

Any comments why the first example does not work is appreciated.
 
V

VK

Robert said:
Hi,

I thought it would be a good idea to make specialised error objects. So
I did something like this:

function IndexOutOfBoundsException(message)
{
Error.call(this, message);
}

IndexOutOfBoundsException.prototype = new Error();
...
throw new IndexOutOfBoundsException("bla");

I expected that I could use error.message after throwing
IndexOutOfBoundsException to retrieve the error message, but that
doesn't work. I just get an uncaught exception: Error.

Of course I can do
function IndexOutOfBoundsException(message)
{
this.message = message;
}

But I felt that the first example was better because
IndexOutOfBoundsException should have everything that an Error has.

Any comments why the first example does not work is appreciated.

If you define the error message right at the moment of call:
throw new IndexOutOfBoundsException("bla");
then what the practical use of it? Just to tell "look'ma, OOP stuff"?
:) With the same success you could just
throw new Error("blah")
It would be much simplier.

If you want to imitate Java/C++ or maybe extend the error with extra
info - and following the unbreakable KISS principles - you could:

function ErrorFactory(message, longdesc) {
var err = new Error(message);
err.longdesc = 'This kind of error happens if ...';
return err;
}

function IndexOutOfBoundsException() {
return ErrorFactory(
'Index is out of bounds',
'This kind of error happens if ...');
}


try {
throw IndexOutOfBoundsException();
}
catch(e) {
alert(e.message);
alert(e.longdesc);
}
 
R

Robert

VK said:
If you define the error message right at the moment of call:
throw new IndexOutOfBoundsException("bla");
then what the practical use of it? Just to tell "look'ma, OOP stuff"?

Well you could do something like:

try {
var first = list.get(0);
}
catch (e) {
if (e instanceof IndexOutOfBoundsException)
return 0;
else
throw e;
}

But more importantly I just don't understand why my code does not work
and I do want to understand.
 
V

VK

Robert said:
Well you could do something like:

try {
var first = list.get(0);
}
catch (e) {
if (e instanceof IndexOutOfBoundsException)
return 0;
else
throw e;
}

But more importantly I just don't understand why my code does not work
and I do want to understand.

I don't know exactly - maybe because you're creating an instance of an
intrinsic object (Error) and implant this instance into the deep of
your own constructor chain. To trace all relations and the path of the
constructor call - it takes a pensil, a paper and some time of deep
thinking :)

Some may comment on why it doesn't work (whatever "work" and "doesn't
work" means here).

As a humble suggestion I would just keep custom objects by their own,
in the chain of extension and the general task of each one.

<script type="text/javascript">

function Exception(num,mes) {
Error.call(this);
this.type = 'Exception';
}

function BadMoodException(num, mes) {
Exception.call(this);
this.number = 666;
this.longdesc = "I'm not moody today.";
}

function IDontLikeYouException() {
BadMoodException.call(this);
this.message = "Some weird exception";
this.longdesc+= " And goblins got me."
}

function BoringStuff() {
}
BoringStuff.prototype.lastDrop = function() {
throw new IDontLikeYouException();
}


try {
var bs = new BoringStuff();
bs.lastDrop();
}
catch(e) {
alert(e.type);
alert(e.number);
alert(e.message);
alert(e.longdesc);
alert(e instanceof IDontLikeYouException);
}
</script>
 
R

Robert

VK said:
Some may comment on why it doesn't work (whatever "work" and "doesn't
work" means here).

"Work" means that the message property has been set, and "doesn't work"
means that it has not been set.
As a humble suggestion I would just keep custom objects by their own,
in the chain of extension and the general task of each one.

<script type="text/javascript">

function Exception(num,mes) {
Error.call(this);
this.type = 'Exception';
}

If Error.call(this, message) doesn't set the message then I don't this
it is useful to do Error.call(this) at all.
To keep the Exception an Error I think it's best to set the prototype.

The rest of the code isn't really related to my question.
 
V

VK

Robert said:
If Error.call(this, message) doesn't set the message then I don't this
it is useful to do Error.call(this) at all.

That was copy'n'paste error. In the ground-zero constructor you make
just generic Error object to fill up accordingly further in the chain.
Or you can overload constructor (it is not obligated to return "this"
every time) :

function Exception(num,mes) {
var err = new Error(num,mes);
err.type = 'Exception';
return err;
}
To keep the Exception an Error I think it's best to set the prototype.

IMHO you are still trying to complicate your life while JavaScript was
build to make it as easy as possible :)

As a hint: "throw" statement doesn't require Error object at all. You
can throw and catch anything: Error's, String's, Number's, Boolean's,
your own objects.
For fun of it you can throw the whole object out of itself on error.
For serious you can throw a string property of your object:
....
this.ErrorMessage = "Something wrong";
....
throw this.ErrorMessage;
 
R

Robert

VK said:
function Exception(num,mes) {
var err = new Error(num,mes);
err.type = 'Exception';
return err;
}

IMHO you are still trying to complicate your life while JavaScript was
build to make it as easy as possible :)

As a hint: "throw" statement doesn't require Error object at all.

I know. Still it is a good convention to throw something that is an Error.

Anyway I don't feel

function MyException(message) {
this.message = message;
}
MyException.prototype = new Error(); //or clone(Error.prototype)

complicates my life and is more complicated than your example.

However I think all this is off-topic. All I wanted to know is why
Error.call(this, message) didn't work.
 
V

VK

Robert said:
However I think all this is off-topic. All I wanted to know is why
Error.call(this, message) didn't work.

Besause intrinsic constructors has to be called explicetly as
constructors - with new keyword. Also all intrinsic objects have a
prototype property that is read-only. Some new *functionality* (read:
property or method) may be added to the prototype, but the object may
not be assigned a different prototype.

On a higher level: as I originally said: because you have to choose
between a la class-based inheritance and prototype inheritance.
JavaScript allows both, but using it in a cocktail is a call for
troubles. A "rule of thumb": if you have in one code both .prototype.
manipulations and new || call || apply then something is possibly
wrong with your code.

This works:

function IndexOutOfBoundsException(mes) {
return new Error(mes);
}

try {
throw new IndexOutOfBoundsException('blah');
}
catch(e) {
alert(e.message);
}
 
R

Richard Cornford

Robert wrote:
... . All I wanted to know is why
Error.call(this, message) didn't work.

It doesn't work because of:-

<quote cite="Ecma 262, 3rd Ed. Section 15.11.1">
15.11.1 The Error Constructor Called as a Function

When Error is called as a function rather than as a constructor, it
creates and initialises a new Error object. Thus the function call
Error(...) is equivalent to the object creation expression
new Error(...) with the same arguments.
</quote>

If calling the Error constructor as a function does the same as using it
as the operand of the - new - operator calling it as a method (which is
effectively what the - call - method does)is going to do the same;
constructing a new Error object and returning it.

Error.call(this, message)

is the equivalent of:-

new Error(message);

- and then you throw the newly created Error object away.

(Incidentally, don't expect to learn anything from VK, he doesn't really
know what he is doing hiself, and makes it up out of thin air.)

Richard.
 
R

Robert

Richard said:
Robert wrote:



It doesn't work because of:-

<quote cite="Ecma 262, 3rd Ed. Section 15.11.1">
15.11.1 The Error Constructor Called as a Function

When Error is called as a function rather than as a constructor, it
creates and initialises a new Error object. Thus the function call
Error(...) is equivalent to the object creation expression
new Error(...) with the same arguments.
</quote>

Thanks for your explanation!
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top