Showing posts with label example code. Show all posts
Showing posts with label example code. Show all posts

Tuesday, May 10, 2011

Simple javascript optimizations

Let us see some of the most simple javascript scripts optimizations which can make big difference,

Rule: Consider using local variable instead of global variable.

Rule: Avoid using eval() or function constructor.

Rule: Pass function, not string to setTimeout() and setInterval(). Passing stirng is same as calling eval().

Rule: Avoid using with().

For-in loop vs for loop

Slow:
function forinloop()
{
    var count=10000;
    var arr=new Array();
    for(var i=0;i<count;i++)
    {
        arr[i]=i;
    }
    var value=0;
    for(var index in arr)
    {
        value+=arr[index];
    }
}
Faster:
function forloop()
{
    var count=10000;
    var arr=new Array();
    for(var i=0;i<count;i++)
    {
        arr[i]=i;
    }
    var value=0;
    count= arr.length;
    for(var index=0;index<count;index++)
    {
        value+=arr[index];
    }
}

Rule: Avoid using for-in loop, instead use for() loop.

String concatenation vs array join

Slow:

function stringcat()
{
    var count=10000;
    var str="";
    for(var i=0;i<count;i++)
    {
        str+="first,";
    }
}
Faster:
function arrayjoin()
{
    var count=10000;
    var arr=new Array();
    for(var i=0;i<count;i++)
    {
        arr[i]="first";
    }
    var str=arr.join("");
}

Rule: Avoid string concatenation and use array join. The performance difference in significant only in IE 7.

Inbuilt functions vs primitive operations

Slow:

function mathmin()
{
    var count=10000;    
    for(var i=0;i<count;i++)
    {
        var a=10;
        var b=5;
        var min = Math.min(a, b);
    }
}
Faster:
function primitiveop()
{
    var count=10000;    
    for(var i=0;i<count;i++)
    {
        var a=10;
        var b=5;
        var min = a < b ? a : b;
    }
}

Rule: Avoid function calls, try to use primitive operations. The performance difference in significant only in IE 7.

External function vs inline function

Slow:

function minfunction(a,b)
{
    var min = a < b ? a : b;
    return min;
}
function externalfunction()
{
    var count=10000;
    for(var i=0;i<count;i++)
    {
        var a=10;
        var b=5;
        var min=minfunction(a,b);
    }
}
Faster:
function inlinefunction()
{
    var count=10000;
    for(var i=0;i<count;i++)
    {
        var a=10;
        var b=5;
        var min = a < b ? a : b;
    }
}

Rule: Avoid external function calls, try to use inline functions. The performance difference in significant only in IE 7.

Comments in the script

Slow:
function withcomments()
{
    var count=50000;    
    for(var i=0;i<count;i++)
    {
        /* dummy comments */
        /* dummy comments */
        var a=10;
        /* dummy comments */
        /* dummy comments */
        var b=5;
        /* dummy comments */
        /* dummy comments */
        var min = a < b ? a : b;
        /* dummy comments */
    }
}
Faster:
function withoutcomments()
{
    var count=50000;
    for(var i=0;i<count;i++)
    {
        var a=10;
        var b=5;
        var min = a < b ? a : b;
    }
}

Rule: Avoid comments in performance critical script. The performance difference in significant only in IE 7.

Try catch in performance critical functions

Slow:
function withtrycatch()
{
    var count=50000;
    for(var i=0;i<count;i++)
    {
        try
        {
            var num=parseInt("10");
        }
        catch(e)
        {
            //handle exception
        }
        finally
        {

        }
    }
}
Faster:
function withouttrycatch()
{
    var count=50000;
    for(var i=0;i<count;i++)
    {
       var num=parseInt("10");
    }
}

Rule: Avoid using try catch inside performance critical function.

Saturday, September 18, 2010

Simple javascript DHTML optimizations

Let us see some of the most simple javascript scripts optimizations with respect to DHTML which can make big difference,

Caching the DOM element

DIV1 element
DIV2 element
DIV3 element
Slow:
function nodomcache()
{
    var count=1000;
    for(var i=0;i<count;i++)
    {
        var value1=document.getElementById("div1").innerHTML;
        var value2=document.getElementById("div2").innerHTML;
        var value3=document.getElementById("div3").innerHTML;
    }
}
Faster:
function domcache()
{
    var count=1000;
    var ele1=document.getElementById("div1");
    var ele2=document.getElementById("div2");
    var ele3=document.getElementById("div3");
    for(var i=0;i<count;i++)
    {
        var value1=ele1.innerHTML;
        var value2=ele2.innerHTML;
        var value3=ele3.innerHTML;
    }
}

Rule: Cache the element for better performance. This caching is applicable for all types or variables.

Creating dynamic HTML (appendChild vs innerHTML)

Slow:
function appendchildhtml()
{
    var count=100;
    var tblele=document.createElement("table");
    var tblbodyele=document.createElement("tbody");
    for(var i=0;i<count;i++)
    {
        var trele= document.createElement("tr");
        var tdele1= document.createElement("td");
        tdele1.appendChild(document.createTextNode(i))
        trele.appendChild(tdele1);
        var tdele2= document.createElement("td");
        tdele2.appendChild(document.createTextNode(i))
        trele.appendChild(tdele2);
        tblbodyele.appendChild(trele);

    }
    tblele.appendChild(tblbodyele);
    document.getElementById("result1").appendChild(tblele);
}
Faster:
function innerhtml()
{
    var count=100;
    var strHTML="";
    strHTML+="<table>";
    for(var i=0;i<count;i++)
    {
        strHTML+="<tr>";
        strHTML+="<td>";
        strHTML+=i;
        strHTML+="</td>";
        strHTML+="<td>";
        strHTML+=i;
        strHTML+="</td>";
        strHTML+="</tr>";

    }
    strHTML+="</table>";
    document.getElementById("result2").innerHTML=strHTML;
}

Rule: Use innerHTML for dynamically adding html content.

Friday, September 17, 2010

Javascript measurement tools

There are two important factor which has to be measured to identify the improvement in the code
  • Time taken to complete some operation
  • Memory usage of the application
Below is the example code for measuring the time.
<html>
    <head>
        <title>Time measurement tool</title>
        <script>
        function measureTimeElapsed()
        {
            var divlogoutput;
            var starttime;
            var endtime;
            var timeelapsed;
            starttime=(new Date()).getTime();
            for(var i=0;i<10000;i++)
            {
                var temp=parseInt("10");
            }
            endtime=(new Date()).getTime();
            timeelapsed=endtime-starttime;
            divlogoutput=document.getElementById("logoutput");
            //append the timeelapsed
            divlogoutput.innerHTML="<b>TimeElapsed:"+
                timeelapsed+"(milliseconds)</b><br/>";
        }
        </script>
    </head>
    <body onload="measureTimeElapsed()">
        <div id="logoutput">
        </div>
    </body>
</html>
Output:
Chrome 6.0:TimeElapsed:1(milliseconds)
Safari 3.2:TimeElapsed:10(milliseconds)
IE 7.0:TimeElapsed:27(milliseconds)
Mozilla Firefox:3.0.3:1(milliseconds)

Note: Profiling tools can be used for the measuring execution time and memory leak.

Note: If you are testing with Google Chrome or Mozilla Firefox then try console.time(name); and console.timeEnd(name);. Please refer Console API

Thursday, September 16, 2010

C# XmlWriter vs XmlDocument vs StreamWriter

Use XmlWriter for creating xml document.The below example uses the following classes
  • Contact class is used for storing name and address
  • AddressBook is the colleciton of Contact class
The c# code example in this article will generate xml document as below, but with 10000 contacts elements.
<AddressBook>
  <Contact>
    <Name>Person1</Name>
    <Address1><![CDATA[Number101]]></Address1>
    <Address2><![CDATA[Address501]]></Address2>
    <Zip>50001</Zip>
    <Phone><![CDATA[999991]]></Phone>
 </Contact>
</AddressBook>
The example first creates and populates an AddressBook class with 10000 Contact objects and measures time taken to generate the xml file with 10000 contacts using using XmlDocument, XmlWriter and StreamWriter (usign StringBuilder).
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using System.Diagnostics;
using System.Xml.Linq;
namespace XmlWrite
{
    class Contact
    {
        public string Name { get; set; }
        public string Address1 { get; set; }
        public string Address2 { get; set; }
        public int Zip { get; set; }
        public string Phone { get; set; }
        public Contact(string strName, string strAddress1, string strAddress2,
            int iZip,
            string strPhone)
        {
            Name = strName;
            Address1 = strAddress1;
            Address2 = strAddress2;
            Zip = iZip;
            Phone = strPhone;
        }
    }
    class AddressBook
    {
        private List<Contact> InnerList = null;
        public List<Contact> GetContacts()
        {
            return InnerList;
        }
        public AddressBook()
        {
            InnerList = new List<Contact>();
        }
        public void Add(Contact objContact)
        {
            InnerList.Add(objContact);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch objSW = null;
            XmlDocument objXmlDoc = null;
            XmlWriter objXmlWriter = null;
            XDocument objXDoc = null;
            StringBuilder objSB = null;
            StreamWriter objStreamWriter = null;
            AddressBook objAddrBook = null;
            int iCount = 10000;
            List<Contact> objContacts = null;

            //populate contacts in the addressbook object model
            objAddrBook = new AddressBook();
            objSW = new Stopwatch();
            for (int i = 0; i < iCount; i++)
            {
                Contact objContact = null;
                string strName = "Person" + (i + 1);
                string strAddress1 = "Number" + (i + 101);
                string strAddress2 = "Address" + (i + 501);
                int iZip = 50000 + (i + 1);
                string strPhone = "99999" + (i + 1);
                objContact = new Contact(strName, strAddress1, strAddress2, iZip,
                    strPhone);
                objAddrBook.Add(objContact);
            }
            //xml creation using XmlDocument
            objSW.Reset();
            objSW.Start();
            objXmlDoc = new XmlDocument();
            XmlElement objXmlAddrBook = objXmlDoc.CreateElement("AddressBook");
            objContacts = objAddrBook.GetContacts();
            for (int i = 0; i < objContacts.Count; i++)
            {
                XmlElement objXmlContact = objXmlDoc.CreateElement("Contact");
                XmlElement objXmlName = objXmlDoc.CreateElement("Name");
                objXmlName.InnerText = objContacts[i].Name;
                objXmlContact.AppendChild(objXmlName);
                XmlElement objXmlAddress1 = objXmlDoc.CreateElement("Address1");
                objXmlAddress1.AppendChild(
                    objXmlDoc.CreateCDataSection(objContacts[i].Address1));
                objXmlContact.AppendChild(objXmlAddress1);
                XmlElement objXmlAddress2 = objXmlDoc.CreateElement("Address2");
                objXmlAddress2.AppendChild(
                    objXmlDoc.CreateCDataSection(objContacts[i].Address2));
                objXmlContact.AppendChild(objXmlAddress2);
                XmlElement objXmlZip = objXmlDoc.CreateElement("Zip");
                objXmlZip.InnerText = objContacts[i].Zip.ToString();
                objXmlContact.AppendChild(objXmlZip);
                XmlElement objXmlPhone = objXmlDoc.CreateElement("Phone");
                objXmlPhone.AppendChild(
                    objXmlDoc.CreateCDataSection(objContacts[i].Phone));
                objXmlContact.AppendChild(objXmlPhone);
                objXmlAddrBook.AppendChild(objXmlContact);
            }
            objXmlDoc.AppendChild(objXmlAddrBook);
            objXmlDoc.Save("address_dom.xml");
            objSW.Stop();
            Console.WriteLine("XML file created using XmlDocument");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);

