Introduction

In this article, I'll speak a little about some issues that I believe are relevant to all modern programmers. However the examples will be written in ASP/VBScript+JScript, so I'll be coherent with the purpose of these articles, which will showcase ASP as an extremely versatile and efficient environment. Here is the list of articles:

  1. ASP, a misinterpreted technology
  2. Event-Driven-Programming and lambda function in ASP/VBScript.
  3. TDD (Test Driven Development) in ASP/VBScript.
  4. Languages: Based on Objects and Object Oriented.
  5. Object Oriented in ASP/VBScript "Hackers way".
  6. "Scripting Components", the ace in the role.
  7. Caching: the concept of DRY (Don't Repeat Yourself) applied to ASP.

If you're reading one of my articles for the first time, I strongly recommend that you read the previous ones first, because I'm trying to lead you into a great abstraction, presenting the topics incrementally.

Event-Driven-Programming

Event-Driven-Programming, also known as event-based programming, is a programming paradigm in which the program execution is affected by events (generally detected by sensors).

This way of programming is, in my humble opinion, the base of all sophisticated UI(User Interface) systems. For example, let's take look at the RocketDock a small menubar similar to the Mac OS X one that everybody loves:

RocketDock picture

It never opens a dialog asking: "Please place the mouse over an icon and click". It simply has a sensor that warns "Hey, program, I detected a mouse enter at (x,y) of the bar" and when this message is received, the program starts a zoom effect and shows the label of the icon in position. This may seem like a silly example, but it's a good illustration of the difference between batch programming and event-driven-programming.

It's important for a web programmer to know event-driven-programming because one of the striking features of the Web 2.0 is the big amount of widgets that are part of the RIAs(Rich Interface Application) - that wow, oh, wow! sites.

Another thing that should be noticed is that the programming paradigms aren't mutually exclusive, i.e. a language and, as a consequence, an application, can carry multiple paradigms. A program can be purely in batch, purely in event-driven, or can contain elements of both. Therefore, it's possible to create programs that are object/procedural oriented and event/batch oriented at the same time. An experienced software architect will know which paradigm is the best choice for each feature he needs to create.

Although this form of programming can be implemented in any language, it's easier if you are using languages with functional concepts such as JScript, Lisp (the second oldest language of our history) or Haskell among others. In the following examples I'll show how to program:

  1. Using just VBScript.
  2. Making a simple bridge with JScript to use the lambda concept that it has (here, a good exercise is to use the Python's lambda concept to achieve the same goal).

Note: The second example is the reason why I consider the ASP extremely versatile. It shows a proof of the concept demonstrated in the first article.

Lambda function

For those who still don't know about it, the lambda function is an interesting feature that was born with Lisp and allows you to define and use functions during runtime. This is one of features that makes it easier to develop artificially intelligent programs (think of a recursive algorithm that generates, interprets and executes functions to generate, interpret and execute tasks and learns something important during the process).

Let's code

Using the CustomEvent class (uncommented version), which I wrote for AXE(ASP Xtreme Evolution), but works out-of-the-box and is MIT licensed:

<%

class CustomEvent
   
    public classType
    public classVersion
   
    public Owner
    private Handlers
    public Arguments
   
    private sub Class_initialize()
        classType    = typename(Me)
        classVersion = "1.0.0"
       
        set Handlers  = Server.createObject("Scripting.Dictionary")
        set Arguments = Server.createObject("Scripting.Dictionary")
    end sub
   
    private sub Class_terminate()
        Handlers.removeAll()
        Arguments.removeAll()
        set Handlers  = nothing
        set Arguments = nothing
    end sub
   
    public sub addHandler(fn)
        select case typename(fn)
            case "JScriptTypeInfo"
                set Handlers.item(fn.toString()) = fn
            case else
                set Handlers.item(fn) = getRef(fn)
        end select
    end sub
   
    public sub removeHandler(fn)
        set Handlers.item(fn) = nothing
        Handlers.remove(fn)
    end sub
   
    public sub fire()
        dim fn : for each fn in Handlers
            Handlers.item(fn)(Me)
        next
    end sub
   
    public function revealArguments()
        revealArguments = ""
        dim arg : for each arg in Arguments
            revealArguments = revealArguments & ", " & arg
        next
        revealArguments = mid(revealArguments, 3)
    end function
   
end class

%>
<script language="javascript" runat="server">
function lambda(f) {
    if(/^functions*([ a-z0-9.$_,]*)s*{[Ss]*}$/gim.test(f)) {
        eval("f = " + f.replace(/r/g, '').replace(/n/g, ''));
        return f;
    } else {
        return function() {};
    }
}
</script>

You can create events in your class like in the example below, which will be used in the examples 1) and 2).

<%

