Don't wanna be here? Send us removal request.
Text
Programming Paradigms
So I was thinking, in the previous post I chatted on time spent creating OO for classic ASP. Why do I want to do OO? What is OO different than other dogmas? Younger developers will not understand the question, because OO is all they were exposed to. But I saw Assembler, Pascal (procedural), C, then VB6, Delphi and C++, then Java and DotNet... And it seems all languages are gravitating towards OO. Why? And on a deeper level, if we can understand where we came from in relation to where we are, we can see where it is heading...
The first time OO was introduced to me it was under the mantle of "this is the way people think". Well I did not buy it, since I thought procedural. What's the difference?
In procedural languages you have procedures/functions and they operate on data. It a bit like speaking verbs, and then nouns: Kick ( the_ball ). Very soon you realize that you need:
KickTheBall (ball'detail), KickTheCat (cat's detail), KickTheBucket ( uuhh. ).
And then they invented modules. Modules are groupings of procedures, so that you do something like:Kick.TheBall(), Kick.TheCat(),,, where Kick was a module. You could also change the system around and have a module for Ball, Cat, Bucket, and then had Kick() in each. There is no objects here, this is just groupings for the procedure names, and these groupings coincided with the files in which the source was saved.
What we do see is a hierarchical definition - a tree structure - that leads to the procedure we are looking at. When OO came, they joined the data into the same tree structure. So in an early procedural environment, procedures were a list of words in a dictionary. With OO we changed the dictionary to tree structure. Why? So we can quicker find the item we are looking for... in our mind and in the source. Why is this important?
Because of a concept I call BIG CODE. You may have heard of BIG DATA? Well here's BIG CODE. All systems grows and evolve, until they reach a point where humans cannot understand them anymore, then they wither and die. The biggest the system can grow, depends on many factors, for example the intelligence of the developer (the size of the bucket to hold the info), the complexity of the technology ( how much info you need to define a concept ), and the complexity of the concept (how much doodoo needs to be hauled).
I have seen the effect of technology on systems - C/C++ is complex. Java slightly less so, DotNet is simpler, and VB6 more simpler, and the most simplest, classic ASP web development. Many people would relate complexity to power, and therefore think that C/C++ is the most powerful. Well, what is the most powerful, a passenger airliner, or an F16? Power is "Can you do with it what you want, easily, quickly, and good?". I once saw on a restaurant's door: we do service quick, cheap, or well - you can choose two of the three.
Big code, is when you so much code, that are getting scared to change anything. Even if you know the system well.
Now I want to divert into another area of information technology - search algorithms. Well not the exact algorithms, more the strategy behind it. The worst case scenario is having 32 million addresses, and you are looking for who lives in 32 Third Avenue, Boksburg. On average you will spent 16 million checks, to find the address.
So the first enhancement, indexes, require that you sort the addresses. This you do once, and thereafter you spent on average checking only 12 addresses before you get the result. Quite an improvement.
Then someone invented indexes on countries, cities and suburbs, and you could create a hierarchy of sorted lists. And it all seems even better.
Someone else also invented the tree structure - and used it to store files on a computer. So you can find it quicker...they say. Well, somehow you find yourself searching sequentially through the hundreds of folders on the PC now. And you build a tools to do this for you. We now call this tool intellisence. The IDE uses whatever you typed so far, and tries to predict, or give you selection options for the next branch in the tree.
OO became the very next mechanism, to have the computer find what you are looking for. Indexed on some mental scheme. And this is where it also fails. One of the biggest drawback of OO is the larger investment you have to make upfront, in learning the structure of how the code is organized.
And typically human, we all want to organize stuff in different ways.
So again, the file-system structure on PCs are us one upfront - they invented "links" or "shortcuts" or "virtual folders" etc. all with which to define a structure that makes sense to me, while not affecting the actual structure, or other people's structures.
But I want to go a step further. Because there is a very good example of how things can become even worse. Think of "Google". It contains billions of pages of information, and a search through it immediately lands you with an odd million hits, 99.9% irrelevant, but still, somehow it seems there is a lesson to be learned here.
Google has no apparent structure - in fact, if you even have 18 exa-byte of data items, you can find the correct one with on average 30 comparisons - indexing, not structure, is the solution.
I believe that building more and more complex OO structures will just run into the same BIG CODE problems - it just takes a bit longer.
What we really need is a way in which to index procedures, and how they operate on data, in a way as to make searching very easy. In fact so easy, that the PC can do it for you.
Enters an old concept that never seemed to get beyond birth - service orientated architecture.
Here the idea is that all "services" are "catalogued", and you can "interrogate" the system to "find" a "service". All good ideas, but why is it not happening?
Because the investment getting into OO is too large to simply "chuck" it?
Imagine all procedures being indexed by input required, export provided, and with keywords. Imagine a programming environment where the system decides which procedure to call...
This is almost like the value-type-function overloading I did in ASP++ for classic asp. It involves calling the correct function based on the type of data used to call the function.
Imagine extending this to call functions that did not exist during compile time... Imagine it extended not just to overloaded functions, but to the specific function required as well..
I'm thinking.....
I'm thinking of a library of classes, functions, etc., indexed by calling names, files, parameters, etc. And all calls to it going through this "library". Sounds like a Windows registry?
But one for code...
Classic ASP with OO: full inheritance
Classic ASP with OO: full inheritance
Harry Marx
OK - I added the source here for you as well - and if you want to read my self-praise thereafter, you are warned.
http://www.nimbushost.co.za/sandbox/asp/aspp.asp?fname=example
PS. I found some major issues in the code and fixed it… working even better now :-)
PS2. This was done in 2015 - now 2018 - major upgrade available - soon will add a new link.
Note - this is not just about how nice classic ASP is, it is also about enhancements of it.
Topic 1: Classic ASP - is it still alive?
You may think I’m mad, but I will make a statement and support it with some interesting facts… “Classic ASP is among, if not THE, most advanced programming language there ever was. ”
Now the reasons I say so…
Imagine you have a programming language that CANNOT do some stuff.
Take for example Classic ASP, one of the scripting language used in IIS for web pages (although not “supported” any more…)
There are stuff you cannot do with classic ASP, for example its class structures does not have inheritance and therefore not polymorphism. Imagine your pet language is JAVA, yes, it also has limitations - no multiple inheritance. And so does all languages have some shortcoming.
Now, my question to you is, can YOUR pet language be “extended” to do what they say it can’t?
I will stick to Classic ASP for now.
My first problem was runtime includes. An include is like a “module”, another source file, that IIS pulls into the main source file. You specify the name of the file where you want it to be included, and it is compiled into your source exactly where you want it. Nice.
But my problem was that I had many of these, and they are becoming co-dependent. A and B used C (each included C), and if you included A and B into main.asp, you generally get “name redefinition errors”.
So can Classic ASPs do runtime includes, and thereby test is C is already included and then NOT include it a 2nd time? NO, it can’t. Oops, sorry, it CAN!
For example, a very naïve implementation:
Dim fso, f, alreadydone
if instr(alreadydone, “myRuntimeInclude.INC”) = 0 then
alreadydone = alreadydone & "myRuntimeInclude.INC"
Set fso = Server.CreateObject(“Scripting.FileSystemObject”)
set f = fso.OpenTextFile(“myRuntimeInclude.INC”, 1)
source = f.ReadAll
f.close
set f = Nothing
set fso = Nothing
ExecuteGlobal source
end if
Now you could package this in a nice SUB, do error handling, etc., and put it inside its own include, and you have the beginnings of runtime includes. In particular, you can add a global variable to this include, into which you add the names of the files included, and NOT include them a 2nd time.
So with a few simple lines of code, ExecuteGlobal enabled Classic ASP to do something it could not.
For example, doing a runtime include like this, will of course not do the nested static includes. No problem - turn the INCLUDE function into a recursive one, and do the static includes also runtime!
Does this makes everything slower? With todays fast servers and cached hard drives etc? Yes, slightly, but just throw more hardware at it and we are OK again - ha ha ha. Yes it is slower, but if you want speed - you would not have gone for classic asp. C++ comes to mind.
And what about HTML and scripting intermixed, as classic asp developers usually does?
No problem - execute the script and print the html as you parse the tags in the include!
Now I will of course add some more notes here, and finally provide you with the source code, but if you are wondering what the final product does, here are a few features:
* dynamic includes
* inheritance - multiple inheritance in fact
* private / inherited methods / properties
* polymorphism
* try - finally - catch blocks
* optional parameters
* function overloading
Thinking about function overloading… Classic VB, being practically a non-typed language, actually is “typed” like any other language. The difference is that in languages like C, pascal, java, dotnet etc., you define the variable’s type, and it is fixed. In Classic ASP, the type of a variable is NOT fixed, and it changes according to the type of data in it - much more dynamic than ANY other language I know of. All other languages resolve the overloading at compile time, which is quicker, but still static. Classic ASP, if it had overloading, would have had to do the binding to the correct version of the overloaded method, at runtime - totally dynamic.
Yes, the example source I added here does ALL of the above!
Inheritance
So lets tackle the difficult issues, firstly inheritance:
Imagine you want to inherit from Parent. The ideal would be that you can simply in the ChildClass say:
#inherits filename
where filename contains a class definition with the same name as the file. OR,
#inherits classname in filename
where the file may contain multiple classes. (Or #inherit classname, where the file is assumed to have the same name.)
In theory all the runtime include will have to do is to read the body of the parent class and insert it into the child class’s body, right?
It should drop the “class classname” and “end class” declarations from the parent of course.
This was simple. To implement this was in fact just 26 lines of code…
What about private and public items in a class? Well the words “private” and “public” are already used in classic ASP, so why not extend it to OO directive?
#private initiates a section of not inherited properties and methods, and must be followed with
#public which switches inheritance on again.
To implement this is a breeze - all you do is cut the parts in the Parent source between #private and #public.
To implement this was in fact just 7 lines of code…
What about #abstract methods? A one liner! Replace the #abstract tag with ThrowCustomError “abstract method not defined”.
So what happens if the parent has a method “Display” and the child attempts to override it? You will get two definitions of Display in the childe class, and it will not compile - Name redefinition error.
This is a good thing! Because now you know you are trying to override a parent ’s method.
The way to allow this is to use #overrides or #extends This will flag the assembler to drop the Display method from the parent definition, or to keep it with an adapted name parent_Display(). Simple, but in order to make provision for properties, subs functions, etc., this took much more code to implement, exactly 45 lines.
This #overrides tag does introduce a slight deviation from the normal OO conventions. It means you cannot call the parent’s Display method inside the Child method. All the overridden methods are not available. But there is an easy fix if this is actually required. Many time you would inside a child’s method do some action, and then call the parent’s method with the same name. This is very much standard practice.
The #extends tag causes the parent’s class to be renamed before it is added into the child class. You can call the inherited method with parent_display(). Why did I do it like this? Read on.
So all in all, it took exactly 90 lines of code, in the runtime include class, to enable the gist of OO into classic ASP. I am thinking, this is why MS has dropped support for classic ASP - it is simply too powerful…. ;-)
To recap, we implemented:
#inherits
#private
#public
#overrides
#extends
#abstract
…. in about 90 lines of classic ASP code.
And there is a small bonus. If you carefully check the code, you will notice that if A inherits from B, and B from C, all the “parents” are assembled into the source if A. The runtime include does not differentiate between who is doing what inheritance. This means you can actually have a child class inherits from multiple parents!!! You can define a chile and say:
class Child_class
#inherits A
#inherits B
…
end class
VERY few languages can do this! And that is why the #extended classes are renamed for the parent class. You can now call A_display() or B_display(), inside the child.
And you also get the case where A inherits B, which inherits C, and you want to call C_display() in A!
..now that is something to digest.
polymorphism
This is one of the complexities of OO that very few people understand. I will explain it as simple as I can.
Imagine you have two different types of objects, a square, and a circle. They are derived from “Form”. Now you can define an object of type Form, and treat it as a container, in which a Square or a Circle is instantiated. Now you can call the container’s Dsiplay() method, and polyM allows the correct Display method to be invoked, relative to if the container contained a Square or Circle.
At compile time, the compiler does not know which, or even if the display method is implemented.
Yet at run time, it calls the correct method!
You can have a function that takes Form as parameter, and inside the function call the Form.display method. Depending if the argument provided was a circle or square, the correct method is called.
This is in other words runtime binding or linking.
Normally as the example went, you require a “parent” class, which is often an abstract class, to act as type (container) for the derived classes. And normally you can only do this type of runtime linking, if the parent class defines a method (can be abstract) with this name.
But, the way in which this OO implementation works - you don’t need either…!? because classic ASP is un-typed.
I can define a function that accepts a parameter:
Sub doDisplay(Obj) Obj.Display End sub
This is perfectly “compilable” in classic ASP, even though the class is never defined for Obj. Of course trying to execute it with doDisplay 10 will throw an error, because 10 does not have a Display method.
However, I can call this sub with ANY object, regardless of parentage, as long as the object has a Display method. And it will call the correct method - polymorphism without the overhead of an abstract method, or even a container class!
Heresy!
try-catch blocks
Now this is a tougher one. We want something like:
Try
a = 1 a = a/0
a = 2 Finally a=0 Catch Response.write “ERROR: div/0<br>” End try
Note the order of the finally and catch blocks. I swapped these for reasons explained later…
The issues is that classic ASP only provides us with the “on error resume next” mechanism.
I played around with some ideas, and the best I came up for now is to do it with a limitation - you cannot do a do-loop inside the try-catch block.
This is because I use an EXIT DO to jump out of the try-block.
So a simple solution is to translate the code into something like:
on error resume next Do
a = 1: if err.number<>0 then exit Do a = 1/0: if err.number<>0 then exit Do
a = 2: if err.number<>0 then exit Do loop until True a=0 select case err.number
Case 0
case else Response.write “ERROR: div/0<br>” end select
Err.Clear
on error goto 0
To get this working was a bit more difficult, it took about 66 lines of code.
Still, its working…
Arrays
I played around with [] brackets being replaced by array(). This is not very useful, but still its working.
For examp:
function foo( p )
dim pp
for each pp in p
response.write pp & “<br>”
next
end function
This you can then call with foo[], foo[1] or foo[1,2,3].
Function overloading
I started implementing function overloading, using the variable name, and an assigned type, as in : dim xxx #as myInt, where myInt could be ANY symbol. This I will call Variable Type Overloading. I implemented it as a global setting, and the value inside the variable does NOT carry the type with. Wherever xxx is used in the page, in all the includes as well, it is assumed to be of type myInt. This type has absolutely no effect on execution of any normal classic asp code, and only comes into affect when you overloaded a function/sub/property using Variable Name overloading: function foo(X #as myInt) can only be called now with xxxas input argument.
This is all done at compile time.
Take note that the variable type is GLOBAL, to all code underneath a runtime include, and all static includes inside the runtime include. This works for function, subs and properties, but I have not debugged it well.
Rather then I realized that classic ASP is not a type-less language, it merely hides the type from the developer, and as a bonus, the type of the variable can indeed be changed.
a = “string” ‘a’s type is String
a = 1 'a’s type is now Integer
This is HUGE - I know of no other language that allows variable’s types to change runtime, well other than when using polymorphism. So I realized that there is a 2nd form of function overloading possible: Value Type Overloading. And this has me excited.
With value type overloading, binding to the correct version of the function/sub/property is based on the data type in the variable, runtime! This is of course not achieved without overhead, as all runtime binding (even polymorphism) requires overhead. Yet it is simple and quick.
One important constraint to notice is that you CANNOT intermix variable type overloading and value type overloading in the same function. Keep them apart. This is because the one happens in the pre-processor, and the value type overloading happens runtime.
Variable type overloading is based on the actual symbol used for the data argument, while value type overloading is on the actual type of data being passed.
Value based overloading is local to within a class, or global outside all classes in a runtime include, and all nested includes. You can have the same function name as a class method, and as a global function, but they will be overloaded separately. Within a class, if you have two versions with the same pattern, you will get name redefinition errors, as the function name is merged with the pattern, and the combination is not unique. Functions that are inherited, are also pushed into the value type overload handler stack. If a parent’s and child’s function name and pattern are the same, you will get name redefinition errors.
There are a few constraints ito overloading:
*All versions of the function/property/sub must be of the same definition - they must be subs, or functions, or properties - you cannot mix these. All must public/private. Only a GET and a LET property can have the same overloaded name, any other will cause compile errors.
*Another silly constraint is that the definition of the method’s name and parameters
must be in the same line, no line continuation character.
*Valid types are all types as returned by TypeName(): Byte, Integer, Long, Single,
Double, Currency, Decimal, Date, String, Boolean, Empty, Null, Object, Unknown,
Nothing, Error or the class name of an object.
You can also overload the return value of a getter or function. The return type will not be matched to the current type of whereto the value is returned, instead you have to tag the function/getter call itself with a type tag ex.: X = myFunc(Y) #of string. Only patterns that is tagged to return a string, will match to this call. Take note - the return type tag is not validated against the actual value returned either. So if function myFunc(Y) #of String actually returns a n integer, the system will not see this as an error.
Also if you call myFunc with no type tag, as in X = myFunc(Y), it will match - if the type is omitted when calling the function, the return type of the overloaded function is ignored.
ooo
So tell me classic ASP is not powerful. To do all this, we needed just over 1000 lines of code.
By the way, I work at one of the largest universities in the world, and this whole runtime include concept, is forming the base of its current IIS web sites. In other words, it does work :-)
1 note
·
View note
Text
Classic ASP with OO: full inheritance
Classic ASP with OO: full inheritance
Harry Marx
OK - I added the source here for you as well - and if you want to read my self-praise thereafter, you are warned.
http://www.nimbushost.co.za/sandbox/asp/aspp.asp?fname=example
PS. I found some major issues in the code and fixed it... working even better now :-)
PS2. This was done in 2015 - now 2018 - major upgrade available - soon will add a new link.
Note - this is not just about how nice classic ASP is, it is also about enhancements of it.
Topic 1: Classic ASP - is it still alive?
You may think I'm mad, but I will make a statement and support it with some interesting facts... "Classic ASP is among, if not THE, most advanced programming language there ever was. "
Now the reasons I say so...
Imagine you have a programming language that CANNOT do some stuff.
Take for example Classic ASP, one of the scripting language used in IIS for web pages (although not "supported" any more...)
There are stuff you cannot do with classic ASP, for example its class structures does not have inheritance and therefore not polymorphism. Imagine your pet language is JAVA, yes, it also has limitations - no multiple inheritance. And so does all languages have some shortcoming.
Now, my question to you is, can YOUR pet language be "extended" to do what they say it can't?
I will stick to Classic ASP for now.
My first problem was runtime includes. An include is like a "module", another source file, that IIS pulls into the main source file. You specify the name of the file where you want it to be included, and it is compiled into your source exactly where you want it. Nice.
But my problem was that I had many of these, and they are becoming co-dependent. A and B used C (each included C), and if you included A and B into main.asp, you generally get "name redefinition errors".
So can Classic ASPs do runtime includes, and thereby test is C is already included and then NOT include it a 2nd time? NO, it can't. Oops, sorry, it CAN!
For example, a very naïve implementation:
Dim fso, f, alreadydone
if instr(alreadydone, "myRuntimeInclude.INC") = 0 then
alreadydone = alreadydone & "myRuntimeInclude.INC"
Set fso = Server.CreateObject("Scripting.FileSystemObject")
set f = fso.OpenTextFile("myRuntimeInclude.INC", 1)
source = f.ReadAll
f.close
set f = Nothing
set fso = Nothing
ExecuteGlobal source
end if
Now you could package this in a nice SUB, do error handling, etc., and put it inside its own include, and you have the beginnings of runtime includes. In particular, you can add a global variable to this include, into which you add the names of the files included, and NOT include them a 2nd time.
So with a few simple lines of code, ExecuteGlobal enabled Classic ASP to do something it could not.
For example, doing a runtime include like this, will of course not do the nested static includes. No problem - turn the INCLUDE function into a recursive one, and do the static includes also runtime!
Does this makes everything slower? With todays fast servers and cached hard drives etc? Yes, slightly, but just throw more hardware at it and we are OK again - ha ha ha. Yes it is slower, but if you want speed - you would not have gone for classic asp. C++ comes to mind.
And what about HTML and scripting intermixed, as classic asp developers usually does?
No problem - execute the script and print the html as you parse the tags in the include!
Now I will of course add some more notes here, and finally provide you with the source code, but if you are wondering what the final product does, here are a few features:
* dynamic includes
* inheritance - multiple inheritance in fact
* private / inherited methods / properties
* polymorphism
* try - finally - catch blocks
* optional parameters
* function overloading
Thinking about function overloading... Classic VB, being practically a non-typed language, actually is "typed" like any other language. The difference is that in languages like C, pascal, java, dotnet etc., you define the variable's type, and it is fixed. In Classic ASP, the type of a variable is NOT fixed, and it changes according to the type of data in it - much more dynamic than ANY other language I know of. All other languages resolve the overloading at compile time, which is quicker, but still static. Classic ASP, if it had overloading, would have had to do the binding to the correct version of the overloaded method, at runtime - totally dynamic.
Yes, the example source I added here does ALL of the above!
Inheritance
So lets tackle the difficult issues, firstly inheritance:
Imagine you want to inherit from Parent. The ideal would be that you can simply in the ChildClass say:
#inherits filename
where filename contains a class definition with the same name as the file. OR,
#inherits classname in filename
where the file may contain multiple classes. (Or #inherit classname, where the file is assumed to have the same name.)
In theory all the runtime include will have to do is to read the body of the parent class and insert it into the child class's body, right?
It should drop the "class classname" and "end class" declarations from the parent of course.
This was simple. To implement this was in fact just 26 lines of code...
What about private and public items in a class? Well the words "private" and "public" are already used in classic ASP, so why not extend it to OO directive?
#private initiates a section of not inherited properties and methods, and must be followed with
#public which switches inheritance on again.
To implement this is a breeze - all you do is cut the parts in the Parent source between #private and #public.
To implement this was in fact just 7 lines of code...
What about #abstract methods? A one liner! Replace the #abstract tag with ThrowCustomError "abstract method not defined".
So what happens if the parent has a method "Display" and the child attempts to override it? You will get two definitions of Display in the childe class, and it will not compile - Name redefinition error.
This is a good thing! Because now you know you are trying to override a parent 's method.
The way to allow this is to use #overrides or #extends This will flag the assembler to drop the Display method from the parent definition, or to keep it with an adapted name parent_Display(). Simple, but in order to make provision for properties, subs functions, etc., this took much more code to implement, exactly 45 lines.
This #overrides tag does introduce a slight deviation from the normal OO conventions. It means you cannot call the parent's Display method inside the Child method. All the overridden methods are not available. But there is an easy fix if this is actually required. Many time you would inside a child's method do some action, and then call the parent's method with the same name. This is very much standard practice.
The #extends tag causes the parent's class to be renamed before it is added into the child class. You can call the inherited method with parent_display(). Why did I do it like this? Read on.
So all in all, it took exactly 90 lines of code, in the runtime include class, to enable the gist of OO into classic ASP. I am thinking, this is why MS has dropped support for classic ASP - it is simply too powerful.... ;-)
To recap, we implemented:
#inherits
#private
#public
#overrides
#extends
#abstract
.... in about 90 lines of classic ASP code.
And there is a small bonus. If you carefully check the code, you will notice that if A inherits from B, and B from C, all the "parents" are assembled into the source if A. The runtime include does not differentiate between who is doing what inheritance. This means you can actually have a child class inherits from multiple parents!!! You can define a chile and say:
class Child_class
#inherits A
#inherits B
...
end class
VERY few languages can do this! And that is why the #extended classes are renamed for the parent class. You can now call A_display() or B_display(), inside the child.
And you also get the case where A inherits B, which inherits C, and you want to call C_display() in A!
..now that is something to digest.
polymorphism
This is one of the complexities of OO that very few people understand. I will explain it as simple as I can.
Imagine you have two different types of objects, a square, and a circle. They are derived from "Form". Now you can define an object of type Form, and treat it as a container, in which a Square or a Circle is instantiated. Now you can call the container's Dsiplay() method, and polyM allows the correct Display method to be invoked, relative to if the container contained a Square or Circle.
At compile time, the compiler does not know which, or even if the display method is implemented.
Yet at run time, it calls the correct method!
You can have a function that takes Form as parameter, and inside the function call the Form.display method. Depending if the argument provided was a circle or square, the correct method is called.
This is in other words runtime binding or linking.
Normally as the example went, you require a "parent" class, which is often an abstract class, to act as type (container) for the derived classes. And normally you can only do this type of runtime linking, if the parent class defines a method (can be abstract) with this name.
But, the way in which this OO implementation works - you don't need either...!? because classic ASP is un-typed.
I can define a function that accepts a parameter:
Sub doDisplay(Obj) Obj.Display End sub
This is perfectly "compilable" in classic ASP, even though the class is never defined for Obj. Of course trying to execute it with doDisplay 10 will throw an error, because 10 does not have a Display method.
However, I can call this sub with ANY object, regardless of parentage, as long as the object has a Display method. And it will call the correct method - polymorphism without the overhead of an abstract method, or even a container class!
Heresy!
try-catch blocks
Now this is a tougher one. We want something like:
Try
a = 1 a = a/0
a = 2 Finally a=0 Catch Response.write "ERROR: div/0<br>" End try
Note the order of the finally and catch blocks. I swapped these for reasons explained later...
The issues is that classic ASP only provides us with the "on error resume next" mechanism.
I played around with some ideas, and the best I came up for now is to do it with a limitation - you cannot do a do-loop inside the try-catch block.
This is because I use an EXIT DO to jump out of the try-block.
So a simple solution is to translate the code into something like:
on error resume next Do
a = 1: if err.number<>0 then exit Do a = 1/0: if err.number<>0 then exit Do
a = 2: if err.number<>0 then exit Do loop until True a=0 select case err.number
Case 0
case else Response.write "ERROR: div/0<br>" end select
Err.Clear
on error goto 0
To get this working was a bit more difficult, it took about 66 lines of code.
Still, its working...
Arrays
I played around with [] brackets being replaced by array(). This is not very useful, but still its working.
For examp:
function foo( p )
dim pp
for each pp in p
response.write pp & "<br>"
next
end function
This you can then call with foo[], foo[1] or foo[1,2,3].
Function overloading
I started implementing function overloading, using the variable name, and an assigned type, as in : dim xxx #as myInt, where myInt could be ANY symbol. This I will call Variable Type Overloading. I implemented it as a global setting, and the value inside the variable does NOT carry the type with. Wherever xxx is used in the page, in all the includes as well, it is assumed to be of type myInt. This type has absolutely no effect on execution of any normal classic asp code, and only comes into affect when you overloaded a function/sub/property using Variable Name overloading: function foo(X #as myInt) can only be called now with xxx as input argument.
This is all done at compile time.
Take note that the variable type is GLOBAL, to all code underneath a runtime include, and all static includes inside the runtime include. This works for function, subs and properties, but I have not debugged it well.
Rather then I realized that classic ASP is not a type-less language, it merely hides the type from the developer, and as a bonus, the type of the variable can indeed be changed.
a = "string" 'a's type is String
a = 1 'a's type is now Integer
This is HUGE - I know of no other language that allows variable's types to change runtime, well other than when using polymorphism. So I realized that there is a 2nd form of function overloading possible: Value Type Overloading. And this has me excited.
With value type overloading, binding to the correct version of the function/sub/property is based on the data type in the variable, runtime! This is of course not achieved without overhead, as all runtime binding (even polymorphism) requires overhead. Yet it is simple and quick.
One important constraint to notice is that you CANNOT intermix variable type overloading and value type overloading in the same function. Keep them apart. This is because the one happens in the pre-processor, and the value type overloading happens runtime.
Variable type overloading is based on the actual symbol used for the data argument, while value type overloading is on the actual type of data being passed.
Value based overloading is local to within a class, or global outside all classes in a runtime include, and all nested includes. You can have the same function name as a class method, and as a global function, but they will be overloaded separately. Within a class, if you have two versions with the same pattern, you will get name redefinition errors, as the function name is merged with the pattern, and the combination is not unique. Functions that are inherited, are also pushed into the value type overload handler stack. If a parent's and child's function name and pattern are the same, you will get name redefinition errors.
There are a few constraints ito overloading:
*All versions of the function/property/sub must be of the same definition - they must be subs, or functions, or properties - you cannot mix these. All must public/private. Only a GET and a LET property can have the same overloaded name, any other will cause compile errors.
*Another silly constraint is that the definition of the method's name and parameters
must be in the same line, no line continuation character.
*Valid types are all types as returned by TypeName(): Byte, Integer, Long, Single,
Double, Currency, Decimal, Date, String, Boolean, Empty, Null, Object, Unknown,
Nothing, Error or the class name of an object.
You can also overload the return value of a getter or function. The return type will not be matched to the current type of whereto the value is returned, instead you have to tag the function/getter call itself with a type tag ex.: X = myFunc(Y) #of string. Only patterns that is tagged to return a string, will match to this call. Take note - the return type tag is not validated against the actual value returned either. So if function myFunc(Y) #of String actually returns a n integer, the system will not see this as an error.
Also if you call myFunc with no type tag, as in X = myFunc(Y), it will match - if the type is omitted when calling the function, the return type of the overloaded function is ignored.
ooo
So tell me classic ASP is not powerful. To do all this, we needed just over 1000 lines of code.
By the way, I work at one of the largest universities in the world, and this whole runtime include concept, is forming the base of its current IIS web sites. In other words, it does work :-)
1 note
·
View note