            //xml creation using XmlWriter
            objSW.Reset();
            objSW.Start();
            XmlWriterSettings objSettings = new XmlWriterSettings();
            objSettings.Indent = true;
            using (objXmlWriter = XmlWriter.Create("address_xw.xml", objSettings))
            {
                objXmlWriter.WriteStartElement("AddressBook");
                objContacts = objAddrBook.GetContacts();
                for (int i = 0; i < objContacts.Count; i++)
                {
                    objXmlWriter.WriteStartElement("Contact");

                    objXmlWriter.WriteStartElement("Name");
                    objXmlWriter.WriteString(objContacts[i].Name);
                    objXmlWriter.WriteEndElement();
                    objXmlWriter.WriteStartElement("Address1");
                    objXmlWriter.WriteCData(objContacts[i].Address1);
                    objXmlWriter.WriteEndElement();
                    objXmlWriter.WriteStartElement("Address2");
                    objXmlWriter.WriteCData(objContacts[i].Address2);
                    objXmlWriter.WriteEndElement();
                    objXmlWriter.WriteStartElement("Zip");
                    objXmlWriter.WriteString(objContacts[i].Zip.ToString());
                    objXmlWriter.WriteEndElement();
                    objXmlWriter.WriteStartElement("Phone");
                    objXmlWriter.WriteCData(objContacts[i].Phone);
                    objXmlWriter.WriteEndElement();

                    objXmlWriter.WriteEndElement();
                }
                objXmlWriter.WriteEndElement();
            }
            objSW.Stop();
            Console.WriteLine("XML file created using XmlWriter");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);
            //xml creation using StringBuilder
            objSW.Reset();
            objSW.Start();
            objSB = new StringBuilder();
            objSB.AppendLine("<AddressBook>");
            objContacts = objAddrBook.GetContacts();

            for (int i = 0; i < objContacts.Count; i++)
            {
                objSB.AppendLine("<Contact>");
                objSB.AppendLine("<Name>" + objContacts[i].Name + "</Name>");
                objSB.AppendLine(
                "<Address1><![CDATA[" + objContacts[i].Address1 + "]]></Address1>");
                objSB.AppendLine(
                "<Address2><![CDATA[" + objContacts[i].Address2 + "]]></Address2>");
                objSB.AppendLine("<Zip>" + objContacts[i].Zip + "</Zip>");
                objSB.AppendLine(
                "<Phone><![CDATA[" + objContacts[i].Phone + "]]></Phone>");
                objSB.AppendLine("</Contact>");
            }
            objSB.AppendLine("</AddressBook>");
            using (objStreamWriter = new StreamWriter("address_sb.xml", false))
            {
                objStreamWriter.Write(objSB.ToString());
            }
            objSW.Stop();
            Console.WriteLine("XML file created using StringBuilder");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);

            //xml creation using XDocument (LINQ)
            objSW.Reset();
            objSW.Start();
            objContacts = objAddrBook.GetContacts();
            XElement[] arrXElem = new XElement[objContacts.Count];
            for (int i = 0; i < objContacts.Count; i++)
            {
                arrXElem[i] = new XElement("Contact",
                    new XElement("Name", objContacts[i].Name),
                    new XElement("Address1",
                    new XCData(objContacts[i].Address1)),
                    new XElement("Address2",
                    new XCData(objContacts[i].Address2)),
                    new XElement("Zip", objContacts[i].Zip),
                    new XElement("Phone", new XCData(objContacts[i].Phone)));
            }
            objXDoc = new XDocument(new XElement("AddressBook",arrXElem));
            objXDoc.Save("address_xdocument.xml");
            objSW.Stop();
            Console.WriteLine("XML file created using XDocument");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);

            Console.ReadLine();

        }
    }
}
Output:
XML file created using XmlDocument
TimeElapsed (Stopwatch float):90.0323ms
TimeElapsed (Stopwatch rounded):90ms
XML file created using XmlWriter
TimeElapsed (Stopwatch float):36.2555ms
TimeElapsed (Stopwatch rounded):36ms
XML file created using StringBuilder
TimeElapsed (Stopwatch float):91.5911ms
TimeElapsed (Stopwatch rounded):91ms
XML file created using XDocument
TimeElapsed (Stopwatch float):71.3794ms
TimeElapsed (Stopwatch rounded):71ms

Note: The StringBuilder performance can be improved by specifying the required capacity when creating the StringBuilder object.

Note: XmlDocument can be considered, if forward and backward reference is unavoidable during the generation of xml document.

Rule: Use XmlWriter for generating or creating xml document.

C# Structure vs Class

Structure performs better than the reference type (Class) with respect to CPU usage and memory usage. Consider using structure over class,
  • If your application has to support data which does not require inheritance and interface
  • The data is in large number
  • The data is only of primitive data type like integer, byte, float, etc.
  • Probability a graphics application or application which deals with large data

Note: Structure with large number of members will degrade the performance when passed as parameter/argument to functions because the values of the entire structure is copied as parameter/argument to the function.

Below code measures the creation of 100000 objects of a class and also measures the time taken to search an object from the collection.
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Drawing;
namespace ClassTimeElapsed
{
    class Brick
    {
        public int Id;
        public float X;
        public float Y;
        public float Width;
        public float Height;
        public Color Color;
    }
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch objStopwatch;
            Brick[] arrBrick;
            int iCount;
            iCount = 100000;

            objStopwatch = new Stopwatch();
            objStopwatch.Reset();
            objStopwatch.Start();
            arrBrick = new Brick[iCount];