class ClassWithEvents
    public classType
    public classVersion
   
    public onComplimentBefore' [1]
    public onComplimentAfter
   
    private sub Class_initialize()
        classType    = typename(Me)
        classVersion = "1.0.0"
       
        set onComplimentBefore = new CustomEvent : set onComplimentBefore.Owner = Me' [2]
        set onComplimentAfter = new CustomEvent : set onComplimentAfter.Owner = Me
    end sub
   
    private sub Class_terminate()
        set onComplimentBefore = nothing' [3]
        set onComplimentAfter = nothing
    end sub
   
    public sub compliment(firstname, lastname, nickname)
        onComplimentBefore.Arguments.item("firstname") = firstname' [4]
        onComplimentBefore.Arguments.item("lastname")  = lastname
        onComplimentBefore.Arguments.item("nickname")  = nickname
       
        call onComplimentBefore.fire()' [5]
        Response.write("Method compliment called." & vbNewline)
        call onComplimentAfter.fire()
    end sub
   
end class

%>

Example 1

Using the ClassWithEvents defined above, you can create objects with events in VBScript:

<code><pre><%

sub ev_onComplimentBefore(ev)' [6]
    Response.write("Event onComplimentBefore has been fired. I was really expecting this method to say: 'Hello World " & ev.Arguments.item("firstname") & " " & ev.Arguments.item("lastname") & " (" & ev.Arguments.item("nickname") & ")'" & vbNewline)
end sub

sub ev_onComplimentAfter(ev)
    Response.write("Event onComplimentAfter has been fired" & vbNewline)
end sub

dim CwE : set CwE = new ClassWithEvents
call CwE.onComplimentBefore.addHandler("ev_onComplimentBefore")' [7]
call CwE.onComplimentAfter.addHandler("ev_onComplimentAfter")
call CwE.compliment("Fabio", "Nagao", "nagaozen")
set CwE = nothing

%></pre></code>

The code above should return:

Event onComplimentBefore has been fired. I was really expecting this method to say: 'Hello World Fabio Nagao (nagaozen)'
Method compliment called.
Event onComplimentAfter has been fired

Below are the footnotes that I left in the source code:

  1. Defining the events.
  2. Initializing the events as CustomEvent and assigning a pointer to the class instance through the Owner property.
  3. Releasing the memory of events created in the step 2.
  4. Defining the arguments of the event.
  5. Warning the sensor that the event occurred.
  6. Configuring actions for an event.
  7. Configuring the sensor to observe an event.

Example 2

Ok, the example 1 was fine, but most people used to event-driven-programming will complain about those subroutines in note 6, which is natural, because it's not intuitive. After all, if the events are related to an object and only to it, why not to define them inside the object itself? Well, the problem is that the VBScript doesn't provide any way to do it inside the object. The natural alternatives, found in other languages, are:

  1. Either you extend the class ClassWithEvents into another class that has the definitions of the actions to the events and then create an instance of this new class, which is impossible with the concepts of objects in VBScript;
  2. Or you use the lambda function concept, which also doesn’t exist in VBScript.

So, what can we do? Surrender to the obvious limitation of the language? Never! After all, it doesn’t help changing the language, since every language has limitations, right?

The solution is easier than it looks. Do you speak JScript? Python? Haskell? Ow, so does ASP! These languages have support for functional concept? Yes!! Okay, problem solved!

An elaboration: for those who haven't realized it yet, together with the definition of class CustomEvent, I also created a global function in javascript (the same as JScript) named lambda. This function receives the definition of a function, interprets and returns the function interpreted. Javascript is such awesome that incorporates the lambda concept at it's core, and it uses lambda without a reserved word for it (different than Python and C#). This function, inside ASP, isn't global just for JScript, but global for the entire application, i.e. you can invoke it from VBScript. With this new solution at hand, we can turn the example 1) into the following:

<%

dim CwE : set CwE = new ClassWithEvents
call CwE.onComplimentBefore.addHandler(lambda("function(ev){ Response.write('Event onComplimentBefore has been fired. I was really expecting this method to say: 'Hello World ' + ev.Arguments.item('firstname') + ' ' + ev.Arguments.item('lastname') + ' (' + ev.Arguments.item('nickname') + ')'\r\n') }"))
call CwE.onComplimentAfter.addHandler(lambda("function(ev){ Response.write('Event onComplimentAfter has been fired') }"))
call CwE.compliment("Fabio", "Nagao", "nagaozen")
set CwE = nothing

%>

That also prints the same message of example 1 on your browser. It's much better now, huh? And much more intuitive.

Summary

The paradigm of Object-Oriented-Programming together with Event-Driven-Programming, allows the programmer to create environments that are very similar to the way we understand objects and events in our physical world. For example: we are used to cross the street when the lights are green and stop when it's red. A programmer trying to model this environment can create, for example, the classes "Person" and "TrafficLight". The "Person" has a method called "walkTo(Place)" that tells it to go to a certain place. This method has a sensor "onRedTrafficLight" that triggers the procedure "stop". When the "Person" detects "onGreenTrafficLight" it can proceed with it's "walkTo(Place)" again.