The JScript Type System, Part Two: Prototypes and constructors

A number of readers made some good comments on my article on JScript typing that deserve to be called out in more detail.

 

First, I was being a little sloppy in my terminology — I casually conflated static typing with strong typing, and dynamic typing with weak typing. Thanks for calling me on that. Under the definitions proposed by the reader, JScript would be a dynamically typed language (because every variable can take a value of any type) and a strongly typed language (because every object knows what type it is.) By contrast, C++ is a statically typed language (because every variable must have a type, which the compiler enforces) but also a weakly typed language (because the reinterpret cast allows one to turn pointers into integers, and so on.)

 

Second, a reader notes that one of the shortcomings of JScript is that though it is a strongly typed language (in our new sense) that it is a royal pain to actually determine the runtime type an object. The typeof operator has a number of problems:

 

* null is listed as being of the object type, though technically it is a member of the Null type.

* primitives (strings, numbers, Booleans) wrapped in objects are listed as being of the object type rather than their underlying type.

* JScript, unlike VBScript, does not interrogate COM objects to determine the class name.

* If JScript is passed a variant from the outside world that it cannot make sense of then typeof returns “unknown”.

 

Perhaps there is some other way. Prototype inheritance affords a kind of type checking, for example.

 

Prototype inheritance works like this.  Every JScript object has an object (or possibly null) called its prototype object.  So suppose an object foo has prototype object bar, and bar has prototype object baz, and baz has prototype object null.  If you call a method on foo then JScript will search foo, bar and baz for that method, and call the first one it finds. The idea is that one object is a prototypical object, and then other objects specialize it. This allows for code re-use without losing the ability to dynamically customize behaviour of individual objects.

 

Prototypes are usually done something like this:

 

var Animal = new Object();

// omitted: set up Animal object

function Giraffe(){

// omitted: initialize giraffe object.

}

Giraffe.prototype = Animal;

var Jerry = new Giraffe();

 

Now Jerry has all the properties and methods of an individual Giraffe object AND all the properties and methods of Animal.  You can use IsPrototypeOf to see if a given object has Animal on its prototype chain. Since prototype chains are immutable once created, this gives you a pretty reliable sort of type checking.

 

Note that Giraffe is not a prototype of Jerry. Note also that Animal is not the prototype of Giraffe! The object which is assigned to the prototype property of the constructor is the prototype of the instance.

 

Now, you guys are not the first people to point out to me that determining types is tricky. A few years ago someone asked me what the differences are amongst

 

if (func.prototype.IsPrototypeOf(instance))

 

and

 

if (instance.constructor == func)

 

and

 

if (instance instanceof func)

 

The obvious difference is that the first one looks at the whole prototype chain, whereas the second two look at the constructor, right? Or is that true? Is there a semantic difference between the last two? Actually, there is. Let’s look at some examples, starting with one that seems to show that there is no difference:

 

function Car(){}

var honda = new Car();

print(honda instanceof Car); // true

print(honda.constructor == Car);  // true

 

It appears that instance instanceof func and instance.constructor == func have the same semantics.   They do not.  Here’s a more complicated example that demonstrates the difference:

 

var Animal = new Object();

function Reptile(){ }

Reptile.prototype = Animal;

var lizard = new Reptile();

print(lizard instanceof Reptile); // true

print(lizard.constructor == Reptile); // false

 

In fact lizard.constructor is equal to Object, not Reptile.

 

Let me repeat what I said above, because no one understands this the first time — I didn’t, and I’ve found plenty of Javascript books that get it wrong. When we say

 

Reptile.prototype = Animal;

 

this does NOT mean “the prototype of Reptile is Animal”.  It cannot mean that because (obviously!) the prototype of Reptile, a function object, is Function.prototype.  No, this means “the prototype of any instance of Reptile is Animal”.  There is no way to directly manipulate or read the prototype chain of an existing object.

 

Now that we’ve got that out of the way, the simple one first:

 

instance instanceof func means “is the prototype property of func equal to any object on instance’s prototype chain?”  So in our second example, the prototype property of Reptile is Animal and Animal is on lizard’s prototype chain.

 

But what about our first example where there was no explicit assignment to the Car prototype?

 

The compiler creates a function object called “Car”.  It also creates a default prototype object and assigns it to Car.prototype.  So again, when we way

 

print(honda instanceof Car);

 

the instanceof operator gets the prototype property (Car.prototype) and compares it to the prototype chain of honda.  Since honda was constructed by Car it gets Car.prototype on its prototype chain.

 

To sum up the story so far,

Tags JScript Scripting

Comments (16)

Cancel reply