            for (int i = 0; i < iCount; i++)
            {
                arrBrick[i] = new Brick();
            }
            int iConst = 15;
            for (int i = 0; i < iCount; i++)
            {
                arrBrick[i].Id = i + 1;
                arrBrick[i].X = i * iConst;
                arrBrick[i].Y = 0;
                arrBrick[i].Width = 10;
                arrBrick[i].Height = 10;
                arrBrick[i].Color = Color.Teal;
            }
            objStopwatch.Stop();
            Console.WriteLine(
                "Class time elapsed for allocation and population");
            //timeelapsed
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objStopwatch.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objStopwatch.ElapsedMilliseconds);
            int iSearchId = 99880;
            Brick objBrick = null;
            objStopwatch.Reset();
            objStopwatch.Start();
            for (int i = 0; i < arrBrick.Length; i++)
            {
                if (iSearchId == arrBrick[i].Id)
                {
                    objBrick = arrBrick[i];
                    break;
                }
            }
            objStopwatch.Stop();
            Console.WriteLine(
                "Class time elapsed for searching");
            //search result
            Console.WriteLine(
                "search result: Id:{0},X:{1},Y:{2},Width:{3},Height:{4},Color:{5}",
                objBrick.Id, objBrick.X, objBrick.Y, objBrick.Width, objBrick.Height,
                objBrick.Color);
            //timeelapsed
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objStopwatch.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objStopwatch.ElapsedMilliseconds);
            Console.ReadLine();
        }
    }
}
Output:
Class time elapsed for allocation and population
TimeElapsed (Stopwatch float):13.7327ms
TimeElapsed (Stopwatch rounded):13ms
Class time elapsed for searching
search result: Id:99880,X:1498185,Y:0,Width:10,Height:10,Color:Color [Teal]
TimeElapsed (Stopwatch float):1.3015ms
TimeElapsed (Stopwatch rounded):1ms
Below code measures the creation of 100000 objects of a struct and also measures the time taken to search an object from the collection.
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Drawing;
namespace StructTimeElapsed
{
    struct Brick
    {
        public int Id;
        public float X;
        public float Y;
        public float Width;
        public float Height;
        public Color Color;
    }
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch objStopwatch;
            Brick[] arrBrick;
            int iCount;
            iCount = 100000;
            objStopwatch = new Stopwatch();
            objStopwatch.Reset();
            objStopwatch.Start();
            arrBrick = new Brick[iCount];
            int iConst = 15;
            for (int i = 0; i < iCount; i++)
            {
                arrBrick[i].Id = i + 1;
                arrBrick[i].X = i * iConst;
                arrBrick[i].Y = 0;
                arrBrick[i].Width = 10;
                arrBrick[i].Height = 10;
                arrBrick[i].Color = Color.Teal;

            }
            objStopwatch.Stop();
            Console.WriteLine(
                "Struct time elapsed for allocation and population");
            //timeelapsed
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objStopwatch.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objStopwatch.ElapsedMilliseconds);
            int iSearchId = 99880;
            Brick objBrick;
            objBrick.Id = 0;
            objBrick.X = 0;
            objBrick.Y = 0;
            objBrick.Width = 0;
            objBrick.Height = 0;
            objBrick.Color = Color.Transparent;
            objStopwatch.Reset();
            objStopwatch.Start();
            for (int i = 0; i < arrBrick.Length; i++)
            {
                if (iSearchId == arrBrick[i].Id)
                {
                    objBrick = arrBrick[i];
                    break;
                }
            }
            objStopwatch.Stop();
            Console.WriteLine(
                "Struct time elapsed for searching");
            //search result
            Console.WriteLine(
                "search result: Id:{0},X:{1},Y:{2},Width:{3},Height:{4},Color:{5}",
                objBrick.Id, objBrick.X, objBrick.Y, objBrick.Width, objBrick.Height,
                objBrick.Color);
            //timeelapsed
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objStopwatch.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objStopwatch.ElapsedMilliseconds);
            Console.ReadLine();
        }
    }
}
Output:
Struct time elapsed for allocation and population
TimeElapsed (Stopwatch float):3.0684ms
TimeElapsed (Stopwatch rounded):3ms
Struct time elapsed for searching
search result: Id:99880,X:1498185,Y:0,Width:10,Height:10,Color:Color [Teal]
TimeElapsed (Stopwatch float):1.0981ms
TimeElapsed (Stopwatch rounded):1ms
Below code measures the memory usage of creation of 100000 objects of a class.
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Drawing;
namespace ClassMemoryUsage
{
    class Brick
    {
        public int Id;
        public float X;
        public float Y;
        public float Width;
        public float Height;
        public Color Color;
    }
    class Program
    {
        static void Main(string[] args)
        {
            long lngGCMemStart = 0;
            long lngGCMemEnd = 0;
            long lngProcessMemStart = 0;
            long lngProcessMemEnd = 0;
            Brick[] arrBrick;
            int iCount;
            iCount = 100000;
            Process objProcess = Process.GetCurrentProcess();
            //Measure starting point memory
            lngGCMemStart = System.GC.GetTotalMemory(true);
            lngProcessMemStart = objProcess.PrivateMemorySize64;
            arrBrick = new Brick[iCount];
            for (int i = 0; i < iCount; i++)
            {
                arrBrick[i] = new Brick();
            }
            //Measure memory after allocating
            lngGCMemEnd = System.GC.GetTotalMemory(true);
            lngProcessMemEnd = objProcess.PrivateMemorySize64;
            int iConst = 15;
            for (int i = 0; i < iCount; i++)
            {
                arrBrick[i].Id = i+1;
                arrBrick[i].X = i*iConst;
                arrBrick[i].Y = 0;
                arrBrick[i].Width = 10;
                arrBrick[i].Height = 10;
                arrBrick[i].Color = Color.Teal;
            }
            Console.WriteLine("Class memory usage.");
            //memoryusage difference
            Console.WriteLine("GC Memory Use:{0} (bytes)",
                lngGCMemEnd - lngGCMemStart);
            Console.WriteLine("Process Memory Use:{0} (bytes)",
                lngProcessMemEnd - lngProcessMemStart);
            Console.WriteLine("GC Memory Start:{0} (bytes)",
                lngGCMemStart.ToString());
            Console.WriteLine("Process Memory Start:{0} (bytes)",
                lngProcessMemStart.ToString());
            Console.WriteLine("GC Memory End:{0} (bytes)",
                lngGCMemEnd.ToString());
            Console.WriteLine("Process Memory End:{0} (bytes)",
                lngProcessMemEnd.ToString());
            Console.ReadLine();
        }
    }
}
Output:
Class memory usage.
GC Memory Use:4802368 (bytes)
Process Memory Use:0 (bytes)
GC Memory Start:130648 (bytes)
Process Memory Start:9232384 (bytes)
GC Memory End:4933016 (bytes)
Process Memory End:9232384 (bytes)
Below code measures the memory usage of creation of 100000 objects of a struct.
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Drawing;

namespace StructMemoryUsage
{
    struct Brick
    {
        public int Id;
        public float X;
        public float Y;
        public float Width;
        public float Height;
        public Color Color;
    }

    class Program
    {
        static void Main(string[] args)
        {
            long lngGCMemStart = 0;
            long lngGCMemEnd = 0;
            long lngProcessMemStart = 0;
            long lngProcessMemEnd = 0;
            Brick[] arrBrick;
            int iCount;
            iCount = 100000;
            Process objProcess = Process.GetCurrentProcess();
            //Measure starting point memory
            lngGCMemStart = System.GC.GetTotalMemory(true);
            lngProcessMemStart = objProcess.PrivateMemorySize64;
            arrBrick = new Brick[iCount];
            //Measure memory after allocating
            lngGCMemEnd = System.GC.GetTotalMemory(true);
            lngProcessMemEnd = objProcess.PrivateMemorySize64;
            int iConst = 15;
            for (int i = 0; i < iCount; i++)
            {
                arrBrick[i].Id = i + 1;
                arrBrick[i].X = i * iConst;
                arrBrick[i].Y = 0;
                arrBrick[i].Width = 10;
                arrBrick[i].Height = 10;
                arrBrick[i].Color = Color.Teal;
            }
            Console.WriteLine("Struct memory usage.");
            //memoryusage difference
            Console.WriteLine("GC Memory Use:{0} (bytes)",
                lngGCMemEnd - lngGCMemStart);
            Console.WriteLine("Process Memory Use:{0} (bytes)",
                lngProcessMemEnd - lngProcessMemStart);
            Console.WriteLine("GC Memory Start:{0} (bytes)",
                lngGCMemStart.ToString());
            Console.WriteLine("Process Memory Start:{0} (bytes)",
                lngProcessMemStart.ToString());
            Console.WriteLine("GC Memory End:{0} (bytes)",
                lngGCMemEnd.ToString());
            Console.WriteLine("Process Memory End:{0} (bytes)",
                lngProcessMemEnd.ToString());
            Console.ReadLine();
        }
    }
}
Output:
Struct memory usage.
GC Memory Use:3602368 (bytes)
Process Memory Use:0 (bytes)
GC Memory Start:130656 (bytes)
Process Memory Start:9232384 (bytes)
GC Memory End:3733024 (bytes)
Process Memory End:9232384 (bytes)

Why? Structure is created in the stack.Structure is a value type.

Rule: Consider using structure for supporting large number of objects(data) in your application.

C# StringBuilder vs String Concatenation

Use StringBuilder for string concatenation. Concatenation of string using StringBuilder has better performance over string.
Below code measures the time taken to concatenate a string for 5000 iteration using “string” and “StringBuilder”.
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
namespace StringVsStringBuilder
{
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch objStopwatch = new Stopwatch();
            string strValue=string.Empty;
            StringBuilder objSBValue = new StringBuilder();
            int iCount = 5000;
            objStopwatch.Reset();
            objStopwatch.Start();
            for (int i = 0; i < iCount; i++)
            {
                strValue = strValue+"simpleValue"+i.ToString();
            }
            objStopwatch.Stop();
            Console.WriteLine("concatenation using String.");
            Console.WriteLine(
                "TimeElapsed (Stopwatch float):{0}ms",
                objStopwatch.Elapsed.TotalMilliseconds
                );
            Console.WriteLine(
                "TimeElapsed (Stopwatch rounded):{0}ms",
                objStopwatch.ElapsedMilliseconds
                );
            //Console.WriteLine(strValue);
            objStopwatch.Reset();
            objStopwatch.Start();
            for (int i = 0; i < iCount; i++)
            {
                objSBValue.Append("simpleValue" + i.ToString());
            }
            objStopwatch.Stop();
            Console.WriteLine(
                "concatenation using StringBuilder."
                );
            Console.WriteLine(
                "TimeElapsed (Stopwatch float):{0}ms",
                objStopwatch.Elapsed.TotalMilliseconds
                );
            Console.WriteLine(
                "TimeElapsed (Stopwatch rounded):{0}ms",
                objStopwatch.ElapsedMilliseconds
                );
            //Console.WriteLine(objSBValue);
            Console.ReadLine();
        }
    }
}
Output:
concatenation using String.
TimeElapsed (Stopwatch float):316.6526ms
TimeElapsed (Stopwatch rounded):316ms
concatenation using StringBuilder.
TimeElapsed (Stopwatch float):2.4933ms
TimeElapsed (Stopwatch rounded):2ms

Why? Any object stored in heap is immutable with respect to size allocation, and any change to the underlying size will require reallocation. If the string is modified (concatenating another string onto it, changing its value), then a new string is created and this can have negative performance implications. The StringBuilder gets around the reallocation problem by using internal buffers. But once the buffer fills up, the reallocation occurs. It is recommended to specify the initial capacity to minimize the reallocation problem.

Rule: Use StringBuilder instead of string for string concatenation operation.

C# XmlReader vs XDocument vs XmlDocument

Use Xmlreader for parse xml document.
Create an xml file as show below, but with 10000 contact elements called as “address_xw_n.xml” and make it available in D driver (d:\).
<AddressBook>
  <Contact>
    <Name>Person1</Name>
    <Address1><![CDATA[Number101]]></Address1>
    <Address2><![CDATA[Address501]]></Address2>
    <Zip>50001</Zip>
    <Phone><![CDATA[999991]]></Phone>
 </Contact>
