Microsoft & .NET ASP New JScript .NET Data Types

New JScript .NET Data Types

JScript has a limited set of data types: Number, String, Boolean, and Object. The JScript interpreter
works behind the scenes to coerce, or convert, data stored
in variables into one of its native types using a standard
set of rules (see section nine of the ECMAScript Language
Specification
).
For example, the listing below uses the typeof operator to demonstrate that
one variable can manage several data types (you can view the sample
here)

var a;
a = 5; // typeof(a) returns 'number'
a = "five"; // typeof(a) returns 'string'
a = false; // typeof(a) returns 'boolean'
a = new String("");// typeof(a) returns 'object'

The key benefit the JScript interpreter provides is that is
makes code easier to write since it performs data type
conversions for you. The key drawback is that the JScript
interpreter can end up working against the developer in
situations like the one I demonstrated last week (where the
interpreter seems to unexpectedly change a data type from
one type to another) – here’s the code again:

a = 1;
b = "1";
a += b; // what is the value of a?

If you guessed that the value of a should be two, you’re wrong. Based
on the data type conversion rules in the ECMAScript
standard, JScript evaluates both operands (a and b) and determines that one of them,
b, is a String (based on the value that’s
assigned to b). Since
there’s a String
involved in the operation (+ in this example), JScript
converts a into a String
and concatenates b to
it. The result is that a
is 11 – it’s not new math, the result is the String “11”.

JScript .NET addresses this type of problem in several
ways:

  • JScript .NET introduces many new and useful data types
  • JScript .NET allows you to declare a variable and assign
    a type to it
  • JScript .NET does not perform type conversions for you
    when you work with variables you have previously declared
  • JScript .NET checks for type mismatch errors at compile
    time, making debugging easier
  • JScript .NET enforces data type constraints by throwing
    an exception at run time when you attempt to assign
    inappropriate values to certain data types

This article describes each feature and demonstrates how
you can create your own data types.

Understanding JScript .NET’s new data types

A key element of the .NET Framework is the Common Type
System, a component of the Common Language Runtime (see
Figure 1).





Click here for larger image

Figure 1 – How the Common Type System relates to the
.NET Framework

The Common Type System is a set of data types that are
available to all .NET programming languages, making it easy
to share data across applications written in different
programming languages. JScript .NET makes it easy to use
Common Type System data types by transparently mapping its
native data types to Common Type System data types. Table 1
lists the new JScript .NET data types, what Common Type
System Type each maps to, and a brief description of each
data type.

Table 1 – JScript .NET data types

Data Type CTS Type Description/Range
Boolean System.Boolean Boolean values – true and false.
byte System.Byte 0 to +255
char System.Char 0 to +65 535
decimal System.Decimal -79.2e27 to +79.2e27
double System.Double -1.7e308 to +1.7e308
float System.Single -3.4e38 to +3.4e38
int System.Int32 -2.147e9 to +2.147e9
long System.Int64 -9.223e18 to +9.223e18
sbyte System.Sbyte -128 to +127
short System.Int16 -32 768 to +32 767
String System.String String data type; represents an immutable String – use
the .NET StringBuilder object for mutable
strings
uint System.UInt32 Unsigned integer ranging from 0 to +4e9
ulong System.Uint64 Unsigned long integer ranging from 0 to +18e18
ushort System.UInt16 Unsigned short integer ranging from 0 to +65 535

The next section describes how to declare variables and use
some of the new data types.

Declaring variables along with their data types

JScript .NET uses the familiar var statement to allow developers to
declare variables before using them. Developers already
familiar with JScript or JavaScript should find it easy to
declare variables. Unlike the simple var statement that JScript and
JavaScript support, JScript .NET allows you to define the
variable’s data type as shown in the following listing:

var a : int; // declare an integer variable...
var b : String; // ...a string varible
var c : ushort; // ...and an unsigned short integer

Declare a variable using the var statement, followed by a colon
(:), which is followed by the data type of variable you
want to declare, as shown above.

Understanding automatic type conversions

