Wednesday, May 28, 2008

ASP.NET AJAX Client Library: Combining createDelegate and createCallback

When working with the ASP.NET AJAX client library, I find that I occasionally need to use both Function.createDelegate() and Function.createCallback() simultaneously.

Each time you use one or the other of these methods, the library places a "call wrapper" around your function.  Then, when the new delegate (or callback) is called, there are actually two calls being made: the first to the wrapper, and the second when the wrapper calls your function.

By combining the use of both methods, you're now placing two call wrappers around your function, which is fairly inefficient, not to mention that it's not exactly elegant or readable.

Why would you want to combine the two methods?

You'd want to combine them when you want to ensure that this refers to a specific object, and you also want to pass specific arguments ("context") to the function.

For example, let's start with two objects, each containing an array of messages (strings).   We also have a function that expects that this will refer to one of the objects, and it will expect to receive the index of the message to display as an argument.

(This is a very contrived example, but it shows the requirement and solution in simple terms.  Real-world situations that require the use of both createDelegate and createCallback are more complex.)

var myObject1 = {
    messages: ["Red", "Blue", "Black"]
};

var myObject2 = {
    messages: ["Audi", "Chevy", "Mitsubishi"]
};

function showAlert(index) {
    alert(this.messages[index]);
};

Now, I'll create two delegates/callbacks: one will call showAlert() and display a color, and the other will call showAlert() and display a car type.  I'll do this by combining the use of createDelegate and createCallback.

var showColor = Function.createDelegate(myObject1, Function.createCallback(showAlert, 2));

var showCar = Function.createDelegate(myObject2, Function.createCallback(showAlert, 1));

If we were to call showColor(), the user would see the word "Black" appear in a alert window.  Likewise, if we were to call showCar(), the user would see the word "Chevy" appear in a alert window. 

The significance of what took place here is that both showColor and showCar can be passed as simple function references to an event or method, and they retain not only the calling object context that we desired (this), but also the argument(s) that we needed to pass (the "context").  It allows us to use one single function (showAlert) to satisfy the display requirements of both objects (myObject1 and myObject2).

The problem with the showColor and showCar methods, as written above, is that they are inefficient because they make a total of three calls each time one is called (two wrapper calls plus the actual function call), and looking at the code, it can be difficult to understand what it is doing (i.e., the code lacks readability).

To solve both issues, I have created a new method called Function.createDelegateCallback().

In one step, we can specify a this reference, the function to wrap/call, and arguments ("context") to pass to the function.

The simplest way of creating the new method would have been to create a method that calls Function.createDelegate(this, Function.createCallback(func, args)), which would solve the readability issue, but would do nothing to solve the inefficiency issue.

Instead, I started with the source code for createCallback, and modified it to include the createDelegate functionality, making sure that only one wrapper call would be placed around the function.

Note: the new createDelegateCallback method is added directly to the JavaScript Function object, just like createDelegate and createCallback are today, so it is utilized in exactly the same way.

Update: After some additional testing, I have slightly modified the code below.  I am not sure as to the reasons for Microsoft coding the for loop they way they did in createCallback, but I accepted at face value that it was the best way.  I now believe it is better below, and my testing bears that out.  There is certainly a reason they coded it the way they did; I just can't figure it out.

Additional note: If you want to pass more than one argument to the target function, simply include them after the context argument.

Function.createDelegateCallback = function (instance, method, context) {
    /// <param name="instance" mayBeNull="true"></param>
    /// <param name="method" type="Function"></param>
    /// <param name="context" mayBeNull="true"></param>
    /// <returns type="Function"></returns>

    return function() {
        var l = arguments.length;

        if (l > 3) {
            var args = [];

            for (var i=2; i<l; i++) {
                args[i-2] = arguments[i];
            } 

            return method.apply(instance, args);
        }

        return method.call(instance, context);
    };
};

Now that we have the new createDelegateCallback method, we can re-write the methods above to make them more efficient and readable:

var showColor = Function.createDelegateCallback(myObject1, showAlert, 2);

var showCar = Function.createDelegateCallback(myObject2, showAlert, 1);

createDelegateCallback is not something you'll use every day, but if you do a lot of client-side coding with the ASP.NET AJAX client library, you will be glad someday that you have it.

Friday, April 04, 2008

Smart String Concatenation

Whether on a individual computer or a server attached to the Internet someplace, people are always looking for better performance of their software.

The first thought that comes to mind is often adding memory or a faster processor, or choosing a faster operating system or web browser.