</AddressBook>
The below code demonstrate the time take to parse the above created xml file using XmlDocument, XDocument and XmlReader.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Diagnostics;
using System.Xml.Linq;
namespace XmlParse
{
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch objSW = null;
            String strNormalFilePath;
            strNormalFilePath = @"d:\address_xw_n.xml";
            XmlDocument xmlNDoc;
            XmlReader xmlNReader = null;
            XDocument xNDoc=null;
            objSW = new Stopwatch();

            //xml parsing using XmlDocument - Normal format
            objSW.Reset();
            objSW.Start();
            xmlNDoc = new XmlDocument();
            xmlNDoc.Load(strNormalFilePath);
            XmlElement xmlDocNElem = xmlNDoc.DocumentElement;
            for (int i = 0; i < xmlDocNElem.ChildNodes.Count; i++)
            {
                XmlNode xmlNode = xmlDocNElem.ChildNodes[i];
                for (int j = 0; j < xmlNode.ChildNodes.Count; j++)
                {
                    string strName = xmlNode.ChildNodes[j].Name;
                    string strValue = xmlNode.ChildNodes[j].ChildNodes[0].Value;
                    //Console.WriteLine(strName + "-" + strValue);
                }
            }
            //xmlNDoc = null;
            objSW.Stop();
            Console.WriteLine("XML parsing using XmlDocument - Normal format");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);

            //xml parsing using XDocument - Normal format
            objSW.Reset();
            objSW.Start();
            xNDoc = XDocument.Parse(xmlNDoc.OuterXml);
            foreach (XElement e in xNDoc.Root.Elements())
            {
                foreach (XElement c in e.Elements())
                {
                    string strName = c.Name.ToString();
                    string strValue = c.Value;
                    //Console.WriteLine(strName+"-"+strValue);
                }
            }
            xNDoc = null;
            objSW.Stop();
            Console.WriteLine("XML parsing using XDocument - Normal format");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);

            //xml parsing using XmlReader - Normal format
            objSW.Reset();
            objSW.Start();
            using (xmlNReader = XmlReader.Create(strNormalFilePath))
            {
                while (xmlNReader.Read())
                {
                    switch (xmlNReader.NodeType)
                    {
                        case XmlNodeType.Element:
                            {
                                switch (xmlNReader.Name)
                                {
                                    case "Name":
                                    case "Zip":
                                        {
                                            string strName = xmlNReader.Name;
                                            xmlNReader.Read();
                                            string strValue = xmlNReader.Value;
                                            //Console.WriteLine(strName +
                                            //  "-" + strValue);
                                            break;
                                        }
                                    case "Address1":
                                    case "Address2":
                                    case "Phone":
                                        {
                                            string strName = xmlNReader.Name;
                                            xmlNReader.Read();
                                            string strValue = xmlNReader.Value;
                                            //Console.WriteLine(strName +
                                            //  "-" + strValue);
                                            break;
                                        }
                                }

                                break;
                            }
                    }
                }
            }

            objSW.Stop();
            Console.WriteLine("XML parsing using XmlReader - Normal format");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);
            Console.ReadLine();


        }
    }
}
Output:
XML parsing using XmlDocument - Normal format
TimeElapsed (Stopwatch float):5232.8249ms
TimeElapsed (Stopwatch rounded):5232ms
XML parsing using XDocument - Normal format
TimeElapsed (Stopwatch float):114.9677ms
TimeElapsed (Stopwatch rounded):114ms
XML parsing using XmlReader - Normal format
TimeElapsed (Stopwatch float):42.7921ms
TimeElapsed (Stopwatch rounded):42ms

Note: XmlDocument can be considered, if forward and backward reference is unavoidable during the parsing of xml document.

Rule: Use XmlReader for parsing xml document.

C# XPATH vs LINQ

Use Xmlreader for parsing xml document.
Create an xml file as show below, but with 10000 contact elements called as “address_xw_n.xml” and make it available in D driver (d:\).
<AddressBook>
  <Contact>
    <Name>Person1</Name>
    <Address1><![CDATA[Number101]]></Address1>
    <Address2><![CDATA[Address501]]></Address2>
    <Zip>50001</Zip>
    <Phone><![CDATA[999991]]></Phone>
 </Contact>
</AddressBook>
The below code demonstrate the time take to query the above created xml file using xpath and LINQ for the Phone element value “999999996“.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Diagnostics;
using System.Xml.Linq;
namespace QueryXML
{
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch objSW = null;
            String strNormalFilePath;
            strNormalFilePath = @"d:\address_xw_n.xml";
            XmlDocument xmlNDoc;
            xmlNDoc = new XmlDocument();
            XDocument xNDoc;
            objSW = new Stopwatch();

            objSW.Reset();
            objSW.Start();
            //load the xml
            xmlNDoc.Load(strNormalFilePath);
            //xml query using xpath - Normal format
            objSW.Reset();
            objSW.Start();
            XmlNode xmlQNNode = xmlNDoc.SelectSingleNode(
                "/AddressBook/Contact/Phone[contains(text(),'999999996')]");
            //Console.WriteLine(xmlQNNode.Name +
            //  "-" + xmlQNNode.ChildNodes[0].Value);
            objSW.Stop();
            Console.WriteLine("XML query using xpath - Normal format");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);

            //xml query using LINQ - Normal format
            //Let us not include the conversion of XmlDocument to XDocument
            xNDoc = XDocument.Parse(xmlNDoc.OuterXml);
            objSW.Reset();
            objSW.Start();
            var linqNQuery = from p in
                                 xNDoc.Root.Elements("Contact").Elements("Phone")
                             where p.Value.Contains("999999996") select p;
            /*foreach (XElement e in linqNQuery)
            {
                Console.WriteLine(e.Name+"-"+e.Value);
            }*/
            objSW.Stop();
            Console.WriteLine("XML query using LINQ - Normal format");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);

            Console.ReadLine();
        }
    }
}

Output:
XML query using xpath - Normal format
TimeElapsed (Stopwatch float):20.0936ms
TimeElapsed (Stopwatch rounded):20ms
XML query using LINQ - Normal format
TimeElapsed (Stopwatch float):0.5082ms
TimeElapsed (Stopwatch rounded):0ms

Rule: Use LINQ for querying xml content.

Wednesday, August 25, 2010

Reading GPS data from Nokia phones

To read GPS data from your Nokia phone follow the below steps,

Make sure your Nokia phone supports inbuilt GPS receiver.

Install Aptana with Nokia WRT Plug-in for Aptana Studio.

Create a new project in Aptana with WRTKit.

1) Paste the below code in the index.html file.
2) Package the widget.
3) Download the package (yourprojectname.wgz) to your Nokia phone and install.
4) Run the application and wait the application to establish connection with the satellites.
5) Have fun!