While JScript .NET encourages developers to declare
variables and assign specific data types to them, JScript
.NET remains backwards compatible with JScript and
JavaScript. For example, you can successfully compile and
run the second snippet of code shown in this article (with
a minor modification), as shown below:

// save this as test01.js
// compile using the command: jsc test01.js
a = 1;
b = "1";
a += b; 
print (a); // prints 11 - the string "11"

If you have trouble compiling the application using jsc, the JScript .NET
compiler, start a Visual Studio .NET Command Prompt and try
again (from the Start menu, select: Start – Programs –
Visual Studio .NET – Visual Studio .NET Tools – Visual
Studio .NET Command Prompt).

What’s happening in the above listing is exactly what
happens when you execute the code in the second snippet in
Internet Explorer or Windows Scripting Host: JScript
converts the value of a
into a String and
concatenates the value of b to it. If you modify the listing
by adding the following statement to the beginning of the
listing, the program will still successfully compile and
run:

var b : String;

The reason it works is that JScript .NET is using the same
rules that JScript and JavaScript use to convert data types
at run time. JScript .NET applies JScript’s and
JavaScript’s type conversion rules only for variables that
you don’t declare or declare a type for. In addition,
you’ll run into problems when you start using language
features like package
and class, since they
require you to declare all variables.

If you declare variable a as an int, the program will not compile.
The JScript .NET compiler will complain about the types
being mismatched (“Type mismatch” error) and will not
produce an executable version of your program. This brings
us to the next benefit of using variables: compile time
checking.

Understanding compile time checking

As I described in the previous article, a compiler produces
two outputs: a list of errors and warnings, and an
executable program. JScript .NET is no different from other
compilers: as it compiles your code, it keeps track of
errors and warnings, and if it encounters any critical
errors it will not produce an executable version of your
code. This feature is useful a variety of scenarios, since
it makes it easy to detect and locate common programming
mistakes like assigning inappropriate values to variables.

Consider the following listing:

var a : sbyte;
a=200;

The code won’t compile because the JScript .NET compiler
knows that an sbyte type
can manage values between -128 and +127, and assigning 200
to it is clearly an error. The JScript .NET compiler is
able to clearly determine the value of a since it does not change in the
above listing (there isn’t any code that changes the value
of a at runtime); as a
result, the compiler generates a “Type mismatch” error and
does not produce an executable version of the code.

Compile time checks can also ensure that you assign types
that are compatible with each other. For example, consider
the following listing:

var a : char; // range is 0 to 65,535
var b : byte; // range is 0 to 255 

a = b; // Ok

This is legal JScript .NET code since the byte data type’s range falls within
the char data type. This
obviously wouldn’t work if you attempt to assign a to b (since the range of a byte is smaller than a char data type).

When the compiler cannot definitively determine the value
of a variable at compile time, the compiler produces an
executable image and relies on runtime checks to detect
errors.

Understanding data type constraints

Consider the following listing:

import System;

var a : sbyte;

try 
{
  a = 100;
  a += 100;
}
catch ( e : Exception) 
{
  print( e.Message );
  // prints: "Exception of type System.OverflowException was thrown"
}

The code declares an sbyte variable, assigns the value
100 to it, and attempts to add 100 to it using the += operator. The above code
successfully compiles since the JScript .NET compiler
cannot establish what the value of a will be unless it
executes the code. Since the compiler’s job is not to
execute code, it creates an executable image, allowing you
to execute the program. The code encapsulates the attempt
to add 100 to a within a
try/catch block since the program must
rely on run time checks to detect assignment errors. When
the code executes, the .NET Class Library throws an
Overflow exception because the result, 200, exceeds the
capacity of the sbyte
data type. The .NET Class Library throws the exception
because the JScript .NET sbyte type transparently maps to the
Common Type System System.Sbyte data type, as shown in Table
1.

The Common Type System enforces data type constraints at
runtime using exceptions. In fact, the.NET Class Library
makes extensive use of exceptions to report errors or
exceptional conditions. As a result, you should become
exception-aware since seemingly simple operations can cause
your applications to unexpectedly terminate. A future
article in this series is dedicated to errors, exceptions
and becoming exception-aware.