But many times (perhaps most times) the real culprit for slow performance is the programmer who wrote the software.

As a programmer, my philosophy is that I personally take responsibility for the performance of my programs, rather than require faster hardware or environment.  I have found that by forcing myself to think about the efficiency of every piece of code I write, the combined performance savings across an entire application is immense.

Think about it: if you save just a quarter of a second of time serving one page view, you have actually saved about 70 hours of processor time after a million page views.  And for a site like Lottery Post that gets many millions of page views a month... well, you can do the math.

With that concept in mind, I'd like to offer some tips about string concatenation that will make your programs more efficient.

String concatenation — the processing of combining strings together — is something that is still slow on many popular platforms.  For example, on all versions of Internet Explorer (up until IE8 is released), combining strings is very inefficient.  Even in the .NET framework, there are some ways of programming that will result in poor performance.

String Concatenation in .NET

In the .NET framework, whether you're programming in C# or VB, the best way to combine strings is using the String.Concat() method.  However, just using String.Concat() is not enough, and here's where the extra efficiency comes into play:

Make sure that all the arguments passed to String.Concat() are strong-typed Strings.  Otherwise, an overloaded version of the String.Concat() will be used that accepts all Object arguments, and each value you pass will be boxed to an Object (when passed) and un-boxed from an Object (when concatenated by the method).

When you test the program, it works just fine either way, but if you are using the Object argument version of the String.Concat() method, you are silently leaking performance.

For example, if you want to create a string like "There are 27 pages", the second version shown below is more efficient:

myString = String.Concat("There are ", intPages, " pages")

myString = String.Concat("There are ", intPages.ToString(), " pages")