Javascript example
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>GPS Tracker</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />        
<script type="text/javascript" src="WRTKit/WRTKit.js"></script>        
<META NAME="Generator" CONTENT="Nokia WRT plug-in for Aptana Studio 2.3.0" />
<style>
body{background-color:#ffffff;font-size:15px;}
#btnGetLocation{width:100%;margin:5px;height:50px;width:100px;}
#latLabel{text-align:left;margin:5px;width:150px;}
#longLabel{text-align:left;margin:5px;width:150px;}
#statusLabel{text-align:left;margin:5px;width:150px;}
#gpsStatusLabel{padding:5px;text-align:left;margin:5px;height:20px;width:150px;}
.gpsStatusLabelA{background-color:lightgreen;}
.gpsStatusLabelIA{background-color:red;}
#gpsStrengthLabel{text-align:left;margin:5px;width:150px;}
</style>
<script>
var interval=1000;   
var TXT_ACTIVE = "Active";
var TXT_INACTIVE = "Inactive";  
var TXT_RUNNING="Running";
var TXT_GPSSTATUSLABEL="gpsStatusLabel";
var GPS_INACTIVE = 0;
var GPS_ACTIVE = 1;

var locDataTimer = null;
var serviceObj = null;
var distanceCriteria = null;
var trackCriteria = null;

function updateElement(name,value)
{
 document.getElementById(name).innerHTML=value;
 if(name == TXT_GPSSTATUSLABEL)
 {     
  if(value == TXT_ACTIVE)
  {  
   document.getElementById(name).setAttribute("class", "gpsStatusLabelA");  
  }
  else
  {  
   document.getElementById(name).setAttribute("class", "gpsStatusLabelIA");
  }
 }
}
function reset()
{
 updateElement("gpsStatusLabel",TXT_INACTIVE);
 updateElement("gpsStrengthLabel","");
 updateElement("statusLabel","");
 updateElement("latLabel","");
 updateElement("longLabel","");    
}
function initUI()
{
 reset();
}
function initSO()
{
 try
 {
  serviceObj = device.getServiceObject("Service.Location", "ILocation");
 }
 catch (ex) 
 {
  updateElement("statusLabel",ex);
  return;
 } 
 // The user cancelled the service object initialization
 if (serviceObj.ILocation == null) 
 {
  return; 
 }        
 // Specify that location information need not be guaranteed. This helps in
 // that the widget doesn't need to wait for that information possibly
 // indefinitely.
 var updateOptions = new Object();
 updateOptions.PartialUpdates = true;
 
 // Initialize the criteria for the GetLocation call
 trackCriteria = new Object();
 trackCriteria.LocationInformationClass = "GenericLocationInfo";
 trackCriteria.Updateoptions = updateOptions;
 // Set the timer to tick (update the location data) at one second intervals
 locDataTimer = setInterval("tick()", interval);
}
function init()
{
 initUI();    
 initSO();
}

// Called when the locDataTimer's interval elapses
function tick() 
{
 updateElement("statusLabel",TXT_RUNNING);
 try 
 {
  var result = serviceObj.ILocation.GetLocation(trackCriteria);
  displayData(result);    
 }
 catch (ex) 
 {
  updateElement("statusLabel",ex);  
 }
}
// Displays the location data
function displayData(result) 
{
 if (result.ReturnValue == undefined) 
 {
  return;
 }

 var latitude = result.ReturnValue.Latitude;
 if (!isNaN(latitude)) 
 {
  updateElement("latLabel", latitude.toFixed(4) + " \u00B0");
 }       
 var longitude = result.ReturnValue.Longitude;
 if (!isNaN(longitude)) 
 {
  updateElement("longLabel", longitude.toFixed(4) + " \u00B0");
 }   
 if (!isNaN(latitude) || !isNaN(longitude)) 
 {
  // Either latitude or longitude information is received, so we can be
  // sure that the GPS is active
  changeGPSStatus(GPS_ACTIVE);
 }
 else 
 {
  changeGPSStatus(GPS_INACTIVE);
 }
 
 var numOfSatellites = result.ReturnValue.SatelliteNumView;
 if (numOfSatellites == undefined) 
 {
  numOfSatellites = 0;
 }
 updateElement("gpsStrengthLabel",numOfSatellites);
}   
//Changes the GPS status on the status pane
function changeGPSStatus(newStatus) 
{       
 if (newStatus == GPS_ACTIVE) 
 {
  updateElement("gpsStatusLabel",TXT_ACTIVE);
 } 
 else 
 {
  updateElement("gpsStatusLabel",TXT_INACTIVE);
 }
}
</script>
</head>
<body onload="init()">
<h3>GPS Tracker</h3>
<table border="1px" width="100%">
<tr>
<td>
GPS:
</td> 
<td align="center">
<div id="gpsStatusLabel"></div>   
</td>
</tr>
<tr>
<td>
GPS Strength:
</td> 
<td align="center">
<div id="gpsStrengthLabel"></div>   
</td>
</tr>
<tr>
<td>
Lat:
</td> 
<td align="center">
<div id="latLabel"></div>   
</td>
</tr>
<tr>
<td>
Long:
</td> 
<td align="center">
<div id="longLabel"></div>   
</td>
</tr>   
<tr>
<td>
Status:
</td> 
<td align="center">
<div id="statusLabel"></div>   
</td>
</tr>
</table>       
</body>
</html>

Simple soap client

Below is a simple javascript soap client. The same code can be modified to work as an ajax client by removing the SOAPAction header. The below code accepts the service URL, soap envelope, SOAPAction header name (because it may be of different case in different technology), action and method.

Javascript example
<html>
<head>
<title>Soap Client</title>
<script>
var READY_STATE_UNINITIALIZED=0;
var READY_STATE_LOADING=1;
var READY_STATE_LOADED=2;
var READY_STATE_INTERACTIVE=3;
var READY_STATE_COMPLETE=4;
var xmlHttpRequest;
function getXmlHttpRequest()
{
 var xRequest=null;
 if (window.XMLHttpRequest)
 {
  xRequest=new XMLHttpRequest();
 }
 else if (typeof ActiveXObject != "undefined")
 {
  xRequest=new ActiveXObject("Microsoft.XMLHTTP");
 }
 return xRequest;
}
function handleEmptyString(value,userMessage)
{
    var status=false;
    if(value == "")
    {
        alert(userMessage);
    }
    else
    {
        status=true;
    }
    return status;
}
function sendRequest(url,soapActionHeaderName,
                        soapAction,params,httpMethod,contentType)
{
    var status=false;
    status=handleEmptyString(url,"Please enter the URL.");
    if(status == true)
    {
        status=handleEmptyString(soapActionHeaderName,"Please enter the Soap action header name.");
        if(status == true)
        {
            status=handleEmptyString(soapAction,"Please enter the Saop action.");
            if(status == true)
            {
                status=handleEmptyString(params,"Please enter the soap request.");
                if(status == true)
                {
                    status=handleEmptyString(contentType,"Please enter the content type.");
                }
            }
        }
    }
    if(status==true)
    {
        //Disable mozilla security restriction
        if(window.netscape &&
        window.netscape.security.PrivilegeManager.enablePrivilege)
        {
            var pm=netscape.security.PrivilegeManager;
            pm.enablePrivilege('UniversalBrowserRead');
        }
        // If method not set
        if (!httpMethod)
        {
            httpMethod="GET";
        }
        xmlHttpRequest=getXmlHttpRequest();
        if (xmlHttpRequest)
        {
            xmlHttpRequest.onreadystatechange=onReadyStateChange;
            xmlHttpRequest.open(httpMethod,url,true);
            xmlHttpRequest.setRequestHeader(
            "Content-Type",contentType);
            xmlHttpRequest.setRequestHeader(soapActionHeaderName,soapAction);
            xmlHttpRequest.send(params);
        }
    }
}
function onReadyStateChange()
{
    var ready=xmlHttpRequest.readyState;
    var data=null;
    if (ready==READY_STATE_COMPLETE)
    {
        data=xmlHttpRequest.responseText;
        //... do something with the data...
        document.getElementsByName("taResponse")[0].value=data;
    }
    else
    {
        data="Loading...["+ready+"]";
        document.getElementsByName("taResponse")[0].value=data;
    }
}
function sendData()
{
    var url=document.getElementsByName("txtURL")[0].value;
    var params=document.getElementsByName("taRequest")[0].value;
    var httpMethod=document.getElementsByName("txtMethod")[0].value;
    var soapActionHeaderName;
    soapActionHeaderName=document.getElementsByName("txtActionHeaderName")[0].value;
    var soapAction=document.getElementsByName("txtAction")[0].value;
    var contentType=document.getElementsByName("txtContentType")[0].value;
    sendRequest(url,soapActionHeaderName,soapAction,params,httpMethod,contentType);
}
function clearData()
{
    document.getElementsByName("taResponse")[0].value="";
}
</script>
</head>
<body>
<h1>Soap client</h1>
<table>
<tr>
<tr>
<td>URL: (e.g. http://xyz.com/service)</td>
<td><input type="text"
value="http://localhost:8080/CalculatorProj/services/Calculator"
name="txtURL" size="150"/></td>
</tr>
<td>Request:</td>
<td><textarea rows="12" cols="120" name="taRequest">
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:q0="http://wtp" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <q0:add>
      <q0:number1>5</q0:number1>
      <q0:number2>6</q0:number2>
    </q0:add>
  </soapenv:Body>
</soapenv:Envelope>
</textarea>
</td>
</tr>
<tr>
<td>Action header name:</td>
<td><input type="text" value="SOAPAction" name="txtActionHeaderName"/></td>
</tr>
<tr>
<td>Action:</td>
<td><input type="text" value="add" name="txtAction"/></td>
</tr>
<tr>
<td>Content type:</td>
<td><input type="text" value="text/xml; charset=utf-8" name="txtContentType" /></td>
</tr>
<tr>
<td>Method: (GET/POST)</td>
<td><input type="text" value="POST" name="txtMethod"/></td>
</tr>
<tr>
<td>Response:</td>
<td><textarea rows="8" cols="120" name="taResponse"></textarea></td>
</tr>
<tr>
<td></td>
<td align="center">
    <input type="button" value="Send" onclick="sendData()"/>
    <input type="button" value="Clear Result" onclick="clearData()"/>
</td>
</tr>
</table>
</body>
</html>

Note: This code sample works only with in your domain. If you want to try across domain then please refer Google AJAX APIs.

Monday, August 23, 2010

Reading cross domain JSON (AJAX)

If you want to read JSON content from a different domain, let us say you want to read JSON content from http://twitter.com, then here is a simple example using JQUERY JSON API.

http://twitter.com JSON content link is http://api.twitter.com/1/statuses/public_timeline.json?callback=?.

Javascript example with jQuery.each() loop
<script type="text/javascript" src="http://code.jquery.com/jquery-1.4.2.min.js"></script>
<script>
var JSONPUBICURL="http://api.twitter.com/1/statuses/public_timeline.json?callback=?";
var TWITTERURL="http://twitter.com/";
function getJSON()
{
var strHTML='';
var imgURL="";
$.getJSON(JSONPUBICURL,
function(data){
strHTML+='<table border="0px">';
$.each(data, function(i, item) {

    imgURL=item.user["profile_image_url"];

    strHTML+='<tr>';
    strHTML+='<td valign="top">';
    strHTML+='<img src="'+imgURL+'" alt="'+item.user["screen_name"]+'" title="'+item.user["screen_name"]+'" height="50px" width="50px"/>';
    strHTML+='</td>';
    strHTML+='<td valign="top" >';
    strHTML+='<a href="'+TWITTERURL+item.user["screen_name"]+'/statuses/'+item.id+'" target="_blank" >'+item.text+'</a><br/>';
    strHTML+=item.created_at+' [via '+item.source+']<br/>';
    strHTML+='</td>';
    strHTML+='</tr>';
});
strHTML+='</table>';
strHTML+='<div align="right" ><a href="'+TWITTERURL+'" target="_blank">more...</a></div>';
document.getElementById("tweets").innerHTML=strHTML;
});
}
</script>
<div id="tweets"></div>
<script>
    $(document).ready(getJSON());
</script>

Note: using this approach you can get the live tweets from http://twitter.com.


Javascript example with for loop
<script type="text/javascript" src="http://code.jquery.com/jquery-1.4.2.min.js"></script>
<script>
var JSONPUBICURL="http://api.twitter.com/1/statuses/public_timeline.json?callback=?";
var TWITTERURL="http://twitter.com/";
function getJSON()
{

var strHTML='';
var imgURL="";

$.getJSON(JSONPUBICURL,
function(data){
strHTML+='<table border="0px">';
var length=data.length;
for(var i=0;i<length;i++)
{
    imgURL=data[i].user["profile_image_url"];
    strHTML+='<tr>';
    strHTML+='<td valign="top">';
    strHTML+='<img src="'+imgURL+'" alt="'+data[i].user["screen_name"]+'" title="'+data[i].user["screen_name"]+'" height="50px" width="50px"/>';
    strHTML+='</td>';
    strHTML+='<td valign="top" >';
    strHTML+='<a href="'+TWITTERURL+data[i].user["screen_name"]+'/statuses/'+data[i].id+'" target="_blank" >'+data[i].text+'</a><br/>';
    strHTML+=data[i].created_at+' [via '+data[i].source+']<br/>';
    strHTML+='</td>';
    strHTML+='</tr>';

}
strHTML+='</table>';
strHTML+='<div align="right" ><a href="'+TWITTERURL+'" target="_blank">more...</a></div>';
document.getElementById("tweets").innerHTML=strHTML;

});

}
</script>
<div id="tweets"></div>
<script>
    $(document).ready(getJSON());
</script>

for loop may be faster than jQuery.each() loop. see jQuery tests in Low Level JavaScript Performance.

Sunday, August 22, 2010

Reading cross domain RSS feeds (AJAX)

If you want to read an RSS feed from a different domain, let us say you want to read an RSS feed from http://digg.com, then here is a simple example using Google AJAX Feed API.

http://digg.com RSS feed link is http://feeds.digg.com/digg/popular.rss.

Javascript example
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script>
var RSSURL="http://feeds.digg.com/digg/popular.rss";
var DIGGURL="http://digg.com/";
function getFeed()
{
var strHTML='';
var feed = new google.feeds.Feed(RSSURL);
feed.load(function(result) {
if (!result.error) {    
    var length=result.feed.entries.length;
    for (var i = 0; i < length; i++) {
        var entry = result.feed.entries[i];
        strHTML+='';
        strHTML+='<a href="'+entry.link+'" target="_blank">'+entry.title+'</a><br/>';
        strHTML+=entry.publishedDate+'<br/>';
        strHTML+='<div>';
        strHTML+=entry.contentSnippet+'<br/>';
        strHTML+='</div>';
        strHTML+='<br/>';
    }
    strHTML+='<div align="right"><a href="'+DIGGURL+'" target="_blank">more...</a></div>';
    document.getElementById("digg").innerHTML=strHTML;
}
});
}
</script>
<div id="digg"></div>
<script>
    google.load("feeds", "1");
    google.setOnLoadCallback(getFeed);
</script>

Note: As the Google AJAX Feed API uses Feedfetcher, feed data from the AJAX Feed API may not always be up to date. The Google feed crawler ("Feedfetcher") retrieves feeds from most sites less than once every hour. Some frequently updated sites may be refreshed more often.

Wednesday, August 18, 2010

Naming convention

There are no hard and fast rules as far as naming conventions are concerned, but it has to be consistent at the individual, team and organization level.

The name of the folder, project, file, namespace, class, and function have to be meaningful. The variable (data members, local members or function arguments) must have the following information as part of their name
  • modifier (private, public, etc.) and scope of the variable (member to the class (data member), member to the function (local variable), constant, static)
  • datatype of the variable
  • meaningful name
Along with the above mentioned points you can also add comments where ever necessary. Also indentation of the code would improve the readability.

C# 2.0 example- Below is the Employee.cs file.
using System;
using System.Collections.Generic;
using System.Text;
namespace Sample_v2
{
    class Employee
    {
        private string m_strName=String.Empty;
        private int m_iEmpId=-1;
        public Employee(string strName, int iEmpId)
        {
            m_strName = strName;
            m_iEmpId = iEmpId;
        }
        public string Name
        {
            get
            {
                return m_strName;
            }
            private set { m_strName = value; }
        }
        public int EmpId
        {
            get
            {
                return m_iEmpId;
            }
            private set { m_iEmpId = value; }

        }
        //should not allow empty string or null string
        public bool SetNameWithValidation(string strName)
        {
            bool blnStatus = false;
            if (strName != string.Empty && strName != null)
            {
                m_strName = strName;
                blnStatus = true;
            }
            return blnStatus;
        }
        public override string ToString()
        {
            return string.Format("Name:{0},EmpId:{1}",
                m_strName, m_iEmpId);
        }

    }

}

C# 3.0 example- Below is the Employee.cs file.
using System;
using System.Collections.Generic;
using System.Text;
namespace Sample_v3
{
    class Employee
    {
        public string Name { get; set; }
        public int EmpId { get; set; }
        public Employee()
        {

        }
        //should not allow empty string or null string
        public bool SetName(string strName)
        {
            bool blnStatus = false;
            if (strName != string.Empty && strName != null)
            {
                Name = strName;
                blnStatus = true;
            }
            return blnStatus;
        }
        public override string ToString()
        {
            return string.Format("Name:{0},EmpId:{1}",
                Name,
                EmpId);
        }
    }
}

Note: Alternatively you can follow the naming standard followed by the respective technology (.Net, J2SE, JavasScript, etc). Intellisense feature of the respective integrated development environment (IDE) could help you on this.

Rule: Follow consistent naming convention.

Rule: If you not clear on the final name of the product, module, etc consider using a meaning less code name (e.g. "code123").

Thursday, June 17, 2010

Optimizing C# code

Let us try to understand what is called optimizing a code.
Write a simple logging function which shall
write the given string message to a file.

Step #1 - Write the Logger class with a function which will open/create the text file and append the string message along with time stamp and close the file.

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Threading;

namespace LoggerTimeElapsed
{

    class Logger
    {
        public string FilePath { get; set; }
        private object m_objLocker;
        public Logger()
        {
            m_objLocker = new object();
            FilePath = @"d:\log.txt";
        }
        //make sure the StreamWriter is closed
        //make sure thr Monitor is exit
        public bool WriteToFile(string strMessage)
        {
            bool blnStatus = false;
            StreamWriter objStreamWriter = null;
            if (strMessage != string.Empty && strMessage != null)
            {
                try
                {
                    Monitor.Enter(m_objLocker);
                    objStreamWriter = new StreamWriter(FilePath, true);
                    //logs only the time and not the date
                    objStreamWriter.WriteLine(
                        DateTime.Now.TimeOfDay + " - " + strMessage
                        );
                    objStreamWriter.Close();
                    Monitor.Exit(m_objLocker);
                    blnStatus = true;
                }
                catch (Exception objEx)
                {
                    //use messagebox if winforms application
                    Console.WriteLine(objEx.StackTrace);
                    if (objStreamWriter != null)
                    {
                        objStreamWriter.Close();
                    }
                    Monitor.Exit(m_objLocker);
                }
                finally
                {
                }
            }
            return blnStatus;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Logger objLogger = null;
            Stopwatch objSW = null;
            int iCount = 100;
            objSW = new Stopwatch();
            objLogger = new Logger();
            objSW.Reset();
            objSW.Start();
            for (int i = 0; i < iCount; i++)
            {
                objLogger.WriteToFile("Unoptimized" + i.ToString());
            }
            objSW.Stop();
            Console.WriteLine("WriteToFile - TimeElapsed");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);
            Console.ReadLine();
        }
    }
}
Step #2 - Measure the time taken by the function to log 100 messages to the text file.In the above code Stopwatch class is used for measuring the time.
Output:
WriteToFile - TimeElapsed
TimeElapsed (Stopwatch float):319.2352ms
TimeElapsed (Stopwatch rounded):319ms
Step #3 - If the time taken by the function does not meet the throughput requirement, then try to optimize the code. So let us now change the Logger class such that, the text file is opened only once and closed only once.
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Threading;

namespace LoggerTimeElapsed
{

    class Logger
    {
        public string FilePath { get; set; }
        private StreamWriter m_objStreamWriter = null;
        private object m_objLocker;
        public Logger()
        {
            m_objLocker = new object();
            FilePath = @"d:\log.txt";
        }
        public bool Open()
        {
            bool blnStatus = false;
            try
            {
                m_objStreamWriter = new StreamWriter(FilePath, true);
                blnStatus = true;
            }
            catch (Exception objEx)
            {
                Console.WriteLine(objEx.StackTrace);
            }
            finally
            {
            }
            return blnStatus;
        }
        public bool Close()
        {
            bool blnStatus = false;
            try
            {
                if (m_objStreamWriter != null)
                {
                    m_objStreamWriter.Close();
                    blnStatus = true;
                }
            }
            catch (Exception objEx)
            {
                Console.WriteLine(objEx.StackTrace);
            }
            finally
            {
            }
            return blnStatus;
        }
        //make sure Open is called before calling WriteToFile
        //make sure Close is called once all logging is done
        public bool WriteToFile(string strMessage)
        {
            bool blnStatus = false;
            if (strMessage != string.Empty && strMessage != null)
            {
                try
                {
                    lock (m_objLocker)
                    {
                        if (m_objStreamWriter != null)
                        {
                            //logs only the time and not the date
                            m_objStreamWriter.WriteLine(
                                DateTime.Now.TimeOfDay
                                + " - "
                                + strMessage
                                );
                            blnStatus = true;
                        }

                    }
                }
                catch (Exception objEx)
                {
                    //use messagebox if winforms application
                    Console.WriteLine(objEx.StackTrace);
                }
                finally
                {
                }
            }
            return blnStatus;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Logger objLogger = null;
            Stopwatch objSW = null;
            int iCount = 100;
            objSW = new Stopwatch();
            objLogger = new Logger();
            objLogger.Open();
            objSW.Reset();
            objSW.Start();
            for (int i = 0; i < iCount; i++)
            {
               objLogger.WriteToFile("Optimized" + i.ToString());
            }
            objSW.Stop();
            objLogger.Close();
            Console.WriteLine("WriteToFile - TimeElapsed");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);
            Console.ReadLine();
        }
    }
}
Step #4 - Measure the time take by the Logger class to log 100 message to the text file.In the above code Stopwatch class is used for measuring the time.
Output:
WriteToFile - TimeElapsed
TimeElapsed (Stopwatch float):4.6166ms
TimeElapsed (Stopwatch rounded):4ms
Step #5 - Analyze the advantages and disadvantages of different approaches and decide the best approach.

