I learned PureMVC for Flex about a month ago, and was able to successfully migrate all of my Flex projects at work to this new framework. Of course, these projects are relatively small (appx 5000 lines of code at best) but it was the best move I could have made.
Though PureMVC doesn't necessarily guarantee good design and separation of concerns in a project, it certainly provides a nicely decoupled way of utilizing the MVC design scheme.
PureMVC uses what's called a Facade to act as a broker for forwarding notifications from various components. View components (MXML and the ActionScript needed to drive them) are provided to "Mediators" which communicate via the Facade. These mediators translate any events from the UI (e.g. users clicking buttons to load information from a server) into "notifications" which are sent via the Facade to the respective Controller objects.
These Controller objects are known as "Commands". Commands receive the notification from the Facade (and any data passed from the View components) and then use "Proxies" to request data and perform the majority of the business logic for the application.
Sound complicated? It's really not. The typical project may be organized like this:
src
|- controller
|- model
|_ view
Under the "controller" directory, Commands are kept which receive notifications. These commands invoke "Proxies" which are stored in the "model" directory. These proxies request information from remote objects (e.g. servers) and relay data back to the appropriate location. The "view" folder contains two different types of objects: view components and mediators. The view components are simply the user-visible forms and controls in which the user interacts. These have absolutely no connection to any PureMVC components; rather, they are passed (at runtime) to a "Mediator". The mediator listens for events from the view components and then relays the event to the Facade as a notification.
Frankly, it sounds a lot more complicated than it is. Future posts should have some examples for how to assemble a simple User-form in PureMVC
Thoughts on theology, books, life, the universe, and everything.
Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts
Wednesday, August 5, 2009
Friday, June 12, 2009
Dependency Injection and Flex
So, a quick note on the progress I've made with Flex. First of all, I wanted a tool to highlight text. So...I spent 3 weeks working through tutorials and examples from some brilliant coders who have already paved this way, worked with several different libraries, and finally found that all my work was for naught; enter, FlexLib. It not only had a great highlighting class, but also contained some moveable Panels, and a nice extensible Tab Navigator...sigh..all that work down the drain.
Anyway, I've heard about Dependency Injections a lot lately, and I finally decided to research what it's about. Wow, I never realized how simple a concept it would be. Having been exposed to different design patterns like Factory Method, this was extremely easy to assimilate.
Dependency Injection works very well with Flex interfaces, and particularly well with Factories. If I have an object A which depends on object B, I could have A instantiate B and maintain a reference to it. Unfortunately, this creates a dependency within A upon B:
In this case, A has a definite dependency upon B's implementation. If B changes 'foo()' to anything else, A will break.
We can partially solve this via a interface, in which A and B agree on B's required methods. In this case, B utilizes an interface, BI, which instructs B to always implement 'foo()'. Thus, A can access B via its instance:
But we still have a problem: A is still relying on the base class of B. What if we wanted to break B into different objects, and 'B' was no longer a valid name? Moreover, what if we moved B to a different library? Enter a factory.
Rather than A creating B, even via its interface, what if the code calling A passed in a reference to B, via its interface? For this, we'll add two new classes. 'Factory' has a 'createBI' function that returns a reference to B via its interface, BI. FooBar is a class which creates A. In this class, the code to create A might look something like this:
Whereas the constructor for A might look like this:
From this point, we've broken the dependency of A to B, and created a new dependency from A to BI. This is a better design and is more extensible: should we need to have different variations of B, as long as they implement the BI interface, A can utilize them.
What's more, 'FooBar' injected the dependencies into A.
That's all there is to it.
Now...my question is...how far can you take this??
Anyway, I've heard about Dependency Injections a lot lately, and I finally decided to research what it's about. Wow, I never realized how simple a concept it would be. Having been exposed to different design patterns like Factory Method, this was extremely easy to assimilate.
Dependency Injection works very well with Flex interfaces, and particularly well with Factories. If I have an object A which depends on object B, I could have A instantiate B and maintain a reference to it. Unfortunately, this creates a dependency within A upon B:
private var bInstance:B;
...
bInstance = new B();
bInstance.foo();
In this case, A has a definite dependency upon B's implementation. If B changes 'foo()' to anything else, A will break.
We can partially solve this via a interface, in which A and B agree on B's required methods. In this case, B utilizes an interface, BI, which instructs B to always implement 'foo()'. Thus, A can access B via its instance:
private var bInstance:BI;
...
bInstance = new B();
bInstance.foo(); //guaranteed since bInstance is an instance of type BI
But we still have a problem: A is still relying on the base class of B. What if we wanted to break B into different objects, and 'B' was no longer a valid name? Moreover, what if we moved B to a different library? Enter a factory.
Rather than A creating B, even via its interface, what if the code calling A passed in a reference to B, via its interface? For this, we'll add two new classes. 'Factory' has a 'createBI' function that returns a reference to B via its interface, BI. FooBar is a class which creates A. In this class, the code to create A might look something like this:
a = new A(Factory.createBI());
Whereas the constructor for A might look like this:
private bInst:BI;
public function A(bInst:BI):void {
this.bInst = bInst;
}
From this point, we've broken the dependency of A to B, and created a new dependency from A to BI. This is a better design and is more extensible: should we need to have different variations of B, as long as they implement the BI interface, A can utilize them.
What's more, 'FooBar' injected the dependencies into A.
That's all there is to it.
Now...my question is...how far can you take this??
Saturday, April 4, 2009
Flex, Emacs, Linux, and Irony
I don't like Adobe. Their software is overpriced, bloated, and often difficult to for me to use. I wouldn't be able to derive $999 of worth from Photoshop, though there are pieces in it I would enjoy working with. Flash has made a lot of bad websites worse, while helping the Browser community ignore some of their past glaring inadequacies in adhering to standardization.
This said, I love working with Flex.
This also said, I refuse to pay for Flex Builder. Though it's not a bad IDE (hey, it's built on Eclipse, my personal favorite), it has a few glaring flaws which I won't go into (for those curious, they lie mostly in the debugger and profiler). I also don't like how little support there is for Linux. I spend 95% of my time at home working in Linux, and I don't particularly appreciate their dumbed-down version of the IDE. It's lacking many of the features I do enjoy (e.g. their WYSIWYG for rapid prototyping), while making certain tasks harder. It took me several hours to get a project assembled, after which I still couldn't create anything but .as files (it kept complaining about the project association).
So, I decided to see if I could create a customized Emacs environment for Flex in Linux. I haven't been too worried about certain features (e.g. debugging, file browsing, and intense code-completion). My primary focus is on syntax-highlighting, template generation, and easy compilation. Obviously, I'm keeping my expectations low for now. Hey, it's either this or log into Windows and use FlashDevelop which is really good, but not good enough to log into Windows.
Anyway, I found two great .el files for integration with Emacs, providing some level of syntax-highlighting and code-completion. Both can be found here: EmacsWiki. The two files are as follows:
1. actionscript-mode: provides a custom ActionScript mode (as it says)
2. nxml-mode: a bundle of files which provide extensive XML support (including MXML)
I was also able to integrate a third .el file which provides customizable templates using hotkey-esque strings: snippet.el.
All of these are searchable on the Emacs Wiki.
Anyway, I got these libraries integrated into Emacs (I also setup ECB, but I haven't used it much yet) and used this great tutorial for creating a "Makefile" for a project: . After this, the coding was pretty easy.
I attached a few screenshots for the basic view of the Bible verse memorization tool I'm developing. It's rudimentary at best, but this mock-up should show a decent view.
This first shot is a simple login screen:

The second is the main GUI with a left-side Accordion control for displaying verse references associated with different Leitner piles (I call them "buckets").

Interestingly, I wrote a similar GUI using PyQT4, which took me about 3 days. The Flex GUI shown in the screenshots took about 20 minutes. I wrote it while watching a movie on TV with my wife, and I bet her I could have it pounded out before a commercial break.
Anyway, I have the data-retrieval code written in Python. I'd like to use the ESV Web Service site as the data-source. I haven't heard back from them on licensing. We'll see how that goes.
So, here's the irony. As I mentioned before, I'm terrible at memorizing verses. Hence, I'm writing this app. Unfortunately, the application is taking more of my time away from memorizing verses...
Go figure...
This said, I love working with Flex.
This also said, I refuse to pay for Flex Builder. Though it's not a bad IDE (hey, it's built on Eclipse, my personal favorite), it has a few glaring flaws which I won't go into (for those curious, they lie mostly in the debugger and profiler). I also don't like how little support there is for Linux. I spend 95% of my time at home working in Linux, and I don't particularly appreciate their dumbed-down version of the IDE. It's lacking many of the features I do enjoy (e.g. their WYSIWYG for rapid prototyping), while making certain tasks harder. It took me several hours to get a project assembled, after which I still couldn't create anything but .as files (it kept complaining about the project association).
So, I decided to see if I could create a customized Emacs environment for Flex in Linux. I haven't been too worried about certain features (e.g. debugging, file browsing, and intense code-completion). My primary focus is on syntax-highlighting, template generation, and easy compilation. Obviously, I'm keeping my expectations low for now. Hey, it's either this or log into Windows and use FlashDevelop which is really good, but not good enough to log into Windows.
Anyway, I found two great .el files for integration with Emacs, providing some level of syntax-highlighting and code-completion. Both can be found here: EmacsWiki. The two files are as follows:
1. actionscript-mode: provides a custom ActionScript mode (as it says)
2. nxml-mode: a bundle of files which provide extensive XML support (including MXML)
I was also able to integrate a third .el file which provides customizable templates using hotkey-esque strings: snippet.el.
All of these are searchable on the Emacs Wiki.
Anyway, I got these libraries integrated into Emacs (I also setup ECB, but I haven't used it much yet) and used this great tutorial for creating a "Makefile" for a project: . After this, the coding was pretty easy.
I attached a few screenshots for the basic view of the Bible verse memorization tool I'm developing. It's rudimentary at best, but this mock-up should show a decent view.
This first shot is a simple login screen:

The second is the main GUI with a left-side Accordion control for displaying verse references associated with different Leitner piles (I call them "buckets").

Interestingly, I wrote a similar GUI using PyQT4, which took me about 3 days. The Flex GUI shown in the screenshots took about 20 minutes. I wrote it while watching a movie on TV with my wife, and I bet her I could have it pounded out before a commercial break.
Anyway, I have the data-retrieval code written in Python. I'd like to use the ESV Web Service site as the data-source. I haven't heard back from them on licensing. We'll see how that goes.
So, here's the irony. As I mentioned before, I'm terrible at memorizing verses. Hence, I'm writing this app. Unfortunately, the application is taking more of my time away from memorizing verses...
Go figure...
Sunday, March 15, 2009
New Project in the Making
I'm starting a new project based on some concepts I learned in the flashcard program.
That program is still in beta testing. The basic feature set is ready, but I'm trying to decide if I should delay the 1.0 release to move everything into a database (rather than files).
Anyway, this one will be a memorization tool for Bible verses. I'm terrible at memorizing Scripture, and I really want to improve. Therefore, I'm working on a new utility which will help with my ability to remember.
Instead of randomization and probabilistic weighting for short-term learning (like the previous flashcard system), this one will feature a long-term memorization technique, much closer to the original Leitner algorithm. A GUI (web-based Flex, or desktop AIR, or desktop QT) will be used to select and display verses in a list, associated with a user. The verses being displayed will be weighted according to the user's ability to remember and repeat them. As users are better able to remember, they'll see them less often every day. I have some investigation to do regarding how to do the time calculations (e.g. I guessed a verse right, when should I be asked again), but that's another post altogether.
Anyway, it will be interesting to see how it goes.
That program is still in beta testing. The basic feature set is ready, but I'm trying to decide if I should delay the 1.0 release to move everything into a database (rather than files).
Anyway, this one will be a memorization tool for Bible verses. I'm terrible at memorizing Scripture, and I really want to improve. Therefore, I'm working on a new utility which will help with my ability to remember.
Instead of randomization and probabilistic weighting for short-term learning (like the previous flashcard system), this one will feature a long-term memorization technique, much closer to the original Leitner algorithm. A GUI (web-based Flex, or desktop AIR, or desktop QT) will be used to select and display verses in a list, associated with a user. The verses being displayed will be weighted according to the user's ability to remember and repeat them. As users are better able to remember, they'll see them less often every day. I have some investigation to do regarding how to do the time calculations (e.g. I guessed a verse right, when should I be asked again), but that's another post altogether.
Anyway, it will be interesting to see how it goes.
Sunday, March 8, 2009
Flex and RIA development
I had a project at work to complete. Our automated testing infrastructure has aged beyond the point of usability, and no money has existed for upgrading to a more recent version, or investing in a different system for automated and manual test deployment, tracking, and maintaining.
One of my coworkers began (several years ago) piecing together a web-based automation utility which would allow us to quickly configure and execute test servers with automated tests. The solution was, conceptually, a combination of Javascript, CSS, and Ajax, in which users could add machines to a table, drag&drop test configurations to each machine, edit the test configurations (e.g. modify the command-line parameters passed to each test), and execute the overall config by sending it to the test automation system as a single CSV string.
His work lasted about 3 months, and resulted in the drag&drop interface.
Shortly after this, another coworker extended upon this work by adding the test config storage and retrieval via Ajax. Users could [in theory] add tests to each machine, edit their respective parameters, and execute said tests. They could also quickly create test configurations which would map directly to their respective automated tests in the version control repository.
The result was pretty good, but fell short in several ways: Ajax calls only worked 70% of the time, resulting in failures to execute tests, save configurations, and retrieve various pieces of information. Each test config was stored as a Javascript file on the web server, which required users to understand Javascript syntax if they wanted to manually add or edit existing configs. It also refused to work in IE.
His work lasted several months as well before he moved on to bigger and better things. I inherited it and took on the work to make it work more consistently with our test infrastructure. This lasted for about 3 months on the system before I decided to investigate other solutions.
Enter Flex.
The original interface put together was quite sound: dragging and dropping test configs to various machines is a great idea, though difficult to implement. I wanted to keep the use model of the system, but move away from pure Javascript.
After hearing some buzz regarding Flex around the office, I decided to take a look and see if it could offer a better solution.
Frankly, I was amazed. Within 3 weeks of starting, and without any prior exposure to Flex and ActionScript, I had completely reproduced all interface functionality, and even added several extensions. Rather than relying on Javascript for test configurations, I was able to introduce XML (a more logical choice, in my opinion) for configuration storage and retrieval. Relying on the Flash player resolved the issues between IE and Firefox (and other browsers which support the issues with storing and retrieving information from the web server.
In short, Flex is a fantastic solution for developing "Rich Internet Applications." The presence of a standardized API (*cough -- javascript!*) and a full-fledged object-oriented language quickly and easily resolved all issues I had with prior implementations.
In essence, though I'm impressed with the usability and functionality of Javascript and CSS, for web apps I'm likely going to stick with Flex and potentially Cappuccino if it's as cool as it looks.
One of my coworkers began (several years ago) piecing together a web-based automation utility which would allow us to quickly configure and execute test servers with automated tests. The solution was, conceptually, a combination of Javascript, CSS, and Ajax, in which users could add machines to a table, drag&drop test configurations to each machine, edit the test configurations (e.g. modify the command-line parameters passed to each test), and execute the overall config by sending it to the test automation system as a single CSV string.
His work lasted about 3 months, and resulted in the drag&drop interface.
Shortly after this, another coworker extended upon this work by adding the test config storage and retrieval via Ajax. Users could [in theory] add tests to each machine, edit their respective parameters, and execute said tests. They could also quickly create test configurations which would map directly to their respective automated tests in the version control repository.
The result was pretty good, but fell short in several ways: Ajax calls only worked 70% of the time, resulting in failures to execute tests, save configurations, and retrieve various pieces of information. Each test config was stored as a Javascript file on the web server, which required users to understand Javascript syntax if they wanted to manually add or edit existing configs. It also refused to work in IE.
His work lasted several months as well before he moved on to bigger and better things. I inherited it and took on the work to make it work more consistently with our test infrastructure. This lasted for about 3 months on the system before I decided to investigate other solutions.
Enter Flex.
The original interface put together was quite sound: dragging and dropping test configs to various machines is a great idea, though difficult to implement. I wanted to keep the use model of the system, but move away from pure Javascript.
After hearing some buzz regarding Flex around the office, I decided to take a look and see if it could offer a better solution.
Frankly, I was amazed. Within 3 weeks of starting, and without any prior exposure to Flex and ActionScript, I had completely reproduced all interface functionality, and even added several extensions. Rather than relying on Javascript for test configurations, I was able to introduce XML (a more logical choice, in my opinion) for configuration storage and retrieval. Relying on the Flash player resolved the issues between IE and Firefox (and other browsers which support the issues with storing and retrieving information from the web server.
In short, Flex is a fantastic solution for developing "Rich Internet Applications." The presence of a standardized API (*cough -- javascript!*) and a full-fledged object-oriented language quickly and easily resolved all issues I had with prior implementations.
In essence, though I'm impressed with the usability and functionality of Javascript and CSS, for web apps I'm likely going to stick with Flex and potentially Cappuccino if it's as cool as it looks.
Sunday, January 11, 2009
Flashcards Project Status
For those of you who don't know, I've been working on a new project for the past several months. My initial desire was to create a simple little app which would help me learn Python, and would also facilitate my learning of Classical Greek endings. Verb and noun endings in Greek are vitally important to understand, and there's so bloody many, I felt a learning application would be a fun project.
The last 4 months of coding have been some of the most fun I've had.
Though the project is still in its infancy, and though I'm struggling with massive amounts of scope creep, I have an "alpha" which is almost ready to be released.
Here are the initial requirements/specifications:
1. The system will provide "questions" and allow users to provide "answers"
2. The system will check the user's response and either accept it as a match, or reject it
3. The "questions" posted by the system will initially be in the form of Classical Greek verbs, nouns, or prepositions. Answers will be posted in English.
4. Verbs and Nouns can be put together by the system as a "cross product" of two sets: roots and endings. In other words, the system should be able to take a list of roots and apply endings to each one.
4a. In addition to this, the system should be able to discern the correct answer
5. The system will use Leitner's System (or a modified version) for "learning" which words the user knows and which ones they don't.
5a. The system will provide "questions" for those less-known words more often than those of well-known words
5bi. The system should have a means for accessing less-known words more often than well-known words (see point 8b)
6. The system will provide a means of "hinting" at the answer
6a. The hint system should be configurable
7. The system will provide statistics for the learner to gauge their progress
7b. The system should output information regarding the number of successes, failures, and hints posted or requested by the user
8. The system will allow the user to modify the underlying details of the Leitner Algorithm while currently engaged with the application
8a. The user should be able to modify the number of "piles" (called "buckets") in which the cards are distributed, within the range of '1' or '10' buckets
8b. The user should be able to modify the means in which the buckets are distributed (e.g. 30% of the time, the system will pull cards from the least-known bucket, 5% of the time it will pull from the well-known bucket)
9. The system should use a QT-based GUI for viewing
10. The system should be able to preserve the current state of user-execution
10a. The system should allow the user to save/restore the current state whenever they desire
11. The system should be configurable via XML configuration files, allowing users to "hot-swap" different card-input algorithms
12. The system will provide detailed documentation for use, administration, and flashcard development.
13. The system will host 'hotkeys' for easier navigation
These are the basic requirements. All but 10 and 11 are pretty much finished, though there are a number of defects and design issues which need to be addressed.
One requirement I'd really like to investigate and get working is #11. My buddy Bump suggested this: apparently, the current Flashcard systems don't have very well abstracted algorithms which can be swapped out. I'm not sure what this will mean, but it sounds interesting and fun.
In the meantime, here are some screenshots of the GUI in action. In order they are:
I. The main GUI and dialog for choosing the card "set"
II. The main flashcard GUI -- note the Unicode characters for the Greek words and the statistics in the lower left corner
III. Main flashcard GUI -- posted failure when user guess is incorrect
IV. Main flashcard GUI -- posted hint when user requests
V. Main flashcard GUI -- posted success when user guess is correct
VI. Main Algorithm Admin GUI -- note the Leitner and Hint system administration options





The last 4 months of coding have been some of the most fun I've had.
Though the project is still in its infancy, and though I'm struggling with massive amounts of scope creep, I have an "alpha" which is almost ready to be released.
Here are the initial requirements/specifications:
1. The system will provide "questions" and allow users to provide "answers"
2. The system will check the user's response and either accept it as a match, or reject it
3. The "questions" posted by the system will initially be in the form of Classical Greek verbs, nouns, or prepositions. Answers will be posted in English.
4. Verbs and Nouns can be put together by the system as a "cross product" of two sets: roots and endings. In other words, the system should be able to take a list of roots and apply endings to each one.
4a. In addition to this, the system should be able to discern the correct answer
5. The system will use Leitner's System (or a modified version) for "learning" which words the user knows and which ones they don't.
5a. The system will provide "questions" for those less-known words more often than those of well-known words
5bi. The system should have a means for accessing less-known words more often than well-known words (see point 8b)
6. The system will provide a means of "hinting" at the answer
6a. The hint system should be configurable
7. The system will provide statistics for the learner to gauge their progress
7b. The system should output information regarding the number of successes, failures, and hints posted or requested by the user
8. The system will allow the user to modify the underlying details of the Leitner Algorithm while currently engaged with the application
8a. The user should be able to modify the number of "piles" (called "buckets") in which the cards are distributed, within the range of '1' or '10' buckets
8b. The user should be able to modify the means in which the buckets are distributed (e.g. 30% of the time, the system will pull cards from the least-known bucket, 5% of the time it will pull from the well-known bucket)
9. The system should use a QT-based GUI for viewing
10. The system should be able to preserve the current state of user-execution
10a. The system should allow the user to save/restore the current state whenever they desire
11. The system should be configurable via XML configuration files, allowing users to "hot-swap" different card-input algorithms
12. The system will provide detailed documentation for use, administration, and flashcard development.
13. The system will host 'hotkeys' for easier navigation
These are the basic requirements. All but 10 and 11 are pretty much finished, though there are a number of defects and design issues which need to be addressed.
One requirement I'd really like to investigate and get working is #11. My buddy Bump suggested this: apparently, the current Flashcard systems don't have very well abstracted algorithms which can be swapped out. I'm not sure what this will mean, but it sounds interesting and fun.
In the meantime, here are some screenshots of the GUI in action. In order they are:
I. The main GUI and dialog for choosing the card "set"
II. The main flashcard GUI -- note the Unicode characters for the Greek words and the statistics in the lower left corner
III. Main flashcard GUI -- posted failure when user guess is incorrect
IV. Main flashcard GUI -- posted hint when user requests
V. Main flashcard GUI -- posted success when user guess is correct
VI. Main Algorithm Admin GUI -- note the Leitner and Hint system administration options





Saturday, October 11, 2008
Dynamic Inheritance in Perl
Ok, I discovered this little tidbit while working on a relatively extensive project in Perl. I came across an issue where I had several OS-based "abstract" classes written in Perl (yeah, I know -- OOP in Perl is nothing but trouble), and I needed to inherit from one of them. The trick, however, was to do it dynamically, depending on the OS I was currently working on.
Casting scalars to functions and even classes is a pretty simple thing.
Consider the following example in foo.pl:
The result of executing this code is fairly simple:
It's also possible to cast a scalar to a package/class type, allowing more flexibility on which objects or modules are called at run time.
Consider the following two files, foo.pl, bar.pm, baz.pm:
foo.pl:
bar.pm:
and baz.pm:
Now, execution looks like this:
Of course, there are some severe consequences of doing such practices. But, in my opinion, none of them compare to what else you can do with Perl's "cast-ability."
Consider the following hiearchy: Class linuxFoo is a class, specific to the Linux OS. Class solarisFoo is also a class, specific to the Solaris OS. Class Foo wants to inherit from either, but only does so in accordance to the OS it's currently running from. Here's the code:
linuxFoo.pm:
solarisFoo.pm:
Foo.pm:
and test.pl:
The result of running this script on two different operating systems (linux and solaris) is as follows:
Now, why is this a bad idea??
Creating function references on the fly via string values is always iffy. It requires a full-knowledge of the underlying code in order to correctly identify which methods are required. Though it's possible to abstract this out to some extent (forcing function/method names to use a value which is immutable for the system--e.g. the OS type), it still creates a brittle interface in which to work.
Dynamically creating and using modules is likewise a bit iffy as well. Should a module need to be refactored in the future (or is replaced with a different one), this forces the programmer to update the string which is used to create it.
Either way, the ability to use a string value to execute a function or use a module is tenuous at best. Dynamic inheritance, however, is downright dangerous. Users can take objects and randomly redefine their hierarchical structure however and whenever they want. Languages such as Java and C++ (to name a few) prevent this by statically typing their classes at compile-time. This forces the contracts imposed by inheritance and interfaces (e.g. interface methods are always implemented, inherited methods are always present via the parent, etc.).
Dynamic inheritance throws it all out the window. If you have a Dog object, it can randomly inherit from a Wheel object. Not only this, it can inherit from a Wheel after it's already inherited from a Fire Hydrant. Ok, the rule of odd and bizarre inheritance structures is present in all languages. But redefining the structure at any point in the code, without compile-time checks, makes Perl a fun, but screwy and dangerous language to program in.
...of course...some would say not to do OOP in Perl, which is why I'm transitioning to Python...
Casting scalars to functions and even classes is a pretty simple thing.
Consider the following example in foo.pl:
#!/usr/bin/perl
my $func = shift;
my $result = &$func(@ARGV);
print "$result\n";
sub add {
my ($x, $y) = @_;
return $x + $y;
}
sub subtract {
my ($x, $y) = @_;
return $x - $y;
}
The result of executing this code is fairly simple:
# perl foo.pl add 1 2
3
# perl foo.pl subtract 2 1
1
It's also possible to cast a scalar to a package/class type, allowing more flexibility on which objects or modules are called at run time.
Consider the following two files, foo.pl, bar.pm, baz.pm:
foo.pl:
#!/usr/bin/perl
my $pkg = shift @ARGV;
require "$pkg.pm"; # only load the package specified on the command line
my $class_ref = $pkg->new();
$class_ref->to_string();
bar.pm:
#!/usr/bin/perl
package bar;
sub new {
my $proto = shift;
my $class = ref $proto || $proto;
my $self = {};
bless ($self, $class);
return $self;
}
sub to_string {
my $self = shift;
return "bar says hello!\n";
}
1;
and baz.pm:
#!/usr/bin/perl
package bar;
sub new {
my $proto = shift;
my $class = ref $proto || $proto;
my $self = {};
bless ($self, $class);
return $self;
}
sub to_string {
my $self = shift;
return "baz says hello!\n";
}
1;
Now, execution looks like this:
# perl foo.pl bar
bar says hello!
# perl foo.pl baz
baz says hello!
Of course, there are some severe consequences of doing such practices. But, in my opinion, none of them compare to what else you can do with Perl's "cast-ability."
Consider the following hiearchy: Class linuxFoo is a class, specific to the Linux OS. Class solarisFoo is also a class, specific to the Solaris OS. Class Foo wants to inherit from either, but only does so in accordance to the OS it's currently running from. Here's the code:
linuxFoo.pm:
#!/usr/bin/perl
package linuxFoo;
sub new {
my $proto = shift;
my $class = ref $proto || $proto;
my $self = {};
bless ($self, $class);
return $self;
}
sub to_string {
return "This is Linux-based functionality!\n";
}
1;
solarisFoo.pm:
#!/usr/bin/perl
package solarisFoo;
sub new {
my $proto = shift;
my $class = ref $proto || $proto;
my $self = {};
bless ($self, $class);
return $self;
}
sub to_string {
return "This is Solaris-based functionality!\n";
}
1;
Foo.pm:
#!/usr/bin/perl
package Foo;
sub new {
my $class = shift;
my $os = $^O; # this gets the OS, in case you don't know
# require the correct module, and use it as the parent
my $pkg = $os . "Foo";
require "$pkg.pm";
our @ISA = $pkg;
my $self = $class->SUPER::new();
bless ($self, $class);
return $self;
}
sub to_string {
my $self = shift;
return $self->SUPER::to_string();
}
1;
and test.pl:
#!/usr/bin/perl
use Foo;
my $class_ref = Foo->new();
print $class_ref->to_string();
The result of running this script on two different operating systems (linux and solaris) is as follows:
# perl test.pl # on linux
This is Linux-based functionality!
# perl test.pl # on solaris
This is Solaris-based functionality!
Now, why is this a bad idea??
Creating function references on the fly via string values is always iffy. It requires a full-knowledge of the underlying code in order to correctly identify which methods are required. Though it's possible to abstract this out to some extent (forcing function/method names to use a value which is immutable for the system--e.g. the OS type), it still creates a brittle interface in which to work.
Dynamically creating and using modules is likewise a bit iffy as well. Should a module need to be refactored in the future (or is replaced with a different one), this forces the programmer to update the string which is used to create it.
Either way, the ability to use a string value to execute a function or use a module is tenuous at best. Dynamic inheritance, however, is downright dangerous. Users can take objects and randomly redefine their hierarchical structure however and whenever they want. Languages such as Java and C++ (to name a few) prevent this by statically typing their classes at compile-time. This forces the contracts imposed by inheritance and interfaces (e.g. interface methods are always implemented, inherited methods are always present via the parent, etc.).
Dynamic inheritance throws it all out the window. If you have a Dog object, it can randomly inherit from a Wheel object. Not only this, it can inherit from a Wheel after it's already inherited from a Fire Hydrant. Ok, the rule of odd and bizarre inheritance structures is present in all languages. But redefining the structure at any point in the code, without compile-time checks, makes Perl a fun, but screwy and dangerous language to program in.
...of course...some would say not to do OOP in Perl, which is why I'm transitioning to Python...
Subscribe to:
Posts (Atom)