(Note:  I did not use CStr(intPages), I used intPages.ToString().  That's because the CStr() VB function accepts an Object type, which will require boxing/unboxing, whereas I believe an Integer can execute its ToString() method quicker.)

In the first example, all three arguments are treated as Object types, but in the second example, all three arguments are String types, so the compiler chooses the quicker all-String-arguments version of the String.Concat() method.

Why not use VB's string concatenation operator ("&")?  Because when you compile your application, the compiler breaks everything down into String.Concat() operations anyway, and you can do a much better job of that than the compiler could.  If you ever took a look at some of the code that gets generated for combining strings, you would be amazed at what is actually taking place under the covers.

And by all means, do not using String.Format() for your string concatenation, unless you are actually using the formatting capabilities of the method (i.e., transforming data into another format).  Even though it can produce slightly more readable code, String.Format() has lots of overhead that makes it a poor choice.

Programming efficiency

Sometimes if you think about the way the computer is executing the code, rather than how your mind is assembling the string, you can come up with some nice efficiencies.

For example, let's say you're creating the name of an image file based on the value of a couple different variables.

With the variable names shown in <brackets>, the file name will be "icon_<isCircle>_<size>_.<isGif>", where <isCircle> is a boolean (True for "circle", False or "square"), <size> is any integer (such as 16, for a 16 x 16 image), and <isGif> is a boolean (True for "gif", False for "jpg").

Here is how someone would normally code this (using the tips above for String.Concat):

myImage = String.Concat("icon_", If(isCircle, "circle", "square"), "_", size.ToString(), "_.", If(isGif, "gif", "jpg"))

or, in C#, the same thing would be:

myImage = String.Concat("icon_", isCircle? "circle" : "square", "_", size.ToString(), "_.", isGif? "gif" : "jpg");

It will indeed work fine, and for top efficiency it uses the all-String version of the String.Concat() method, but why should you force the computer to combine 6 different strings together, when you can do the same thing by combining only 3 strings together?

The following is functionally equivalent to the first solution, but takes half the work to do:

myImage = String.Concat(If(isCircle, "icon_circle_", "icon_square_"), size.ToString(), If(isGif, "_.gif", "_.jpg"))

or, in C#:

myImage = String.Concat(isCircle? "icon_circle_" : "icon_square_", size.ToString(), isGif? "_.gif" : "_.jpg");

If you were to go through your program code, how many times would you see something similar to the first solution, as opposed to the second?  Probably a lot.

JavaScript coding

The same exact approach applies to JavaScript — especially to JavaScript.

As I mentioned earlier, JavaScript is very slow performing string concatenation on IE web browsers, and IE makes up the majority of web browsers in use today.  That's a lot of potential for slow code.

Therefore, when writing JavaScript programs be careful anywhere you combine strings, especially when it's done inside a loop.

The reason behind the slow performance is that each time strings are concatenated, a new copy of  the string is created in memory, which requires allocating new memory, copying the contents of the old strings, and then releasing the memory from the old strings.

When doing a lot of string concatenation in JavaScript, it is often much better to create an array of string values, and then use an Array.join() method to combine them.  Each time a new element is added to an array, you're allocating memory for the new element, but you're not copying the old string value, and you're not releasing memory for the old string.

Here is an example comparing regular string concatenation with array-based concatenation.  The example is to create a string containing a comma-separated list of numbers 1 through 100.  The second method is much faster than the first.

Method 1: regular string concatenation

var str = "";

for (var i=1; i<=100; i++) {
    str += (i + ",");
}

Method 2: combine array elements

var a = [];

for (var i=1; i<=100; i++) {
    a[i-1] = i;
}

var str = a.join(",");

Lots of other efficiencies

There are lots and lots of other things that can be done to increase performance of strings and string concatenation.  This only scratches the surface.

Hopefully what this does is to show the types of things that you can think about when you're looking to increase the efficiency and performance of your programs.

I wouldn't go crazy doing things that make your code impossible to read, but at the same time don't be afraid to do things that save only a tiny bit of time.  As you implement lots and lots of small tweaks, eventually they will combine into a much bigger overall savings.

Monday, March 03, 2008

Three cheers for Microsoft! The web is about to improve big-time

I am so happy to report that Microsoft made an announcement this morning that its upcoming IE8 web browser will support all current web browser standards as the default browser behavior!

While I knew that IE8 was going to support the current set of web standards, Microsoft's plan to-date was to require web sites to add a special indicator to their HTML code that would "turn on" this support.

The result of that previous plan would have been a confusing mess of web sites, with many inexperienced web developers wondering why their sites did not render properly.

Also, it would have continued the practice of making old, outdated web browser standards the default experience, and once again the onus would be placed on users to figure out which browser to use for what site. 

This is going to be an exciting time for web developers, as they will finally be freed of the shackles imposed by IE6 and IE7 — as soon as enough people have migrated to IE8.

I've done some development work recently for the Safari 3.0 web browser, which currently supports many of the upcoming IE8 features, and it is just so incredibly liberating to use the new standards.

Features like rounded borders, multiple background images per object, CSS selectors based on attribute values, multi-column layouts, and much, much more.

The trick is going to be getting a critical mass of people upgraded to IE8 as quickly as possible.  Based on the adoption rate of IE7, that will be no easy task.  It was only within the past few months that I've noticed more people using IE7 than IE6.  Hopefully there will be a compelling reason to upgrade (for users, that is).

Here is a link to Microsoft's announcement:

http://www.microsoft.com/presspass/press/2008/mar08/03-03WebStandards.mspx

Friday, February 15, 2008

Applying Vista SP1 caused VS 2008 compiles to fail (includes fix)

Being a Microsoft Developer Network subscriber, yesterday I was able to get my hands on the new Vista Service Pack 1 (SP1), which includes hoards of fixes and performance tweaks.

The install went well, but is slow.  It probably took an hour to install, but that was only after an hour to uninstall the SP1 Release Candidate that I had previously installed.

The biggest pain was having to tell my virus protection software that every file that changed on my PC was OK.  I wish there was an easy way to do that globally.

Anyway, the only anomaly I discovered was that Visual Studio 2008 started coming up with compile errors after applying SP1.  It indicated a problem in the web.config file, on these specific lines:

<compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.VisualBasic.VBCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" warningLevel="4">
    <
providerOption name="CompilerVersion" value="v3.5"/>
    <
providerOption name="OptionInfer" value="true"/>
    <
providerOption name="WarnAsError" value="false"/>
</compiler>

The error message stated that the tag could not have nested child tags.  The catch-22 is that removing the child tags would remove all support for .NET 3.0 and 3.5 functionality, so that was not the solution.

This really had me stumped for quite a while, until I discovered this post:

http://forums.asp.net/t/1186941.aspx

I ran the two patches indicated in the post (rebooting after installing the first one), and that solved the problem.  What's going on Microsoft?  This is really strange.  I have no idea what those patches install, but they did the trick.

As far as SP1 is concerned, if you installed the Release Candidate, you already have a good idea of the performance improvements and increased stability you'll get.  The best part was getting rid of the annoying "Evaluation Copy" watermark on the screen.

Props to Microsoft for getting SP1 into its MSDN subscribers' hands before they said they would, but hopefully you've learned your lesson never to roll out a service pack like that again.  Treat your MSDN subscribers like first class citizens!

Monday, January 14, 2008

ASP.NET AJAX: Half-way between createDelegate() and createCallback()

I stumbled on a use of Function.createDelegate() method today that seems to be a cross between Function.createDelegate() and Function.createCallback().

I had the need to pass a context to a handler function, with the context being a JSON object containing the state of a few variables.  I tried using createCallback(), which is designed for that purpose, but it did not seem to work well because I was not using it together with a DOM event — just with an internal function call.

So I turned to createDelegate(), using the JSON object as the this argument, and it worked quite nicely.

An example of this syntax is as follows.  The code assigns a function to the variable fn that (when called) displays an alert box containing the element number and id of a DIV with an ID of "ThisOne".  There are certainly more useful uses for this method, but it should provide a clear example of how it works.  The key point here is the function() assignment that uses this to utilize the values passed in the delegate.

var a = document.getElementsByTagName("div");
var fn;

for (var x=0; x < a.length; x++) {
    if (a[x].id == "ThisOne") {
        fn = Function.createDelegate({
            e: a[x],
            num: x
        }, function () {
            alert("DIV #"+this.num+": "+this.e.id);
        });
    }
}

fn();

If you're not sure about the value of the above code, ask yourself, "How would I code the same thing without the createDelegate()?"  Also ask yourself how hard it would be to pass the DOM element itself to your function, as I have done with createDelegate().

Would you use the Function() constructor that allows you to create a dynamic function from a string value?  (Bad idea.)

Would you use global variables?  (Bad idea.)

If your answer is that you'd use apply(), then you're doing the same thing that createDelegate() does internally.  If you didn't think of that before you read this, then you can't claim credit for thinking of it.  ;-)