You must be logged in to post a comment.

  1. Erik Arvidsson says:Just a side note. The prototype object is usually called __proto__ ( [[Protoype]] in the spec) and almost all ECMAScript engines (except the Microsoft ones) allows read write of this private property.
  2. Log in to Reply
  3. November 6, 2003 at 2:40 pm
  4. Jay Hugard says:Can you explain the logic behind the following madness (in JScript Classic), which appears to mean that a string is not always a String but a regexp is always a RegExp?slit instanceof String => false
    sobj instanceof String => true
    slit instanceof Object => false
    sobj instanceof Object => true
    typeof( slit ) => string
    typeof( sobj ) => object
    typeof( slit ) == typeof( sobj ) => falseAs generated by:function evalprintln( s )
    {
    if( !s ) { println(“”); return }
    var out = s + ” => “;
    try{ out += eval(s) } catch( e ) { out += “Error: ” + e.description }
    println(out);
    }var tests = [
    “slit instanceof String”,
    “sobj instanceof String”,
    “slit instanceof Object”,
    “sobj instanceof Object”,
    “typeof( slit )”,
    “typeof( sobj )”,
    “typeof( slit ) == typeof( sobj )”,
    null,
    “relit instanceof RegExp”,
    “reobj instanceof RegExp”,
    “relit instanceof Object”,
    “reobj instanceof Object”,
    “typeof( relit )”,
    “typeof( reobj )”,
    “typeof( relit ) == typeof( reobj )”
    ];Log in to Reply
  5. for( var ix in tests ) { evalprintln( tests[ix] ) }
  6. var slit = “Literal String”;
    var sobj = new String( “String object” );
    var relit = /literal regexp/i
    var reobj = new RegExp( “RegExp object” );
  7. function println(s) { WScript.echo(s) /*System.Console.Out.WriteLine(s)*/ }
  8. relit instanceof RegExp => true
    reobj instanceof RegExp => true
    relit instanceof Object => true
    reobj instanceof Object => true
    typeof( relit ) => object
    typeof( reobj ) => object
    typeof( relit ) == typeof( reobj ) => true
  9. Conversly, what is the recommended way of determining if a value is a string?
  10. November 6, 2003 at 6:01 pm
  11. Peter Torr says:Erik — IIRC, Netscape removed the support for __proto__ from their engine some years ago because it was a bad idea to let people mess with the prototype chain this way. The ECMA standard does not require the property to be exposed, and it is dangerous to do so.
  12. Log in to Reply
  13. November 6, 2003 at 6:32 pm
  14. Peter Torr says:Jay, if you read the ECMA spec you will see that there are string primitives and string objects, just as there are number/boolean primitives and number/boolean objects. Basically you should never use “new String(…)” because it is a waste of time and energy.print(nlit instanceof Number)
    print(nlit instanceof Object)
    print(nobj instanceof Number)
    print(nobj instanceof Object)
  15. Log in to Reply
  16. var nlit = 42
    var nobj = new Number(42)
  17. November 6, 2003 at 6:40 pm
  18. IUnknown says:>JScript, unlike VBScript, does not interrogate COM objects to determine >the class name.Log in to Reply
  19. This gets the award for the most unrelated error message:
    TypeName(myObject)
    throws, when the type information is unavailable:
    Out Of string space: ‘TypeName’
  20. November 7, 2003 at 2:02 am
  21. Eric Lippert says:Can I see a repro for that? If the type name is unavailable, it should return “Unknown” or, if it is an IDispatch, “Object”.Log in to Reply
  22. TypeName does return “Out of string space”, but only when the attempt to allocate the string for the type name fails.
  23. November 7, 2003 at 12:54 pm
  24. Erik Arvidsson says:Peter: I know both the Mozilla engines (C and Java) and the Macromedia engine has support for this. I was pretty sure that Opera supported this as well but I just verifed that they do not.fucntion SubClass( args )
    {
    SuperClass.call( args );
    }
    SubClass.prototype.__proto__ = SuperClass.prototype;Log in to Reply
  25. Well, well… now that we have ECMAScript v4 around the corner there is no real need for this.
  26. I can understand why it is considered dangerous but usage of __proto__ can be very useful. For example it allows you to skip creating an instance that is used as the prototype.
  27. November 7, 2003 at 3:14 pm
  28. Eric Lippert says:> Well, well… now that we have ECMAScript v4 around the corner there is no real need for this.Log in to Reply
  29. That’s news to me. Could you more precisely define “around the corner”?
  30. November 7, 2003 at 5:02 pm
  31. Isaac says:> conflated static typing with strong typing
    “static typing” unhelpfully confuses when checks are made with the kind of checks that are made.Simpler to understand that JScript is a dynamically-checked untyped (safe?) language.Log in to Reply
  32. I think you demonstrated that it’s pretty hard to figure out what the type of a value is in JScript – so why insist on calling it a typed language?
  33. Simpler to understand that C++ is a statically-checked weakly-typed language (and also that some things are dynamically checked in C++).
  34. November 7, 2003 at 5:26 pm
  35. Anonymous says:[quote]Can I see a repro for that? If the type name is unavailable, it should return “Unknown” or, if it is an IDispatch, “Object”. [/quote]Also see this:
    http://groups.google.com/groups?q=typeName+%22Out+of+string+space%22
  36. Log in to Reply
  37. I got this when trying it on a COM object that uses run-time generated type info (ie. CreateDispTypeInfo). This only provides a minimal implementation of ITypeInfo. This is not common(or recommended) so I wouldn’t worry too much. If it helps the COM object is out of process.
  38. November 8, 2003 at 6:05 am
  39. Eric Lippert says:OK, then I have a guess as to what is happening. This is a TERRIBLE way to wait for an out-of-proc object (OOPO) to shut down. I’ll bet that there is a race condition here where the stub is returning a pointer to memory that becomes bad when the OOPO shuts down. So the TypeName method essentially gets passed a pointer to bad memory.So what we’ve got here is a memory corruption bug that is not crashing, but returning a bogus error instead.
  40. Log in to Reply
  41. Now suppose that the bad memory happens to be in a readable committed page, but contains garbage. We assume that the thing is a BSTR, so we look at the value stashed preceding the string body to determine the length. That could be any old number; the odds that the number happens to be larger than the largest remaining heap block are actually very good.
  42. November 8, 2003 at 10:57 am
  43. Anonymous says:The link I posted was just something I found while searching on the error. My situation relates to using run time type info. Have you tested TypeName with run time type info? It is obsolete and I only use it for testing so this discussion is essentially accademic.I think my object was based on the code found here, so if you want to copy and paste:
    http://docs.rinet.ru:8083/VidimyyC/vcu28fi.htm#I25
  44. Log in to Reply
  45. My guess is that something similar is happening, ITypeInfo must be returning bogus data. Assuming that you check all error results this could even be a bug in the implementation of ITypeInfo for CreateDispTypeInfo. As mentioned, this is obsolete and probably hasn’t been looked at for a long time.
  46. November 9, 2003 at 4:13 am
  47. Erik Arvidsson says:”That’s news to me. Could you more precisely define “around the corner”?”Known implemantions of ECMAScript v4:One possible reason for JS2 taking so long might be that ECMA moved all their resources to C# instead?
  48. Log in to Reply
  49. ActionScript

    QTScript

    JScript 7

  50. I guess I was wrong 😥 This has been in the works for way too long…
  51. May 2, 2004 at 7:07 am
  52. Eric Lippert says:A more likely reason is that Waldemar Horwat, who was the primary driving force behind the E4 spec, no longer works for AOL-Time-Warner-Netscape and hence is no longer being paid to drive the spec process forward. (Rumour has it that he’s at google now.)Log in to Reply
  53. Microsoft is still involved in the E4 process, but it is slow going.
  54. May 2, 2004 at 8:23 am
  55. Fabulous Adventures In Coding says:Log in to Reply
  56. October 7, 2004 at 1:32 pm
  57. Intercept instanceof | keyongtech says:PingBack from http://www.keyongtech.com/4947719-intercept-instanceof
  58. Log in to Reply
  59. January 18, 2009 at 12:41 pm
Advertisements

What is the Matrix?

I’m going to make a rare departure from technical stuff for a moment.  I’ve seen Matrix Revolutions twice in the last twelve hours, once in IMAX.

A number of people have asked me for an opinion.  To sum up in a spoiler-free manner:

First off, IMAX was better, though not enormously so.  (Oddly enough, Reloaded was enormously better in IMAX.)  As an example of state-of-the-art action movie making, it kicked ass.  But what about the underlying theme?  Let’s summarize:

The Matrix was a movie about kung fu vs. evil robots that asked and answered the philosophical question “what is the nature of reality?”

The Matrix Reloaded was a movie about kung fu vs. evil robots that asked and answered the philosophical question “what is the nature of free will?”

Matrix Revolutions was a movie about kung fu vs. evil robots that asked and answered the philosophical question “if Neo got into a fight with Agent Smith, who would win?”

We return you now to your regularly scheduled programming.


Commentary from 2019:

As I’ve noted before, the VSTO team code names and whatnot were all taken from The Matrix, and it was a fun theme.

I am not “spoiler averse” but I saw the first movie in the series knowing absolutely nothing about it, and was thrilled to discover that it had kung fu, evil robots, and literal brain-in-a-vat philosophy undergrad thought experiments. Sure, lots of it was hokey and unbelievable, but it had such energy, and was genuinely surprising.

I should not have been surprised by a reversion to the mean in the sequels; the original was hard to top.

 

The JScript Type System, part one

I thought I might spend a few days talking about the JScript and JScript .NET type systems, starting with some introductory material.

Consider a JScript variable:

var myVar;

Now think about the possible values you could store in the variable. A variable may contain any number, any string or any object. It can also be true or false or null or even undefined. This is a rather large set of possible values. In fact, the set of all legal values is infinite.Countably infinite, and in practice limited by available memory, but in theory there is no upper limit.

A type is characterized by two things, a set and a rule. First, a type consists of a subset (possibly infinitely large) of the set of all possible values. Second, a type defines a rule for transforming values outside the set into values in the set. (This rule may specify that certain values are not convertible and hence produce “type mismatch” errors.)

For example, String is a type. The set of all possible strings is an (infinite) subset of the set of all possible values, and there are rules for determining how all non-string values are converted into strings.

JScript Classic is a dynamically typed language. This means that any value of any type may be assigned to any variable without restriction. It is often said — inaccurately — that “JScript has only one type”. This is true only in the sense that JScript has no restrictions on what data may be assigned to any variable, and in that sense every variable is “the same type” – namely, the “any possible value” type. However, the statement is misleading because it implies that JScript supports no types at all, when in fact it supports six built-in types.

JScript .NET, by contrast, is an optionally statically-typed language. A JScript .NET variable may be given a type annotation which restricts the values which may be stored in the variable. This annotation is optional; an unannotated variable acts like a JScript variable and may be assigned any value.

JScript has the property that a value can always describe its own type at runtime. This is not true in, say, C, where you can have a void* and no way of asking it “are you pointing to an integer or a string?” In JScript, you can always ask a value what its type is and it will tell you.

The concept of subtyping is not particularly important in JScript Classic though it will become quite useful when we discuss JScript .NET classes later. Essentially a type T1 is a subtype of another type T2 if T1’s set of values is a subset of T2’s set of values. A type consisting of the set of all integers might be a subtype of a type consisting of all the numbers, for instance. (This is not how the integers are traditionally construed; the C type system makes integers and floats disjoint types, where the integer 1 and the float 1.0 are different values that happen to compare as equal — but comparisons across types is a subject for a later blog entry.)