Creating your own data types

There are scenarios when isolated variables are too simple
to express your designs. For example, suppose that you’re
creating an application that collects information about
visitors to your site. The information that your site
collects includes a visitor’s first and last name, and
their email address. This information is useful throughout
your application and simple string variables quickly become
awkward. A solution to this problem would be to encapsulate
all of a visitor’s details within an object, making it
easier to manage and easier to add methods that, for
example, validate the user’s email address’s format.

JScript and JavaScript provide some support for creating
your own objects, as shown in the following listing:

function Person()
{
  this.firstName = "";
  this.lastName = "";
  this.email = "";
  this.create=Person_Create;
}

function Person_Create(first,last,emailAddress)
{
  this.firstName=first;
  this.lastName=last;
  this.email=emailAddress;
  this.isValidEmail=Person_isValidEmail;
  Person.prototype.toString=Person_toString;
}
    
function Person_toString()
{
  return this.lastName + ", " + this.firstName + " : " +
             this.email + "nEmail address " + 
    (this.isValidEmail() ? "is" : "is not") +  " valid";
}

var  aPerson;
aPerson = new Person;
aPerson.create("Essam","Ahmed","[email protected]");
alert(aPerson);

The listing defines a Person object and associates a create, isValidEmail (not shown – refer to
the sample code), and toString method with it. This code
appears in a
sample page
, which you can experiment with (use your
borwser’s “view source” feature to review the source code).
The sample page is shown in Figure 2 and the output is in
Figure 3.

Figure 2 – Creating a custom data type using JScript in
Internet Explorer

Figure 3 – Output of custom data type page

While the solution seems to work, it is messy since the
Person object really
doesn’t exist as a first class object. The Person object seems to exist because
it takes advantage of JScript’s late binding features –
there’s no way of binding the Person_Create function to the Person type, nor is there any means
of controlling access to a Person’s variables.

Creating a custom data type using JScript .NET

JScript .NET addresses the above issues by allowing you to
create your own data types using the class keyword. Consider the
following code:

class Person
{
  public var firstName : String;
  public var lastName : String;
  private var emailAddress : String;
  // rest of class follows later in this article...

The listing defines a new person class with three member
variables, just as the HTML page did in the previous
example. The differences here are that each of the
variables is bound to a specific type (String), and two of the three
variables are public
while one is private.
public variables are
just like regular variables – you can directly access and
modify them. A private
variable, in contrast, is not accessible to any code that
resides outside of the class that defines the variable. The
class in this example makes the emailAddress variable private since
it controls access to it through special functions, called
accessors. Accessor functions behave like variables but are
actually functions that reside within a class, allowing
developers a high degree of control over what actions other
code can take on a class’s variables.

The emailAddress
variable is important since its contents must conform to a
specific format; as a result, the class restricts access to
it through functions that validate the format of the
variable’s content, as shown in the following listing:

// This function verifies the format of the email
// address on assignment
function set eMail(theAddress:String)
{
  emailAddress=theAddress;
  if(!this.isEmailValid)
    throw(new Exception("Invalid Email address format"));
}
   
// This function does not attempt to verify
// the format of the email address since it 
// simply returns the current value
function get eMail() : String 
{
  return emailAddress;
}

// This is a read-only class property (since
// only the get function has been defined) that
// returns true if the current email address is
// valid. This function is used in one of  the class's
// constructors and in the set eMail function.
function get isEmailValid() : Boolean
{
  var emailReg = "^[w-_.]*[w-_.]@[w].+[w]+[w]$";
  var regex = new RegExp(emailReg);

  if (!regex.test(this.emailAddress)) 
  {
    emailAddress="";
    return false;
  
  }
  return true;
}

The listing demonstrates three accessor functions: set and
get eMail and get isEmailValid. The comments in
the listing provide details on the role of each function.
The class verifies the email address’s format using a
regular expression that returns true for email addresses like
[email protected], and [email protected]

The class makes it easy to create new Person objects since it has two
constructors. A constructor is analogous to the Person_Create function in the previous
example: a constructor usually sets a class’s initial
state. The Person class has two constructors: a default
constructor that initializes the class to an empty state,
and a constructor that allows developers to create a Person initialized with a
first and last name, and email address. The listing that
follows demonstrates how to create both types of
constructors:

// Default constructor
function Person()
{
  firstName=new String("");
  lastName=new String("");
  emailAddress=new String("");
}

// Constructor that initializes the Person based on
// names and email address
function Person(fName:String,lName:String,eMail:String)
{
  firstName=new String(fName);
  lastName=new String(lName);
  emailAddress=new String();
  emailAddress=eMail;
}

The sample Windows Forms application demonstrates how to
use the Person class. A
form similar to the one shown in Figure 4 appears when you
start the application; the form looks very similar to the
one in Figure 2.

Figure 4 – Windows Forms application that demonstrates
how to use custom data types in JScript .NET

When you click on the Ok button, the application creates a
new instance of the Person class using the following
code:

var aPerson : Person;
aPerson = new Person(firstName.Text,lastName.Text,emailAddress.Text);

Each parameter that the Person constructor receives is based
on the values that appear in the form – the Text property of each is similar to
the HTML input element’s
value property.

The class allows developers to check the validity of the
email address through the isEmailValid property (the get isEmailValid accessor
function). There are cases when it is more appropriate to
check the validity of the email address when the Person
object initializes, as opposed to requiring that developers
check the value of a class’s property. The sample code also
demonstrates how to validate the email address in the
Person class constructor – the constructor reports an
invalid email address using an exception. Although it is
possible to throw exceptions from a constructor, it is
generally not a good practice to follow and I provide it
here for demonstration only. Use the directions that follow
at the end of this section to build compile the application
to report email validation exceptions when the Person object is created.

Regardless of what the state of the email address is, if
you’re using the application’s default build, the
application pops up a message box that echoes the values in
the fields and an assessment of the email address’s
validity, as shown in Figure 5.

Figure 5 – Output of the sample Windows Forms
application

The advantages that a JScript .NET class provides over a
JScript object are many. The include:

  • The ability to specify what code can access member
    variables and functions through the public, protected,
    and private keywords
  • The ability to directly associate member functions with a
    specific, user-defined data type
  • A high degree of control over what other code can do with
    your class and its members
  • A high degree of encapsulation, offering the potential
    for better reuse across applications, potentially
    reducing the effort you spend on creating new
    applications.

Directions for downloading and building the sample
application

These directions assume that the systems you use these
directions on have version Beta 2 of the .NET Framework
installed.

  1. Download the sample using

    this link
  2. Extract the contents of the ZIP file into a new folder
  3. Start a Visual Studio .NET Command Prompt as described
    earlier in this article and type the command buildPerson to compile the sample
    code. If the sample compiles successfully, you’ll see a
    form on the screen that asks you to fill in a name and
    email address. If the sample does not compile
    successfully ensure that you can execute jsc, the JScript .NET compiler,
    from the command prompt.

Compile the alternate version of the application, described
in the article, using the command:

buildPerson alt

When you run the application, change the value of the email
address field to an invalid email address format and click
on the Ok button. You should see an error about the email
address being invalid – refer to the sample code for
details.

Note that there seems to be a bug in the version of the
.NET Framework I have installed on my system that
inconsistently reports an email address as valid when it is
actually not valid. If this happens on your system, change
the value of the email address field and try again – it
usually works after one or two tries (even if you remove a
single character each try).

Summary

This article described the new JScript .NET data types, how
they map to Common Type System data types, and how to use
data types to perform compile time and run time checks to
assist in your debugging efforts and improve the quality of
your code. This article also demonstrated how to create
your own data types using JScript .NET in the context of
comparing the process with JScript. The next article in
this series goes into more detail about the class statement in addition to the
const, enum, package and import statements.

Essam Ahmed is the author of “JScript .NET Programming”
(ISBN 0764548689, Published by Hungry Minds September
2001), many articles (including some at CodeGuru.com) and book reviews
(also available at CodeGuru.com). Contact Essam at
[email protected],
or at his Web site

# # #

Latest Posts

Related Stories