Wednesday, January 02, 2008

ChangeAll extension method alters every item in an iCollection(Of T)

My favorite feature of the new .NET 3.5 framework is extension methods.  Ever since I heard they would be available in this version of the .NET framework I have been designing functions in a way that they could be easily converted to extension methods.

For the unenlightened, extension methods are a new feature of the .NET 3.5 framework that allows you to extend any class — whether it is a built-in class, a third-party class, or your own class.

When you create an extension method, you can call the new method as if it were a native method of the class.

As an easy-to-understand example, I created an extension of the .NET String class called SuperTrim().  The method works like the built-in Trim() method, but instead of just trimming spaces from the front and back of a string, it trims any kind of control characters (any character with an ASCII code of less than 32, plus a few others).

After creating the extension method, I can apply SuperTrim() to an string in exactly the same way I would apply a regular Trim():

newString = oldString.SuperTrim()

Now that's cool! 

Last week I came upon a scenario in a program where I had to manipulate all of the items in a collection, so I tried using the built-in ForEach() method.  The trouble is that ForEach() is designed to do something with all the items in a collection, but not to change all of the items in a collection.

ForEach() passes each item, one by one, to your specified function, but it explicitly only passes the item by value, not by reference.  If your function changes the value passed, it is not changed in the collection — only within the scope of your function.

ForEach() also does not pass an index number or any other value that could help determine which item in the collection to change, so any attempt to use ForEach() to change items in the original collection would be a messy affair.

In response, I created an extension to iCollection called ChangeAll().  You pass a function to ChangeAll() that will receive each item, one by one, and the return value from your function will become the new value of that item in the collection.

Incidentally, ChangeAll() works great with the new lambda expressions — another wonderful .NET 3.5 feature!

Here is a sample usage of ChangeAll(), which trims all items in a collection (using a lambda expression):

myColl.ChangeAll(Function(value As String) Trim(value))

Pretty nice, eh?

If you don't want to use a lambda, you can just as easily use a regular function, like this:

Function TrimIt(ByVal value As String) As String
    Return Trim(value)
End Function

myCollection.ChangeAll(AddressOf TrimIt) 

There are lots of other uses, besides trimming every item in the collection.  The point is that now it is very easy to change each item of a collection, in a way that is simple and easy to read/understand — thanks to the new extension methods.

When creating ChangeAll() I first tried extending iEnumerable(Of T), but found that the base class does not have sufficient functionality to do what I needed.  So I then extended iCollection(Of T) instead, which can do some basic manipulation of the collection's items.

So without further adieu, here is the code, in its entirety.  This is the entire contents of a file I call "ColectionExtensions.vb" (you can give the file any name).  It includes inline documentation (yay!).

Option Explicit On
Option Strict On

Imports
System.Runtime.CompilerServices