Anyway, JScript Classic has six built-in types, all of which are disjoint. They are as follows:

The Number type contains all floating-point numbers as well as positive Infinity, negative Infinity and a special Not-a-Number (“NaN”) values. It may seem odd that “Not-a-Number” is a Number but this does in fact make sense. NaN is the value returned when an operation logically must return a number but no actual number makes sense. For example, when trying to convert the string “banana” to a Number, NaN is the result. Because numbers in JScript are actually represented by a 64 bit floating point number there are a finite number of possible Number values. The number of numbers is very large (in fact there are 18437736874454810627 possible numbers, which is just shy of 2^64.) Numbers have approximately fifteen decimal digits of precision and can range from as tiny as 2.2 x 10^-308 to as large as 1.7 x 10^308.

The String type contains all Unicode strings of any length (including zero-length empty strings.) The string type is for all practical purposes infinite, as the length of a string is limited only by the ability of the operating system to allocate enough memory to hold it.

The Boolean type has two values: true and false

The Null type has one value: null

The Undefined type has one value: undefined. All uninitialized JScript variables are automatically set to undefined

The Object type has an infinite number of values. An object is essentially a collection of named properties where each property can be a value of any type. In JScript many things are objects: functions, dates, arrays and regular expressions are all objects.

Types are not themselves “first class” objects in JScript, though they are in JScript .NET. I’ll discuss that, along with the differences between prototype and class inheritance, in later entries.