Write the code → Measure → Optimize the code → Measure

C# measurement tools

There are two important factor which has to be measured to identify the improvement in the code
  • Time taken to complete some operation
  • Memory usage of the application
Below is the code for measuring memory consumption.
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace StructMemoryUsage
{
    struct EmployeeStruct
    {
        public string Name;
        public int EmpId;
    }

    class Program
    {
        static void Main(string[] args)
        {
            long lngGCMemStart = 0;
            long lngGCMemEnd = 0;
            long lngProcessMemStart = 0;
            long lngProcessMemEnd = 0;

            //employee as struct
            EmployeeStruct[] objEmployee;
            int iCount;
            iCount = 100000;

            Process objProcess = Process.GetCurrentProcess();
            //Measure starting point memory
            lngGCMemStart = System.GC.GetTotalMemory(true);
            lngProcessMemStart = objProcess.PrivateMemorySize64;

            objEmployee = new EmployeeStruct[iCount];

            //Measure memory after allocating
            lngGCMemEnd = System.GC.GetTotalMemory(true);
            lngProcessMemEnd = objProcess.PrivateMemorySize64;

            for (int i = 0; i < iCount; i++)
            {
                objEmployee[i].Name = "Emp" + i.ToString();
                objEmployee[i].EmpId = i;
            }
            Console.WriteLine("Struct memory usage.");
            //memoryusage difference
            Console.WriteLine("GC Memory Use:{0} (bytes)",
                lngGCMemEnd - lngGCMemStart);
            Console.WriteLine("Process Memory Use:{0} (bytes)",
                lngProcessMemEnd - lngProcessMemStart);

            Console.WriteLine("GC Memory Start:{0} (bytes)",
                lngGCMemStart.ToString());
            Console.WriteLine("Process Memory Start:{0} (bytes)",
                lngProcessMemStart.ToString());

            Console.WriteLine("GC Memory End:{0} (bytes)",
                lngGCMemEnd.ToString());
            Console.WriteLine("Process Memory End:{0} (bytes)",
                lngProcessMemEnd.ToString());

            Console.ReadLine();
        }
    }
}
Output:
Struct memory usage.
GC Memory Use:802380 (bytes)
Process Memory Use:0 (bytes)
GC Memory Start:126592 (bytes)
Process Memory Start:8937472 (bytes)
GC Memory End:928972 (bytes)
Process Memory End:8937472 (bytes)