Public Module CollectionExtensions

  ''' <summary>
  ''' Executes a transformation function on each item in
  ''' an ICollection(T) generic collection, replacing
  ''' each item with the return value.
  ''' </summary>
  ''' <typeparam name="T">
  ''' The type contained in Collection and that is passed
  ''' to ChangeFunction, as well as the type that must be
  ''' returned from ChangeFunction.
  ''' </typeparam>
  ''' <param name="Collection">
  ''' The collection on which ChangeFunction will be
  ''' applied to each item.
  ''' </param>
  ''' <param name="ChangeFunction">
  ''' Each item in Collection will be passed to this
  ''' function, and the return value will replace the
  ''' original item in the collection. If you wish an
  ''' item to remain unchanged, this function must
  ''' return the item's original value.
  ''' </param>
  ''' <returns>
  ''' Returns the collection, so this method may be
  ''' daisy-chained.
  ''' </returns>
  <Extension()> _
  Public Function ChangeAll(Of T)( _
    ByVal Collection As ICollection(Of T), _
    ByVal ChangeFunction As Func(Of T, T)) _
  As ICollection(Of T)

    If (Not Collection.IsReadOnly) Then
      Dim newCollection(Collection.Count - 1) As T

      Collection.CopyTo(newCollection, 0)
      Collection.Clear()

      For Each item As T In newCollection
        Collection.Add(ChangeFunction(item))
      Next

    End If

    Return Collection
  End Function

End Module

Obviously, all of the above is written in VB, but exactly the same functionality can be created in C# with a few tweaks in syntax.

I hope that this extension can be useful to you, but more importantly, that it can demonstrate the usefulness of the technique, so that you can similarly extend classes in your applications.

Sunday, December 16, 2007

IE7 has now overtaken IE6

I am happy to be able to report the news that is the subject of this blog entry:  that IE7 has now apparently overtaken IE6 for browser share.

I base this information on the Active Users page here at Lottery Post, in addition to regular web site log analysis.

Over the past several weeks I have monitored consistent statistics showing at least 25% more IE7 users than IE6 users.  (Looking further down the chain, the IE5 user population is so small at this point that it's a mere blip, and certainly not worthy of breaking one's back to support.)

The Lottery Post user community is an excellent one to use in gaging browser penetration, because it is first-most a very large user population, but perhaps even more importantly, it is made up of mainly non-technical people.  (If technical people made up a large percentage of the Lottery Post site visits there would be completely unrealistic browser statistics, with a high percentage of Firefox users and much fewer IE6 users.)

The migration from IE6 to IE7 is a tremendous benefit to everyone, because that means more and more people are seeing pages as they are meant to be seen, and web site designers are inching closer to the day when they no longer have to jump through hoops to have every web user share the same experience.

An example of this can be seen on the (admittedly cool) Sudoku page I completed and implemented this week.  IE6 users can play the game, just like anyone else, but they are missing some cool button roll-over effects because their web browser is simply incapable of drawing PNG semi-transparent images together with CSS sprite techniques that are used for the roll-overs.

In fact, it was hard enough just to get IE6 to draw the PNG images with no roll-over effect!  To support the image format I had to use conditional comment tags and a special style sheet that would only be read by IE6.

The kind of limitations imposed on web developers by needing to support old browsers like IE6 not only is a waste of time for people like me, but also limits the amount of creativity I can employ, and reduces the number of cool, friendly features that I can implement.

Thus, I look at the shrinking IE6 population with hope and excitement.

Some of the surge in IE7 usage may be due to Windows Vista making some inroads.  (IE7 is the default web browser in Vista.)  I have been noticing a consistent figure of about 15% of the Lottery Post site vistors using Vista.

Like the migration from IE6 to IE7, the migration to Vista also represents a positive step for web designers, as they can count on each Vista user having excellent support for recent and emerging technologies, like Flash, fonts, graphics (like PNG graphics), etc. — as well as generally better hardware, such as monitor resolution. 

The ability to produce wider pages (again like the Sudoku example, as well as pages like the Lottery Results Gadget Guide) is liberating for web designers, and better for users.

In fact, although I refer to web designers in each case as being the beneficiary of user upgrades, it is fact the users that ultimately benefit the most.

Many IE6 users have not upgraded to IE7 yet because they don't see the benefit, don't know it's free and/or easy, or because they simply don't know about it.

Do you fall into that category?  Go into the Tools menu of your web browser and select Windows Update.

Follow the options and prompts to set up the Windows Update, if you are so prompted, and then follow the prompts to upgrade to IE7.

You and I both will be happy you did.