Comments (14)

  1. Dan Shappir

    One thing that really bugs me about JavaScript, a.k.a. JScript Classic, is the myriad yet incompatible methods to determine object type. The main problem being the various ways to define what constitutes a unique JavaScript type. For example, one could argue that the definition you have presented is to weak in that the Object group is not sufficiently specific.

    The obvious way to determine object type is the typeof operator. This operator returns a different set of values than the one you enumerated: “number,” “string,” “boolean,” “object,” “function,” and “undefined.” That is, null is identified as an object, yet JScript functions are magically identified as being something more than just any old object.

    Also, a few may know that JScript’s typeof can also return “unknown” in certain weird cases.

    Add to this confusion that typeof(3) is “number” but typeof(new Number(3)) is “object”. I can understand why this is, but is can be confusing. For example, what would be the output from the following code:

    Number.prototype.showType = function() { alert(typeof(this)); }
    (3).showType();

    Automatic boxing, I know.

    Another way to determine types is using the constructor property. This allows you to determine if an object is an Array for example:

    if ( x.constructor === Array ) …

    or you can use the instanceof operator.

    You might also care about the subclass of a particular type, as determined by it’s prototype. In this case you would use the isPrototypeOf method.

    Finally, since JavaScript uses duck-typing, what might actually be relevant is not an object’s exact type, but which properties it implements. In this case you would use the in operator, or maybe even propertyIsEnumerable.

    The situation is even worse when you involve objects that are external to JScript. For example, DOM methods are not identified as functions and DOM collections may look a bit like arrays but aren’t.

  2. I’ve seen slightly different uses of the vocabulary that your article uses. Type systems can usefully be classified along two axes, namely static / dynamic and strong / weak.

    Static typing means variables have associated (compile-time) type information and can only be bound to values of some type. By your examples, JScript classic is dynamically typed, since a variable can be bound to values of different types during its lifetime. This would not be possible in a statically typed language, such as C.

    Strong typing essentially means that there’s a typeof operator – i.e., a value (not the variable, but the thing it is bouund to) holds information about its type. C is weakly typed: a value is just a bit pattern in memory without any explicit type information, and there’s nothing forbidding anyone from reinterpreting a `long’ value as a pointer to a structure. This would not be possible in a strongly typed language.

  3. Michael Feathers

    I’ll second Rudi on this. The definitions that he mentions are becoming more pervasive. If Strong/Weak and Static/Dynamic aren’t seen as orthogonal then you have the situation where Smalltalk and early C are considered to have the same kind of type system, and that’s nearly a criminal misrepresentation. It equates having well defined errors detected at runtime with silent memory corruption that crashes a system if you are lucky, or just makes things randomly and silently wrong over the life of a system, if you aren’t.

  4. Isaac

    “implies that JScript supports no types at all”
    Much of the confusion and ambiguity in the terms we use seems to stem from fear of negative connotations.

    It’s unclear to me why we cannot work with the terms defined by Luca Cardelli (in Handbook of Computer Science and Engineering, Chapter 103. CRC Press, 1997; http://citeseer.nj.nec.com/cardelli97type.html
    ) .

    typed (untyped)
    “A program variable can assume a range of values during the execution of a program. An upper bound of such a range is called a type of the variable. Languages that do not restrict the range of variables are called untyped languages.”

    safe (unsafe)
    “A program fragment is safe if it does not cause untrapped errors to occur. Languages where all program fragments are safe are called safe languages.”

    So, Smalltalk is untyped and safe (no untrapped errors), and C is typed and unsafe.

    (Of course, he also defines explicit/implicit types, static checking/dynamic checking, strongly checked/weakly checked…)

  5. Just some guy

    You describe a subtype in terms of a subset of the possible values of a super type. But in practice (in most all exaples I have seen , in textbooks and so forth) the opposite is true… This convention is also enforced by some language rules (which I will get to).

    For example the class java.util.zip.JarFile extends java.util.zip.ZipFile, but it represents both a zip file AND a jar file, so clearly it’s set of possible values is larger. But it is also a subtype of ZipFile…. how can this be? does it violate the rules of subtypeing? and if it did, why does the compiler not reject it?

    Because most all languges have subtypes inheret attributes of the supertpe, it is easy for developers to make these kinds of mistakes.

  6. Michael Feathers

    >It’s unclear to me why we cannot work with the terms defined by Luca >Cardelli (in Handbook of Computer Science and Engineering, Chapter 103. >CRC Press, 1997; http://citeseer.nj.nec.com/cardelli97type.html
    >typed (untyped)
    >”A program variable can assume a range of values during the execution of a >program. An upper bound of such a range is called a type of the variable. >Languages that do not restrict the range of variables are called untyped >languages.”

    It sounds like he is talking about variables, and that’s fine, but in some OO languages you don’t have data variables, you have references to objects. Calling languages like these untyped doesn’t make much sense because the objects themselves obviously have types. In other words, the languages features are at a level of abstraction where that definition isn’t very relevant.

    Another example. In some languages you don’t have to be particularly concerned if you attempt to increment an integer beyond its range. The object adjusts its range dynamically. Now which is the variable? The object or the reference that holds it? If you say it is the reference, then all references have the same type, but if you say it is the object, well, what is its type really? And, do you ever assign an object to another? In many OO languages you can’t you can only assign references.

  7. Michael Feathers

    >It’s unclear to me why we cannot work with the terms defined by Luca >Cardelli (in Handbook of Computer Science and Engineering, Chapter 103. >CRC Press, 1997; http://citeseer.nj.nec.com/cardelli97type.html
    >typed (untyped)
    >”A program variable can assume a range of values during the execution of a >program. An upper bound of such a range is called a type of the variable. >Languages that do not restrict the range of variables are called untyped >languages.”

    It sounds like he is talking about variables, and that’s fine, but in some OO languages you don’t have data variables, you have references to objects. Calling languages like these untyped doesn’t make much sense because the objects themselves obviously have types. In other words, the languages features are at a level of abstraction where that definition isn’t very relevant.

    Another example. In some languages you don’t have to be particularly concerned if you attempt to increment an integer beyond its range. The object adjusts its range dynamically. Now which is the variable? The object or the reference that holds it? If you say it is the reference, then all references have the same type, but if you say it is the object, well, what is its type really? And, do you ever assign an object to another? In many OO languages you can’t you can only assign references.

  8. > You describe a subtype in terms of a subset of the possible values of a super type. But in practice (in most all exaples I have seen , in textbooks and so forth) the opposite is true
    > For example the class java.util.zip.JarFile extends java.util.zip.ZipFile, but it represents both a zip file AND a jar file, so clearly it’s set of possible values is larger.

    If JarFile is a subtype of ZipFile then every instance of JarFile is also an instance of ZipFile. But that’s the definition of “subset” — if every member of X is a member of Y then X is a subset of Y.

    Therefore, I’m not following your train of thought here. The set of all objects that are ZipFiles contains all JarFiles plus all the non-JarFile instances of ZipFiles, so how could JarFiles be a larger set?

  9. Curt Sampson

    You seem to have confused the “set of possible values.” With type systems here we’re concerned about the number of possible values a variable can hold. A variable of type ZipFile can reference any ZipFile object, and any JarFile object. But a variable of type JarFile can reference only JarFile objects, not ZipFile objects that are not JarFile objects. Thus, a JarFile variable holds a subset of the values that can be held in a ZipFile variable.

  10. Just some guy

    Eric Lippert Writes:
    “I’m not following your train of thought here…if every member of X is a member of Y then X is a subset of Y. ”

    Thank you for clearing me up. My confusion was in thinking that increasing the functionality in the subclass increases the values it can represent… like a TitledBorder with a Border superclass.

    I just assumed that the Border type does not include a border with a title, because it does not properly handle the title, ( has no operators for title) it shold not include values with titles…. only the TitledBorder type should include that valeu. But a TitledBorder also can handle a border with not title, as it is also a border. So I just assumed that TitledBorder will represnt a superset..

    But as you note, the Border type should include borders that have titles. Even if it can not represent thoese titles properly. It just seemed silly that a border without a title is not a valid TitledBorder (or a zipfile without a manifes is a valid jar file).. but the reverse is ture, even though i have no way of representing/manipulating the title/manifest.

    But i see my fault.

  11. Isaac

    > It sounds like he is talking about variables, and that’s fine
    Yes, the definition is in terms of the range of values that can be assigned to a variable.

    > but in some OO languages you don’t have data variables,
    > you have references to objects
    The distinction between value types and reference types is unimportant to this definition. In a typed language we may restrict a variable to hold references to a particular type – such as POINTER TO ZipFile. In an untyped language we don’t do that.

    > Now which is the variable? The object or the reference that holds it?
    > If you say it is the reference, then all references have the same type
    I’m unsure what you mean. Let’s be more concrete (Smalltalk):
    | myVariable |
    myVariable := OrderedCollection new.
    Now myVariable holds a reference to an instance of OrderedCollection.
    myVariable := Dictionary new.
    Now myVariable holds a reference to an instance of Dictionary.

    myVariable is “the variable”. Any value can be assigned to myVariable. The language is untyped.

    In some other language
    ArrayList myVariable = new ArrayList();
    Now myVariable holds a reference to an instance of ArrayList.
    myVariable = new HashMap();
    ***Fails – the range of values that myVariable may hold is restricted to references to ArrayList instances. The language is typed.

    This kind of definition has been called misleading because languages without typed variables do have values of different types.
    OTOH being *untyped* is the easy explanation for why we have ad-hoc polymorphism and loose-coupling in these languages. They got rid of type restrictions – proud to be untyped and safe.

    In that universe, “JScript Classic” would be untyped, and “JScript .NET” would be typed (presumably “untyped” variables are “restricted” to some universal type).

  12. Michael Feathers

    >This kind of definition has been called misleading because languages >without typed variables do have values of different types.
    >OTOH being *untyped* is the easy explanation for why we have ad-hoc >polymorphism and loose-coupling in these languages. They got rid of type >restrictions – proud to be untyped and safe.

    Except they didn’t.

    myVariable := Dictionary new.
    myVariable floggle.

    Sending floogle to myVariable is a type error, it is just one detected at run-time.

  13. Isaac

    Can we find a better forum for this discussion?

    >> They got rid of type restrictions
    > Except they didn’t.

    Wasn’t it clear from the context that “type restrictions” refered to type restrictions on variables? Ain’t none of those in Smalltalk

    I’m a bit surprised that there’s anything controversial about this – back in 1990, Justin Graver & Ralph Johnson were quite clear that “Smalltalk is untyped”, see “A Type System for Smalltalk”.
    http://citeseer.nj.nec.com/graver90type.html

    > Sending floogle to myVariable is a type error
    It might be if Dictionary was a type, but it isn’t – it’s a class. Implementation is inherited, specification is ignored (notably in Dictionary being a subclass of Set – see the paper).
    So “Sending floogle to myVariable” is just messageNotUnderstood

Eval is evil, part two

As
I promised, more information on why eval is evil.  (We once considered having
T-shirts printed up that said “Eval is evil!” on one side and “Script happens!” on
the other, but the PM’s never managed to tear themselves away from their web browsing
long enough to order them.)

 

 

/>Incidentally, a buddy
of mine who is one of those senior web developer kinda guys back in

Waterloo
sent me an email yesterday saying “Hello, my name is Robert and I am an evalaholic”.
People, it wasn’t my intention to
start a twelve step program, but hey, whatever works!

 

As
discussed
the other day
, eval on
the client is evil because it leads to sloppy, hard-to-debug-and-maintain programs
that consume huge amounts of memory and run unnecessarily slowly even when performing
simple tasks.  But like I said in my performance
rant
, if it’s good
enough
, then hey, it’s good enough.  Maybe
you don’t need to write maintainable,
efficient code.  Seriously! Script is
often used to write programs that are used a couple of times and then thrown away,
so who cares if they’re slow and inelegant?

 

But eval on
the server is an entirely different beast.  First
off, server scenarios are generally a lot more performance sensitive than client scenarios.  On
a client, once your code runs faster than a human being can notice the lag, there’s
usually not much point in making it faster.  But  as
I mentioned earlier
, ASP goes to a lot of work to ensure that for a given page,
the compiler only runs once. An eval defeats
this optimization by making the compiler run every time the page runs! On a server,
going from 25 ms to 40 ms to serve a page means going from 40 pages a second to 25
pages a second, and that can be expensive in real dollar terms.

 

But
that’s not the most important reason to eschew eval on
the server.  Any use of eval (or
its VBScript cousins Eval, Execute and ExecuteGlobal)
is a potentially enormous security hole. 

 

<%

var
Processor_ProductList;

var
Software_ProductList;

var
HardDisk_ProductList;

//

CategoryName
= Request.QueryString(“category”);

ProductList
= eval(CategoryName & “_ProductList”);

//

 

What’s
wrong with this picture?  The
server assumes that the client is not hostile.
  Is
that a warranted assumption?  Probably
not!  You know nothing about the client
that sent the request.  Maybe your client
page only sends strings like “Processor” and “HardDisk” to the server, but anyone
can write their own web page that sends

 

((new
ActiveXObject(‘Scripting.FileSystemObject’)).DeleteFile(‘C:*.*’,true)); Processor

 

which
will cause eval to
evaluate

 

((new
ActiveXObject(‘Scripting.FileSystemObject’)).DeleteFile(‘C:*.*’,true)); Processor_ProductList

 

Obviously
that’s a pretty unsophisticated attack.  The
attacker can put any
code in there that they want
, and it will run in the context of the server process.  Hopefully
the server process is not a highly privileged one, but still, there’s vast potential
for massive harm here just by screwing up the logic on your server.

 

Never
trust the input to a server, and try to never use 
eval on
a server.  
Eval injection
makes SQL injection look tame!

 

To
try and mitigate these sorts of problems, JScript .NET has some restrictions on its
implementation of eval,
but that’s a topic for another entry.

 

Tags ASP JScript Performance Scripting Security

Comments (6)

You must be logged in to post a comment.

  1. CliffGreat information, but how about some advice on what to use as an alternative?  The point to Eval/Execute is to provide the ability to execute code that you wont know you need until the last minute.  I can see why Eval might be bad, but how would one go about it otherwise?Log in to Reply
  2. Answers are the difference between being a thermometer & a thermostat.  Thermometers just let you know something is wrong.  A thermostat sees the problem & then takes action to actually do something to improve the situation.
  3. April 13, 2006 at 12:29 pm
  4. Eric LippertHow would one go about WHAT otherwise?  To answer the question, I’d have to know what eval/execute was being used for in the first place!Log in to Reply
  5. That said, _most_ uses of eval that I’ve seen could be rewritten to use a lookup table, and the resulting code would be smaller, faster, easier to maintain, and have fewer security holes.
  6. April 13, 2006 at 12:55 pm
  7. EnigmaticWe are using XAML to write validation rules which are evaluated on the fly using Eval. So how would you go about evaluating at runtime a condition whose values may change depending on the input of the user?
  8. Log in to Reply
  9. March 15, 2007 at 6:37 pm
  10. Why Won’t eval() Eval My JSON? (Or: JSON Object !== Object Literal) « The Curious SchemerPingBack from http://rayfd.wordpress.com/2007/03/28/why-wont-eval-eval-my-json-or-json-object-object-literal/
  11. Log in to Reply
  12. March 28, 2007 at 2:14 pm
  13. Calling a sub | keyongtechPingBack from http://www.keyongtech.com/1169946-calling-a-sub
  14. Log in to Reply
  15. January 21, 2009 at 11:50 pm
  16. MarlinIn answer to Eric’s question, this worked for me in ASP classic, JScript:I found it at JSON .org and I saved it as json-sans-eval.asp and edited it so that it started with <% and ended with %><!– #include file=”json_sans_eval.asp” –>Worked great.
  17. Then instead of eval(X) is used jsonParse(X).
  18. Then in my code where I was using eval I put this at towards the top (outside of the <% %>
  19. code.google.com/…/json-sans-eval
  20. March 22, 2012 at 3:42 pm

A parable

Once upon a time I was in high school. Ah, the halcyon days of my youth. One day I was sitting in class, minding my own business when the teacher said: “Does anyone have a thin metal ruler?”

No answer. Apparently no one had a thin metal ruler.

“No? How about a nail file?”

No answer. Now, I cannot imagine that of all the girls in the class, not one of them had a nail file. But I can well imagine that none of them wanted to share it with a teacher.

“No? Hmm.”

So I piped up: “What do you need a nail file for?”

“I have this big staple in this document that I need to remove.”

Upon which point one of my classmates mentioned that he had a staple remover. Problem solved.

Over and over again I find that script customers (both internal consumers here at Microsoft and third-party developers) frequently ask questions like my teacher. That is, they have a preconceived notion of how the problem is going to be solved, and then ask the necessary questions to implement their preconceived solution. And in many cases this is a pretty good technique! Had someone actually brought a thin metal ruler to class, the problem would have been solved. But by choosing a question that emphasizes the solution over the problem, the questioner loses all ability to leverage the full knowledge of the questionees.

When someone asks me a question about the script technologies I almost always turn right around and ask them why they want to know. I might be able to point them at some tool that better solves their problem. And I might also learn something about what problems people are trying to solve with my tools.

Joel Spolsky once said that people don’t want drills, they want holes. As a drill provider, I’m fascinated to learn what kinds of holes people want to put in what kinds of materials, so to speak. Sometimes people think they want a drill when in fact they want a rotary cutter.


Commentary from 2019:

First off, I misattributed that quotation. “People don’t want to buy a quarter-inch drill, they want a quarter-inch hole.” is a quote from the economist Theodore Levitt. At the time I wrote this, I was sure that I had read about this idea in a Joel On Software article, but if I did, I cannot find it now. Apologies for the error.

Second, I did not know at the time that we have a name for this pattern of “have a problem, get a crazy idea about a solution, ask baffling questions about the crazy idea, rather than stating the problem directly” that we see so often on StackOverflow. It is an “XY problem“, which strikes me as a terrible name.

Third, I am reminded of a story about the time I was helping Morton Twillingate put a roof on his shed. “Hand me the screw driver there b’y,” he said so I handed him a Philips head screwdriver. “Sweet t’underin’ Jaysus b’y, give me the screw driver!” he said, pointing at the hammer in my other hand, “If I’d wanted the screw remover I’d have said so!”

 

Eval is evil, part one

The eval method
— which takes a string containing JScript code, compiles it and runs it — is probably
the most powerful and most misused method in JScript. There are a few scenarios in
which eval is
invaluable.  For example, when you are
building up complex mathematical expressions based on user input, or when you are
serializing object state to a string so that it can be stored or transmitted, and
reconstituted later.

 

However,
these worthy scenarios make up a tiny percentage of the actual usage of eval.  In
the majority of cases, eval is
used like a sledgehammer swatting a fly — it gets the job done, but with too much
power.  It’s slow, it’s unwieldy, and
tends to magnify the damage when you make a mistake.  Please
spread the word far and wide: if you are considering
using 
eval then
there is probably a better way. 
 Think
hard before you use eval.

 

Let
me give you an example of a typical usage.

 

<span
id=”myspan1″></span>

<span
id=”myspan2″></span>

<span
id=”myspan3″></span>

function
setspan(num, text)

{

eval(“myspan”
+ num + “.innerText = ‘” + text + “‘”);

}

 

Somehow
the program is getting its hands on a number, and it wants to map that to a particular
span.  What’s wrong with this picture?

 

Well,
pretty much everything.  This
is a horrid way to implement these simple semantics.
  First
off, what if the text contains an apostrophe?  Then
we’ll generate

 

myspan1.innerText
= ‘it ain’t what you do, it’s the way thacha do it’;

Which
isn’t legal JScript.  Similarly, what
if it contains stuff interpretable as escape sequences?  OK,
let’s fix that up.

 

eval(“myspan”
+ num).innerText = text;

If
you have to use 
evaleval as
little of the expression as possible, and only do it once.  
I’ve
seen code like this in real live web sites:

 

if (eval(foo)
!= null && eval(foo).blah == 123)

eval(foo).baz
= “hello”;

 

Yikes!  That
calls the compiler three times to compile up the same code!  People, eval starts
a compiler
.  Before
you use it, ask yourself whether there is a better way to solve this problem than
starting up a compiler!

 

Anyway,
our modified solution is much better but still awful.  What
if num is
out of range?  What if it isn’t even a
number?  We could put in checks, but why
bother?  We need to take a step back here
and ask what problem we are trying to solve.

 

We
have a number.  We would like to map that
number onto an object.  How would you
solve this problem if you didn’t have eval?  This
is not a difficult programming problem!  Obviously
an array is a far better solution:

 

var spans
= new Array(null, myspan1, myspan2, myspan3);

function
setspan(num, text)

{

if
(spans[num] != null)

spans[num].innertext
= text;

}

 

And
since JScript has string-indexed associative arrays, this generalizes to far more
than just numeric scenarios.  Build
any map you want.  JScript even provides
a convenient syntax for maps!

 

var spans
= { 1 : mySpan1, 2 : mySpan2, 12 : mySpan12 };

 

Let’s
compare these two solutions on a number of axes:

 

Debugability:
what is easier to debug, a program that dynamically generates new code at runtime,
or a program with a static body of code?  What
is easier to debug, a program that uses arrays as arrays, or a program that every
time it needs to map a number to an object it compiles up a small new program?

 

Maintainability:
What’s easier to maintain, a table or a program that dynamically spits new code?

 

Speed:
which do you think is faster, a program that dereferences an array, or a program that
starts a compiler?

 

Memory:
which uses more memory, a program that dereferences an array, or a program that starts
a compiler and compiles a new chunk of code every time you need to access an array?

 

There
is absolutely no reason to use eval to
solve problems like mapping strings or numbers onto objects.  Doing
so dramatically lowers the quality of the code on pretty much every imaginable axis.

 

It
gets even worse when you use eval on
the server, but that’s another post.

 

 

Tags JScript Performance Scripting

Comments (29)

You must be logged in to post a comment.

  1. Dan ShappirIf I were to rewrite the HTML I would implement it as:No eval and also no lookup table that must be kept in sync with the HTML.Speaking of “new Function”, eval’s sibling so to speak, here is an interesting if somewhat extreme example of its use:The local frames were generated using a custom OSP, feeding data directly into the HTML via binding. The user could filter this view by filling in a search form. The way filtering was done was that the OSP would generate an event, intercepted by a JavaScript event handler. If this handler returned false, the specific record was excluded.Fun times.
  2. Log in to Reply
  3. A big problem was performance – the view could contain hundreds, even thousands of records in extreme cases. Thus, it was imperative that the filtering would be as quick as possible. What I did was generate the JavaScript event handler on the fly based on the user’s input. This way I could construct optimal code for evaluating the specific filter expression.
  4. I was a lead developer for an application that was a mixed thin/fat client – some of the data was maintained locally, thus accessible while offline. The rest of the data was online. The way we did it was that the entire UI was DHTML + JavaScript, with some frames generated locally and the others provided by a web server.
  5. BTW, we do use eval a couple of time in the BeyondJS library, but BeyondJS is not you average JavaScript code. One example where we use it is to construct functions on the fly. The reason we use eval instead of “new Function” is because we need to create the function in the current scope.
  6. function setspan(num, text)
    {
    var span = document.all(“myspan” + num);
    if (span != null)
    span.innertext = text;
    }
  7. November 1, 2003 at 5:21 pm
  8. BradleyAnother good way to get an element in the DOM is to use:
    document.getElementById(“myspan” + num);Log in to Reply
  9. Another benefit of this method (over eval or document.all) is that if you accidentally insert two (or more) elements with the same ID into the document, getElementById will always return an element (the first one), while eval (or document.all) will return a collection of all the elements with that ID, possibly causing code that expects a single element to fail.
  10. November 1, 2003 at 10:06 pm
  11. Dan ShappirgetElementById has one significant advantage over document.all – it’s part of the DOM standard endorsed by the W3C, and is thus also supported by Mozilla. On the downside, it not supported by IE4 (not sure if anyone still cares about that version).Log in to Reply
  12. I’m not sure, however, that the fact that it returns the first element in the event of multiple existing elements with the same ID is an advantage. It means that if you accidentally create two elements with the same ID you might not notice and as result not fix the bug.
  13. November 2, 2003 at 4:21 am
  14. Meme WasherIn the comp.lang.javascript Javascript Best Practices document; I came across an interesting discussion of the reasons for preferring square bracket notation to eval(). The consensus seems to be that eval is evil, and that &quot;if it exists in your page,..
  15. Log in to Reply
  16. June 6, 2006 at 8:35 am
  17. Mike’s Lookout » Blog Archive » Disection of a Spam CommentPingBack from http://www.belshe.com/2006/10/25/disection-of-a-spam-comment/
  18. Log in to Reply
  19. October 25, 2006 at 2:19 pm
  20. SteveEval is easy… Hahahahahahah.Also:-Maintainability. Depends on the situtaion. Eval may be better.Memory. Aint a problem.Log in to Reply
  21. I think a lot of of “Gurus” are opposed to anything that makes life easier for us lesser beings.
  22. Speed. If it’s fast enough who cares.
  23. Debugability.   Well if bugs turn up I can always rewrite it the hard way. Also in many cases the eval code may be simpler and more readable.
  24. If  a fly is bugging me and I have a sledgehammer beside me, why go inside for and search for a flyswatter? That might take me half an hour.
  25. November 30, 2006 at 5:35 pm
  26. AlbertoSteve Rocks!Though, going back to the eval thing, it is true that the eval is bad and that there is a number of workarounds (one of the reasons why i love js!).doing eval(‘obj.’ + methodName) seems a piece of cake. What about obj[methodName]() ? Much better.function ClassFactory(constructorClassName){    eval(‘myObj=new ‘ + constructorClassName +'()’)}Log in to Reply
  27. A class factory on the fly!!!
  28.     return myObj;
  29.     var myObj;
  30. Though there is nothing like:
  31. Workaround A: gotta call a method of an object but i know only the name.
  32. I agree, a religious conception of programming is the whorthest evil there is (bracket should be opened on a new line, etc);
  33. January 10, 2007 at 10:57 pm
  34. How to Use window.onload the Right WayPingBack from http://blog.roberthahn.ca/articles/2007/02/02/how-to-use-window-onload-the-right-way
  35. Log in to Reply
  36. February 2, 2007 at 10:01 am
  37. Why Won’t eval() Eval My JSON? (Or: JSON Object !== Object Literal) « The Curious SchemerPingBack from http://rayfd.wordpress.com/2007/03/28/why-wont-eval-eval-my-json-or-json-object-object-literal/
  38. Log in to Reply
  39. March 28, 2007 at 2:14 pm
  40. Template-Engine – Seite 3 – PHP @ tutorials.de: Forum, Tutorial, Anleitung, Schulung & HilfePingBack from http://www.tutorials.de/forum/php/268678-template-engine-3.html#post1415829
  41. Log in to Reply
  42. May 6, 2007 at 4:14 am
  43. Twey— QUOTE —function ClassFactory(constructorClassName){    eval(‘myObj=new ‘ + constructorClassName +'()’)}How about:function ClassFactory(constructorClassName) {}(Although the usefulness of this function is debatable, and the names misleading: there are no classes in JScript.)— CODE — eval(‘myobject.’ + propName + ‘ = ‘ “’ + propValue + ‘”’);// versus— END CODE —* I say “almost” — the example scenarios EricLippert gave are perfectly valid reasons to use eval(), and to write a dedicated JS parser for these situations is (usually) silly when eval() is already available.Log in to Reply
  44. P.S. Ugh, I had to switch browsers to post this — no Konq support on a blog that deals with web coding?
  45. Especially note, if we’re discussing getElementById() support, that some older browsers don’t support try/catch, so the only option when given a bad property name or value is to error out if you want to support these browsers.
  46. myobject.someProperty[propName] = propValue;
  47. } catch(e) {}
  48. try {
  49. Almost* everything that can be done with eval() can be done with square bracket notation, and not only is it more efficient, it’s also almost invariably simpler (you don’t have to worry about whether the input will form a valid JS expression, for a start) and produces neater code than eval():
  50. — END CODE —
  51.  return new this[constructorClassName]();
  52. — CODE —
  53. — END QUOTE —
  54.     return myObj;
  55.     var myObj;
  56. Though there is nothing like:
  57. August 14, 2007 at 4:03 am
  58. 5 Things I Hate About Ruby « Devi Web DevelopmentPingBack from http://deviweb.wordpress.com/2007/09/03/5-things-i-hate-about-ruby/
  59. Log in to Reply
  60. September 3, 2007 at 7:19 am
  61. The best Smarty + Zend View Helpers solution! | CodeUtopiaPingBack from http://codeutopia.net/blog/2007/11/03/the-best-smarty-zend-view-helpers-solution/
  62. Log in to Reply
  63. November 6, 2007 at 12:52 am
  64. Ajax Girl » Blog Archive » Is using a JS packer a security threat?PingBack from http://www.ajaxgirl.com/2008/01/26/is-using-a-js-packer-a-security-threat/
  65. Log in to Reply
  66. January 26, 2008 at 4:32 am
  67. Javascript News » Blog Archive » Is using a JS packer a security threat?PingBack from http://www.javascriptnews.com/javascript/is-using-a-js-packer-a-security-threat.html
  68. Log in to Reply
  69. January 26, 2008 at 12:54 pm
  70. The Best Web Design ComicsPingBack from http://blogsurfer.net/7270/the-best-web-design-comics-13.html
  71. Log in to Reply
  72. January 26, 2008 at 1:04 pm
  73. Is using a JS packer a security threat?PingBack from http://blogsurfer.net/7406/is-using-a-js-packer-a-security-threat-2.html
  74. Log in to Reply
  75. January 27, 2008 at 12:33 am
  76. Is using a JS packer a security threat?PingBack from http://blogsurfer.net/7518/is-using-a-js-packer-a-security-threat-3.html
  77. Log in to Reply
  78. January 27, 2008 at 9:31 am
  79. Don’t build your Web site in a vacuumPingBack from http://blogsurfer.net/7618/dont-build-your-web-site-in-a-vacuum-56.html
  80. Log in to Reply
  81. January 27, 2008 at 5:33 pm
  82. WordPress Admin Theme: DeconstructedPingBack from http://blogsurfer.net/7663/wordpress-admin-theme-deconstructed.html
  83. Log in to Reply
  84. January 27, 2008 at 9:10 pm
  85. Is using a JS packer a security threat?PingBack from http://blogsurfer.net/7923/is-using-a-js-packer-a-security-threat-4.html
  86. Log in to Reply
  87. January 29, 2008 at 12:32 am
  88. Manipulating innerHTML removes eventsPingBack from http://blogsurfer.net/8079/manipulating-innerhtml-removes-events-70.html
  89. Log in to Reply
  90. January 29, 2008 at 2:02 pm
  91. Web Content: Not just YOUR words and picturesPingBack from http://blogsurfer.net/8135/web-content-not-just-your-words-and-pictures-44.html
  92. Log in to Reply
  93. January 29, 2008 at 8:35 pm
  94. Our new additionPingBack from http://blogsurfer.net/8500/our-new-addition-39.html
  95. Log in to Reply
  96. January 31, 2008 at 7:03 am
  97. Performance web &raquo; Archive du blog &raquo; JSON ?PingBack from http://performance.survol.fr/2008/04/json/
  98. Log in to Reply
  99. April 25, 2008 at 1:17 pm
  100. Ajax performance analysis – Blue Box SolsPingBack from http://blueboxsols.com/?p=1813
  101. Log in to Reply
  102. September 10, 2008 at 1:09 pm
  103. Sergio PereiraThis post is part of a series called JavaScript Demystified . I'm pretty sure by now you have heard
  104. Log in to Reply
  105. March 31, 2009 at 6:27 pm
  106. linkfeedr &raquo; Blog Archive &raquo; JavaScript: Avoid the Evil eval – RSS Indexer (beta)PingBack from http://www.linkfeedr.com/development/140126/javascript-avoid-the-evil-eval.html
  107. Log in to Reply
  108. May 22, 2009 at 7:02 pm
  109. mr.tangoh,I can’t understand.my english is pool enough
  110. Log in to Reply
  111. July 13, 2012 at 12:05 am

Eval is evil, part one

The eval method
— which takes a string containing JScript code, compiles it and runs it — is probably
the most powerful and most misused method in JScript. There are a few scenarios in
which eval is
invaluable. For example, when you are
building up complex mathematical expressions based on user input, or when you are
serializing object state to a string so that it can be stored or transmitted, and
reconstituted later.

 

However,
these worthy scenarios make up a tiny percentage of the actual usage of eval. In
the majority of cases, eval is
used like a sledgehammer swatting a fly — it gets the job done, but with too much
power. It’s slow, it’s unwieldy, and
tends to magnify the damage when you make a mistake. Please
spread the word far and wide: if you are considering
using
eval then
there is probably a better way.
Think
hard before you use eval.

 

Let
me give you an example of a typical usage.

 

<span
id=”myspan1″></span>

<span
id=”myspan2″></span>

<span
id=”myspan3″></span>

function
setspan(num, text)

{

eval(“myspan”
+ num + “.innerText = ‘” + text + “‘”);

}

 

Somehow
the program is getting its hands on a number, and it wants to map that to a particular
span. What’s wrong with this picture?

 

Well,
pretty much everything. This
is a horrid way to implement these simple semantics.
First
off, what if the text contains an apostrophe? Then
we’ll generate

 

myspan1.innerText
= ‘it ain’t what you do, it’s the way thacha do it’;

Which
isn’t legal JScript. Similarly, what
if it contains stuff interpretable as escape sequences? OK,
let’s fix that up.

 

eval(“myspan”
+ num).innerText = text;

If
you have to use
eval, eval as
little of the expression as possible, and only do it once.
I’ve
seen code like this in real live web sites:

 

if (eval(foo)
!= null && eval(foo).blah == 123)

eval(foo).baz
= “hello”;

 

Yikes! That
calls the compiler three times to compile up the same code! People, eval starts
a compiler
. Before
you use it, ask yourself whether there is a better way to solve this problem than
starting up a compiler!

 

Anyway,
our modified solution is much better but still awful. What
if num is
out of range? What if it isn’t even a
number? We could put in checks, but why
bother? We need to take a step back here
and ask what problem we are trying to solve.

 

We
have a number. We would like to map that
number onto an object. How would you
solve this problem if you didn’t have eval? This
is not a difficult programming problem! Obviously
an array is a far better solution:

 

var spans
= new Array(null, myspan1, myspan2, myspan3);

function
setspan(num, text)

{

if
(spans[num] != null)

spans[num].innertext
= text;

}

 

And
since JScript has string-indexed associative arrays, this generalizes to far more
than just numeric scenarios. Build
any map you want. JScript even provides
a convenient syntax for maps!

 

var spans
= { 1 : mySpan1, 2 : mySpan2, 12 : mySpan12 };

 

Let’s
compare these two solutions on a number of axes:

 

Debugability:
what is easier to debug, a program that dynamically generates new code at runtime,
or a program with a static body of code? What
is easier to debug, a program that uses arrays as arrays, or a program that every
time it needs to map a number to an object it compiles up a small new program?

 

Maintainability:
What’s easier to maintain, a table or a program that dynamically spits new code?

 

Speed:
which do you think is faster, a program that dereferences an array, or a program that
starts a compiler?

 

Memory:
which uses more memory, a program that dereferences an array, or a program that starts
a compiler and compiles a new chunk of code every time you need to access an array?

 

There
is absolutely no reason to use eval to
solve problems like mapping strings or numbers onto objects. Doing
so dramatically lowers the quality of the code on pretty much every imaginable axis.

 

It
gets even worse when you use eval on
the server, but that’s another post.

 

 

Tags JScript Performance Scripting

Comments (29)

Cancel reply

You must be logged in to post a comment.

  1. Dan Shappir says:If I were to rewrite the HTML I would implement it as:No eval and also no lookup table that must be kept in sync with the HTML.Speaking of “new Function”, eval’s sibling so to speak, here is an interesting if somewhat extreme example of its use:The local frames were generated using a custom OSP, feeding data directly into the HTML via binding. The user could filter this view by filling in a search form. The way filtering was done was that the OSP would generate an event, intercepted by a JavaScript event handler. If this handler returned false, the specific record was excluded.Fun times.
  2. Log in to Reply
  3. A big problem was performance – the view could contain hundreds, even thousands of records in extreme cases. Thus, it was imperative that the filtering would be as quick as possible. What I did was generate the JavaScript event handler on the fly based on the user’s input. This way I could construct optimal code for evaluating the specific filter expression.
  4. I was a lead developer for an application that was a mixed thin/fat client – some of the data was maintained locally, thus accessible while offline. The rest of the data was online. The way we did it was that the entire UI was DHTML + JavaScript, with some frames generated locally and the others provided by a web server.
  5. BTW, we do use eval a couple of time in the BeyondJS library, but BeyondJS is not you average JavaScript code. One example where we use it is to construct functions on the fly. The reason we use eval instead of “new Function” is because we need to create the function in the current scope.
  6. function setspan(num, text)
    {
    var span = document.all(“myspan” + num);
    if (span != null)
    span.innertext = text;
    }
  7. November 1, 2003 at 5:21 pm
  8. Bradley says:Another good way to get an element in the DOM is to use:
    document.getElementById(“myspan” + num);Log in to Reply
  9. Another benefit of this method (over eval or document.all) is that if you accidentally insert two (or more) elements with the same ID into the document, getElementById will always return an element (the first one), while eval (or document.all) will return a collection of all the elements with that ID, possibly causing code that expects a single element to fail.
  10. November 1, 2003 at 10:06 pm
  11. Dan Shappir says:getElementById has one significant advantage over document.all – it’s part of the DOM standard endorsed by the W3C, and is thus also supported by Mozilla. On the downside, it not supported by IE4 (not sure if anyone still cares about that version).Log in to Reply
  12. I’m not sure, however, that the fact that it returns the first element in the event of multiple existing elements with the same ID is an advantage. It means that if you accidentally create two elements with the same ID you might not notice and as result not fix the bug.
  13. November 2, 2003 at 4:21 am
  14. Meme Washer says:In the comp.lang.javascript Javascript Best Practices document; I came across an interesting discussion of the reasons for preferring square bracket notation to eval(). The consensus seems to be that eval is evil, and that &quot;if it exists in your page,..
  15. Log in to Reply
  16. June 6, 2006 at 8:35 am
  17. Mike’s Lookout » Blog Archive » Disection of a Spam Comment says:PingBack from http://www.belshe.com/2006/10/25/disection-of-a-spam-comment/
  18. Log in to Reply
  19. October 25, 2006 at 2:19 pm
  20. Steve says:Eval is easy… Hahahahahahah.Also:-Maintainability. Depends on the situtaion. Eval may be better.Memory. Aint a problem.Log in to Reply
  21. I think a lot of of “Gurus” are opposed to anything that makes life easier for us lesser beings.
  22. Speed. If it’s fast enough who cares.
  23. Debugability.   Well if bugs turn up I can always rewrite it the hard way. Also in many cases the eval code may be simpler and more readable.
  24. If  a fly is bugging me and I have a sledgehammer beside me, why go inside for and search for a flyswatter? That might take me half an hour.
  25. November 30, 2006 at 5:35 pm
  26. Alberto says:Steve Rocks!Though, going back to the eval thing, it is true that the eval is bad and that there is a number of workarounds (one of the reasons why i love js!).doing eval(‘obj.’ + methodName) seems a piece of cake. What about obj[methodName]() ? Much better.function ClassFactory(constructorClassName){    eval(‘myObj=new ‘ + constructorClassName +'()’)}Log in to Reply
  27. A class factory on the fly!!!
  28.     return myObj;
  29.     var myObj;
  30. Though there is nothing like:
  31. Workaround A: gotta call a method of an object but i know only the name.
  32. I agree, a religious conception of programming is the whorthest evil there is (bracket should be opened on a new line, etc);
  33. January 10, 2007 at 10:57 pm
  34. How to Use window.onload the Right Way says:PingBack from http://blog.roberthahn.ca/articles/2007/02/02/how-to-use-window-onload-the-right-way
  35. Log in to Reply
  36. February 2, 2007 at 10:01 am
  37. Why Won’t eval() Eval My JSON? (Or: JSON Object !== Object Literal) « The Curious Schemer says:PingBack from http://rayfd.wordpress.com/2007/03/28/why-wont-eval-eval-my-json-or-json-object-object-literal/
  38. Log in to Reply
  39. March 28, 2007 at 2:14 pm
  40. Template-Engine – Seite 3 – PHP @ tutorials.de: Forum, Tutorial, Anleitung, Schulung & Hilfe says:PingBack from http://www.tutorials.de/forum/php/268678-template-engine-3.html#post1415829
  41. Log in to Reply
  42. May 6, 2007 at 4:14 am
  43. Twey says:— QUOTE —function ClassFactory(constructorClassName){    eval(‘myObj=new ‘ + constructorClassName +'()’)}How about:function ClassFactory(constructorClassName) {}(Although the usefulness of this function is debatable, and the names misleading: there are no classes in JScript.)— CODE — eval(‘myobject.’ + propName + ‘ = ‘ “’ + propValue + ‘”’);// versus— END CODE —* I say “almost” — the example scenarios EricLippert gave are perfectly valid reasons to use eval(), and to write a dedicated JS parser for these situations is (usually) silly when eval() is already available.Log in to Reply
  44. P.S. Ugh, I had to switch browsers to post this — no Konq support on a blog that deals with web coding?
  45. Especially note, if we’re discussing getElementById() support, that some older browsers don’t support try/catch, so the only option when given a bad property name or value is to error out if you want to support these browsers.
  46. myobject.someProperty[propName] = propValue;
  47. } catch(e) {}
  48. try {
  49. Almost* everything that can be done with eval() can be done with square bracket notation, and not only is it more efficient, it’s also almost invariably simpler (you don’t have to worry about whether the input will form a valid JS expression, for a start) and produces neater code than eval():
  50. — END CODE —
  51.  return new this[constructorClassName]();
  52. — CODE —
  53. — END QUOTE —
  54.     return myObj;
  55.     var myObj;
  56. Though there is nothing like:
  57. August 14, 2007 at 4:03 am
  58. 5 Things I Hate About Ruby « Devi Web Development says:PingBack from http://deviweb.wordpress.com/2007/09/03/5-things-i-hate-about-ruby/
  59. Log in to Reply
  60. September 3, 2007 at 7:19 am
  61. The best Smarty + Zend View Helpers solution! | CodeUtopia says:PingBack from http://codeutopia.net/blog/2007/11/03/the-best-smarty-zend-view-helpers-solution/
  62. Log in to Reply
  63. November 6, 2007 at 12:52 am
  64. Ajax Girl » Blog Archive » Is using a JS packer a security threat? says:PingBack from http://www.ajaxgirl.com/2008/01/26/is-using-a-js-packer-a-security-threat/
  65. Log in to Reply
  66. January 26, 2008 at 4:32 am
  67. Javascript News » Blog Archive » Is using a JS packer a security threat? says:PingBack from http://www.javascriptnews.com/javascript/is-using-a-js-packer-a-security-threat.html
  68. Log in to Reply
  69. January 26, 2008 at 12:54 pm
  70. The Best Web Design Comics says:PingBack from http://blogsurfer.net/7270/the-best-web-design-comics-13.html
  71. Log in to Reply
  72. January 26, 2008 at 1:04 pm
  73. Is using a JS packer a security threat? says:PingBack from http://blogsurfer.net/7406/is-using-a-js-packer-a-security-threat-2.html
  74. Log in to Reply
  75. January 27, 2008 at 12:33 am
  76. Is using a JS packer a security threat? says:PingBack from http://blogsurfer.net/7518/is-using-a-js-packer-a-security-threat-3.html
  77. Log in to Reply
  78. January 27, 2008 at 9:31 am
  79. Don’t build your Web site in a vacuum says:PingBack from http://blogsurfer.net/7618/dont-build-your-web-site-in-a-vacuum-56.html
  80. Log in to Reply
  81. January 27, 2008 at 5:33 pm
  82. WordPress Admin Theme: Deconstructed says:PingBack from http://blogsurfer.net/7663/wordpress-admin-theme-deconstructed.html
  83. Log in to Reply
  84. January 27, 2008 at 9:10 pm
  85. Is using a JS packer a security threat? says:PingBack from http://blogsurfer.net/7923/is-using-a-js-packer-a-security-threat-4.html
  86. Log in to Reply
  87. January 29, 2008 at 12:32 am
  88. Manipulating innerHTML removes events says:PingBack from http://blogsurfer.net/8079/manipulating-innerhtml-removes-events-70.html
  89. Log in to Reply
  90. January 29, 2008 at 2:02 pm
  91. Web Content: Not just YOUR words and pictures says:PingBack from http://blogsurfer.net/8135/web-content-not-just-your-words-and-pictures-44.html
  92. Log in to Reply
  93. January 29, 2008 at 8:35 pm
  94. Our new addition says:PingBack from http://blogsurfer.net/8500/our-new-addition-39.html
  95. Log in to Reply
  96. January 31, 2008 at 7:03 am
  97. Performance web &raquo; Archive du blog &raquo; JSON ? says:PingBack from http://performance.survol.fr/2008/04/json/
  98. Log in to Reply
  99. April 25, 2008 at 1:17 pm
  100. Ajax performance analysis – Blue Box Sols says:PingBack from http://blueboxsols.com/?p=1813
  101. Log in to Reply
  102. September 10, 2008 at 1:09 pm
  103. Sergio Pereira says:This post is part of a series called JavaScript Demystified . I'm pretty sure by now you have heard
  104. Log in to Reply
  105. March 31, 2009 at 6:27 pm
  106. linkfeedr &raquo; Blog Archive &raquo; JavaScript: Avoid the Evil eval – RSS Indexer (beta) says:PingBack from http://www.linkfeedr.com/development/140126/javascript-avoid-the-evil-eval.html
  107. Log in to Reply
  108. May 22, 2009 at 7:02 pm
  109. mr.tang says:oh,I can’t understand.my english is pool enough
  110. July 13, 2012 at 12:05 am