Note: Alternatively use perfmon->Add Counters->.NET CLR Memory counters can be used for viewing the memory consumption of selected .NET process.

Below is the code for measuring the time.
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace MeasuringTime
{
    class Program
    {
        static void Main(string[] args)
        {
            long lngStartTime = 0;
            long lngEndTime = 0;
            DateTime dtStartTime;
            TimeSpan tsTimeDiff;
            long lngSWFrequency=0;
            Stopwatch objSW;// Only from .Net 2.0

            //If the computer is kept running continuously
            //for 49 days then the Environment.TickCount would
            //start counting backwards
            //So the most significant bit is extracted
            lngStartTime = Environment.TickCount
                & Int32.MaxValue;
            System.Threading.Thread.Sleep(5000);
            lngEndTime = Environment.TickCount
                & Int32.MaxValue;

            Console.WriteLine("TimeElapsed (TickCount):{0}ms",
                lngEndTime - lngStartTime);
            //Resolution of DateTime.Now is 10+ milliseconds
            dtStartTime = DateTime.Now;
            System.Threading.Thread.Sleep(5000);
            tsTimeDiff = DateTime.Now - dtStartTime;


            Console.WriteLine("TimeElapsed (DateTime):{0}ms",
                tsTimeDiff.TotalMilliseconds);
            //Stopwatch uses the hardware timer if it
            //highresolution timer or else uses the DateTime.Now
            //To check the availability of the high
            //resolution timer use IsHighResolution property
            if (true == Stopwatch.IsHighResolution)
            {
                Console.WriteLine(
                    "HighResolutionTimer is present"
                    );
            }
            else
            {
                Console.WriteLine(
                    "HighResolutionTimer is absent"
                    );
            }

            lngSWFrequency = Stopwatch.Frequency;
            Console.WriteLine(
                "Timer frequency in ticks/second:{0}",
                lngSWFrequency);
            objSW = Stopwatch.StartNew();
            System.Threading.Thread.Sleep(5000);
            objSW.Stop();
            Console.WriteLine(
                "TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds
                );
            Console.WriteLine(
                "TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds
                );

            Console.ReadLine();

        }
    }
}

Output:
TimeElapsed (TickCount):4992ms
TimeElapsed (DateTime):5002ms
HighResolutionTimer is present
Timer frequency in ticks/second:14318180
TimeElapsed (Stopwatch float):5000.7317ms
TimeElapsed (Stopwatch rounded):5000ms

Note: Profiling tools can be used for the measuring time and memory leak.

How to write a program?

Program accepts input, performs the function and produces the output.

Accept inputs → Perform the function (logic) → Produce output

Let us try to write a simple calculator. The calculator has to support addition, subtraction, multiplication and division and also display the result.
Try to write the calculator program on a paper by following the steps below
Step #1 - Identify the user inputs.
number1
number2
operation
Step #2 - Identify the output.
result
Step #3 - Write the logic.
if operation is "add"
{
    number1+number2=result
}
if operation is "sub"
{
    number1-number2=result
}
if operation is "mul"
{
    number1*number2=result
}
if operation is "div"
{
    number1/number2=result
}
Step #4 - Display the output (result).
Now try to execute the program on the paper by following the steps
Step #1 - Accept user inputs
number1=8
number2=7
operation="sub"
Step #2 - Nothing to do in this step
Step #3 - Execute the logic
if operation is "add"
{
    number1+number2=result
}
if operation is "sub"
{
    number1-number2=result
    8 - 7 = 1(result)
}
if operation is "mul"
{
    number1*number2=result
}
if operation is "div"
{
    number1/number2=result
}
Step #4 - Display the result
Result is 1
The program works fine on the paper.
C# example- Now open Microsoft Visual Studio
or Microsoft Visual C# 2008 Express Edition and create a
console application (File → New Project → Console Application) and try to write the program as below.
using System;

namespace calculator
{
    class Program
    {
        static void Main(string[] args)
        {
            //Identify the user inputs
            float Number1;
            float Number2;
            string Operation;

            //Identify the output
            float Result=0;

            //Accept user inputs
            //can write code to get the input through the console or user interface
            Number1=8;
            Number2=7;
            Operation = "sub";

            //Write the logic
            if ("add" == Operation)
            {
            Result = Number1+Number2;
            }
            if ("sub" == Operation)
            {
            Result = Number1 - Number2;
            }
            if ("mul" == Operation)
            {
            Result = Number1 * Number2;
            }
            if ("div" == Operation)
            {
            Result = Number1 / Number2;
            }

            //Display the output
            Console.Write("Result is {0}",Result);

            //To make the console wait for the user to read the result
            Console.ReadLine();
        }
    }

}
Output:
Result is 1
The above program works fine. So now try to write the logic
or function part as class as below.
using System;

namespace ConsoleApplication6
{
    class Calc//also called as type
    {
        public Calc()//constructor
        {

        }
        //Logic as function
        public float Add(float Num1, float Num2)//function with arguments/inputs
        {
            float Result;//local variable
            Result = Num1 + Num2;
            return Result;//return Result/output
        }
        //Logic as function
        public float Sub(float Num1, float Num2)//function with arguments/inputs
        {
            float Result;//local variable
            Result = Num1 - Num2;
            return Result;//return Result/output

        }
        //Logic as function
        public float Mul(float Num1, float Num2)//function with arguments/inputs
        {
            float Result;//local variable
            Result = Num1 * Num2;
            return Result;//return Result/output
        }
        //Logic as function
        public float Div(float Num1, float Num2)//function with arguments/inputs
        {
            float Result;//local variable
            Result = Num1 / Num2;
            return Result;//return Result/output
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            //Identify the user inputs
            float Number1;
            float Number2;
            string Operation;

            //Identify the output
            float Result = 0;

            //Accept user inputs
            //can write code to get the input through the console or user interface
            Number1 = 8;
            Number2 = 7;
            Operation = "sub";

            Calc Calc1 = new Calc();//create new Calc

            //Display the inputs
            Console.WriteLine("Number1 is {0},Number2 is {1}", Number1, Number2);
            //Write the logic
            if ("add" == Operation)
            {
                //Display the operation
                Console.WriteLine("Operation is Add");
                Result=Calc1.Add(Number1, Number2);
            }
            if ("sub" == Operation)
            {
                //Display the operation
                Console.WriteLine("Operation is Sub");
                Result = Calc1.Sub(Number1, Number2);
            }
            if ("mul" == Operation)
            {
                //Display the operation
                Console.WriteLine("Operation is Mul");
                Result = Calc1.Mul(Number1, Number2);
            }
            if ("div" == Operation)
            {
                //Display the operation
                Console.WriteLine("Operation is Div");
                Result = Calc1.Div(Number1, Number2);
            }

            //Display the output
            Console.Write("Result is {0}", Result);

            //To make the console wait for the user to read the result
            Console.ReadLine();



        }
    }
}
Output:
Number1 is 8,Number2 is 7
Operation is Sub
Result is 1
JavaScript example- Now let us write the same
program in JavaScript and dhtml, so open a notepad and try to
write the program as below and save it as .html file.
<html>
    <head>
        <title>Calculator</title>
        <style>
        body{
        background:blue;
        color:white;
        }
        td{
        background:white;
        color:maroon;
        font-family:verdana;
        font-size:15px;
        }
        #cssresult{
        background:fuchsia;
        color:lime;
        }
        .cssbutton{
        background:yellow;
        }
        </style>
        <script>
        function calc(op)
        {
            //Identify the user inputs
            var number1;
            var number2;
            var operation;
            //Identify the output
            var result;
            //Accept user inputs
            number1 = (parseFloat)(document.getElementsByName("txtnum1")[0].value);
            number2 = (parseFloat)(document.getElementsByName("txtnum2")[0].value);
            operation=op;
            //Write the logic
            if(operation == "add")
            {
                result = number1 + number2;
                //Display the result
                document.getElementsByName("txtresult")[0].value=result;
                //Display the result (dhtml)
                document.getElementById("divResult")
                .innerHTML="<b>Result is "+result+"</b>";
                alert("Result is "+result);
            }
            if(operation == "sub")
            {
                result = number1 - number2;
                //Display the result
                document.getElementsByName("txtresult")[0].value=result;
                //Display the result (dhtml)
                document.getElementById("divResult")
                .innerHTML="<b>Result is "+result+"</b>";
                alert("Result is "+result);
            }
            if(operation == "mul")
            {
                result = number1 * number2;
                //Display the result
                document.getElementsByName("txtresult")[0].value=result;
                //Display the result (dhtml)
                document.getElementById("divResult")
                .innerHTML="<b>Result is "+result+"</b>";
                alert("Result is "+result);
            }
            if(operation == "div")
            {
                result = number1 / number2;
                //Display the result
                document.getElementsByName("txtresult")[0].value=result;
                //Display the result (dhtml)
                document.getElementById("divResult")
                .innerHTML="<b>Result is "+result+"</b>";
                alert("Result is "+result);
            }
            if(operation == "clear")
            {
                document.getElementsByName("txtnum1")[0].value="";
                document.getElementsByName("txtnum2")[0].value="";
                document.getElementsByName("txtresult")[0].value="";
                document.getElementById("divResult").innerHTML="";
            }
        }
        </script>
    </head>
    <body >
        Calculator
        <table border="2">
        <tr>
        <td>Number 1</td>
        <td><input type="textbox" name="txtnum1"></td>
        <td class="cssbutton">
            <input type="button" value="Add" onclick="calc('add')">
        </td>
        </tr>
        <tr>
        <td>Number 2</td>
        <td><input type="textbox" name="txtnum2"></td>
        <td class="cssbutton">
            <input type="button" value="Sub" onclick="calc('sub')">
        </td>
        </tr>
        <tr >
        <td>Result</td>
        <td id="cssresult"><input type="textbox" name="txtresult"></td>
        <td class="cssbutton">
            <input type="button" value="Mul" onclick="calc('mul')">
        </td>
        </tr>
        <tr>
        <td colspan="2" class="cssbutton">
            <input type=button value="Clear" onclick="calc('clear')">
        </td>
        <td class="cssbutton">
            <input type="button" value="Div" onclick="calc('div')">
        </td>
        </tr>
        </table>
        <div id="divResult"></div>
    </body>
</html>

Output:
Result is 1

Note: Extend the above program to accept input through the user interface and support more features.

Happy programming!

Note: Please read the guidelines listed in this website for efficient programming.

Return variable

Initialize the failure status value to return variable. So that even if the success value is not set to the return value, the call would always fail and the developer can debug and fix the issue during unit testing or development.

C# example- In the below example blnStatus is initialized to false.
//should not allow empty string or null string
public bool SetName(string strName)
{
    bool blnStatus = false;
    if (strName != string.Empty && strName != null)
    {
        Name = strName;
        blnStatus = true;
    }
    return blnStatus;
}

Rule: Initialize the return variable to failure status value.

Rule: Make sure return variable is set to success status value at the right place.

Single return

Avoid multiple return statements.
C# example- Code with multiple return statement.
//should not allow empty string or null string
public bool SetName(string strName)
{

    if (strName != string.Empty && strName != null)
    {
        m_strName = strName;
        return true;
    }
    return false;

}

C# example- Code with single return statement.
//should not allow empty string or null string
public bool SetName(string strName)
{
    bool blnStatus = false;
    if (strName != string.Empty && strName != null)
    {
        m_strName = strName;
        blnStatus = true;
    }
    return blnStatus;
}

Rule: Have single return statement.

Thread safety

If you are developing a multi threaded application. Make sure you code is thread safe. For better performance try to protect only the resource being accessed for reading or writing across threads and some lines of code.

C#- Make sure the mutex, monito or semaphore, if used, are released properly.

Note: A semaphore with a capacity of one is similar to mutex or lock. Semaphore is thread-agnostic because it has no owner. Any thread can call release a semaphore, but with lock and mutex, only the thread that acquired the resource can release it.


C# example- Below Logger class covers using lock and monitor, releasing monitor and protecting only the resource being shared across threads.
class Logger
{
    public string FilePath { get; set; }
    private StreamWriter m_objStreamWriter = null;
    private object m_objLocker;
    public Logger()
    {
        m_objLocker=new object();
        FilePath = @"d:\log.txt";
    }
    public bool Open()
    {
        bool blnStatus = false;
        try
        {
            m_objStreamWriter = new StreamWriter(FilePath, true);
            blnStatus = true;
        }
        catch (Exception objEx)
        {
            Console.WriteLine(objEx.StackTrace);
        }
        finally
        {
        }
        return blnStatus;
    }
    public bool Close()
    {
        bool blnStatus = false;
        try
        {
            if (m_objStreamWriter != null)
            {
                m_objStreamWriter.Close();
                blnStatus = true;
            }
        }
        catch (Exception objEx)
        {
            Console.WriteLine(objEx.StackTrace);
        }
        finally
        {
        }
        return blnStatus;
    }
    //make sure Open is called before calling WriteToFile
    //make sure Close is called once all logging is done
    public bool WriteToFile(string strMessage)
    {
        bool blnStatus = false;
        if (strMessage != string.Empty && strMessage != null)
        {
            try
            {
                lock (m_objLocker)
                {
                    if (m_objStreamWriter != null)
                    {
                        //logs only the time and not the date
                        m_objStreamWriter.WriteLine(
                            DateTime.Now.TimeOfDay
                            + " - "
                            + strMessage
                            );
                        blnStatus = true;
                    }

                }
            }
            catch (Exception objEx)
            {
                //use messagebox if winforms application
                Console.WriteLine(objEx.StackTrace);
            }
            finally
            {
            }
        }
        return blnStatus;
    }
    //make sure the StreamWriter is closed
    //make sure thr Monitor is exit
    public bool WriteToFile_Local(string strMessage)
    {
        bool blnStatus = false;
        StreamWriter objStreamWriter = null;
        if (strMessage != string.Empty && strMessage != null)
        {
            try
            {
                Monitor.Enter(m_objLocker);
                objStreamWriter = new StreamWriter(FilePath,
                    true);
                //logs only the time and not the date
                objStreamWriter.WriteLine(
                    DateTime.Now.TimeOfDay + " - " + strMessage
                    );
                objStreamWriter.Close();
                Monitor.Exit(m_objLocker);
                blnStatus = true;
            }
            catch (Exception objEx)
            {
                //use messagebox if winforms application
                Console.WriteLine(objEx.StackTrace);
                if (objStreamWriter != null)
                {
                   objStreamWriter.Close();
                }
                Monitor.Exit(m_objLocker);
            }
            finally
            {
            }
        }
        return blnStatus;
    }
    //exception has to be handled by the caller
    //can not be unit tested using UnitTestingTool class
    public void WriteToFile_Local_Using(string strMessage)
    {
        StreamWriter objStreamWriter = null;
        if (strMessage != string.Empty && strMessage != null)
        {
            //private member variable
            lock (m_objLocker)
            {
                using (objStreamWriter =
                    new StreamWriter(FilePath, true))
                {
                    //logs only the time and not the date
                    objStreamWriter.WriteLine(
                        DateTime.Now.TimeOfDay + " - " +
                        strMessage
                        );
                }
            }
        }
    }
}

Rule: Write thread safe code if your application is multi threaded.

Rule: Protecting only the resource being shared across threads or processes.

Rule: Releasing the mutex, monitor or semaphore if used.

Release resources

Make sure you release all the used resource. Below are some of the examples
  • closing the database connection
  • closing the file handle
  • closing the communication port (RS232, Socket, USB, UDP, etc)
C#- If you are using try catch block, make sure you have
the finally block to release the resources. In some case the resource may
have to be released in catch block. Otherwise the “Using”
(gets compiled to try/finally block) block can be used.

C# example- Below code has StreamWriter and try/catch/finally block.
//make sure the StreamWriter is closed
//make sure thr Monitor is exit
public bool WriteToFile_Local(string strMessage)
{
    bool blnStatus = false;
    StreamWriter objStreamWriter = null;
    if (strMessage != string.Empty && strMessage != null)
    {
        try
        {
            Monitor.Enter(m_objLocker);
            objStreamWriter = new StreamWriter(FilePath, true);
            //logs only the time and not the date
            objStreamWriter.WriteLine(
                DateTime.Now.TimeOfDay + " - " + strMessage
                );
            objStreamWriter.Close();
            Monitor.Exit(m_objLocker);
            blnStatus = true;
        }
        catch (Exception objEx)
        {
            //use messagebox if winforms application
            Console.WriteLine(objEx.StackTrace);
            if (objStreamWriter != null)
            {
               objStreamWriter.Close();
            }
            Monitor.Exit(m_objLocker);
        }
        finally
        {
        }
    }
    return blnStatus;
}

C# example- Below code has StreamWriter and Using block.
//exception has to be handled by the caller
//can not be unit tested using UnitTestingTool class
public void WriteToFile_Local_Using(string strMessage)
{
    StreamWriter objStreamWriter = null;
    if (strMessage != string.Empty && strMessage != null)
    {
        //private member variable
        lock (m_objLocker)
        {
            using (objStreamWriter =
                new StreamWriter(FilePath, true))
            {
                //logs only the time and not the date
                objStreamWriter.WriteLine(
                    DateTime.Now.TimeOfDay + " - " + strMessage
                    );
            }
        }
    }
}

Note: When you are done with the reference variable it need
not be set to null, because once a variable fall out of scope,
it is popped from the stack and the reference is removed.

Rule: Close the database connection.

Rule: Close the communication port.

Rule: Close the file handle.