Showing posts with label ActionScript. Show all posts
Showing posts with label ActionScript. Show all posts

08 March 2011

To Flash or not to Flash

I love building stuff with Flash technologies. I think ActionScript 3.0 is an excellent language and Flex 4 is a very good framework. I'm not particularly enamored of the alternatives. I find JavaScript to be a mediocre language (albeit with some excellent libraries). I don't like wrangling CSS more than I have to (although Less makes it much nicer). I find HTML 5 to be a pretty immature technology so far. SilverLight's days are probably numbered. (I haven't yet delved into mobile operating systems, like Android and iOS, so I can't speak for those. And those aren't complete alternatives, anyway.)


Because I love Flash, I have a tendency to want to build everything in it. But over the years I've learned that this tendency must be curbed whenever possible. There are definite downsides to Flash, and especially to doing entire websites in Flash. (The now-defunct March of Man website and some abandoned versions of the Dinosauricon are testaments to this.)


For PhyloPic, it was pretty clear to me that there would be no significant advantage to building it in Flash. Load times would be increased without any functionality enhancement. I wouldn't be able to use it on my iPhone. And all the functionality I needed was easily available in plain old HTML/JavaScript/CSS.


With one exception.


The Submission Tool is built as a Flex app. There is one primary reason for this: image processing. Processing the silhouettes on the server side was an option, but one that could have potentially bogged the server down. (It's already starting to buckle a bit as is, pending some optimizations.) But, by using Flash's BitmapData class, I can do that bit of work on the client side before the silhouettes are shipped off to the database.


Of course there are some other benefits as well. In descending order of importance:

  • Flash allows for a more unified experience for the submitter. No page reloads and no cross-browser differences.
  • SPAM bots are much more capable of cracking HTML forms than cracking custom AMF web services. SWF files are generally opaque to them.
  • It was easier for me to build and test.
Had it just been those three reasons, there might still have been a good argument to do it as HTML/AJAX. The image processing requirement is what really tipped the scales. One hundred submitters contrasting, cropping, and rescaling bitmaps is much nicer if they're doing it on their own machines than if they're all doing it on the server. (Okay, I've barely had even two simultaneous submitters so far, but I can dream....)

There may be other Flash tools in PhyloPic's future. For example, I think it is the best technology for the Cladogram Generator. But for the rest of the site, plain old HTML/JavaScript/CSS is certainly sufficient—better, even.

UPDATE (2012 Jan 26): The Submission Page still uses Flash but is not a Flex app.

26 July 2010

3D Visualization of the Fossil Distribution of the Human-Chimpanzee Total Clade

What it says.
Click on the image to open the visualization.
I've been compiling data on "pan-mangani" fossils. This is my first March of Man toolshop post in a while: a 3D visualization of that data, where the horizontal axis is longitude, the vertical axis is latitude, and depth (the z-axis) is age. The "blobs" each represent a fossilized individual, and you can mouse over them to see what their taxon is.

Some data is missing, notably a lot of entries for our own species. Other data needs to be refined—some of the better-known species (ahem, Neandertals) are big clouds that need to be tied down to specific sites. Also, I obviously need to do more work on that present-day distribution map. But it's a decent start.


Fun things to do:

  • See if you can find the oldest individual (the lone specimen of Sahelanthropus tchadensis).
  • Try to find its Chadian compatriots.
  • Find the earliest non-African individuals (hint: East Europe and the Malayan Archipelago).
  • Wonder what the heck that thing in India is.
  • Look for the single cluster of extinct chimpanzees (Pan sp.).
  • Find the three subspecies of Homo sapiens other than our own. (Note: these may not be distinct from each other—I just prefer to err on the side of splitting for projects like these. Easier to revise later.)
  • Marvel at how easy it is to become sympathetic to multiregionalism when you just view the distribution data without any morphological context and ignore the fact that not all regions are good for preservation.
  • Wonder how people can possibly believe in baraminology in the face of such ample evidence. (Adding morphological data to this would help a lot—there really aren't any good "cutoff" points for our lineage.)
UPDATE:

Better version here.

26 June 2010

Names on Nodes is finally online.

A month ago I got notice that my abstract had been accepted, and that I would be demoing Names on Nodes at the iEvoBio conference's Software Bazaar on June 29. This is the first time Names on Nodes has ever truly had a hard deadline. Since it's a personal project, until now I have had the luxury of languidly rebuilding and polishing and rebuilding and polishing. But now I have to get something up. So it's up.




There's still a lot left to do, but this will have to do for now. You can load NexML and Newick files (not NEXUS for now, sorryalthough, really, you should be sorry for still using it when NexML is available). You can save as MathML and export PNG image files. You can create phylogenies and phylogenetic definitions on the fly using a visual interface that emphasizes drag-and-drop. Or you can type them in (as Newick and MathML, respectively), should you prefer that.


There are still a lot of bugs, and a lot of unimplemented features. If you come across issues or if you have feature requests, please feel free to submit an issue. And if you want to look at the code, it's open source (MIT license) and available on BitBucket.

06 May 2010

PhyloPainter: Happy Little Trees

The whole Flash/Apple fracas has been rather distasteful to me. But I'm not going to dwell on that right now. Instead, I am trying to keep an open mind by trying out some of the technologies that are competing with my favored development tools. First up: HTML 5.

I'll probably write more on the topic later, but suffice to say for now that working HTML 5 feels like I've traveled in time back to 2001, the days of ActionScript 1.0. JavaScript is a poor language for anything complicated. Canvas has covered the basics of vector drawing well, but little else. That said, I see potential and I'm pretty certain the tools will improve.

For my first HTML 5 app, I ported some basic functionality from Names on Nodes, namely, the ability to read Newick tree strings and the ability to draw graphs. I give you:


It's a bit rough right now. For one thing, it doesn't work in Internet Explorer (despite the inclusion of a workaround JavaScript tool—the current version of IE doesn't support HTML 5 Canvas). But it's a start.

Give it a try—paint some happy little trees!

20 November 2009

What I Do For a Living, Part 312: Dr. Facilier's Parlour

I recently completed a new application. This one is a collection of three games associated with Disney's upcoming animated film, The Princess and the Frog. This one requires a Facebook account: Dr. Facilier's Parlour. (Dr. Facilier is the villain of the movie.)

This is my first completed project using certain technologies:
Also see the Shadow Shakedown game therein for an example of how DisplacementMapFilter can be useful. (I also got to do a tiny bit of character animation there.)

I have to say I was very pleased with all of these new technologies. In particular, the Spark component set is a huge improvement over the previous Halo components. Skinning components is so easy now it's hard to imagine that it was ever difficult. Adobe has acted on the "Favor composition to inheritance" maxim, and it has paid off. Also, props to Code Igniter, with its flexible tools and strong emphasis on the MVC pattern, for making PHP development (something I had all but sworn off) actually kind of fun.

Enjoy!

24 August 2009

Online NEXUS File Viewer

It's been a month since my last post, but I have a very good reason for the hiatus. Namely, I was busy getting married to this woman (at the Los Angeles County Museum of Natural History) and going on our honeymoon (in Sydney, Australia).

Now that I'm back in California, time to get back to work on Names on Nodes! I've just put together a small demo of two key parts of its functionality: the reading of NEXUS files and the displaying of phylogenetic networks. Click here to see the NEXUS Viewer demo. This application opens NEXUS files and displays the trees in them as a combined phylogenetic network.

Things you need to know:
  1. You must have a NEXUS file stored locally on your computer to use this.
  2. That file should have a TREES section. (If not, the viewer should just display a list of operational taxonomic units.)
  3. This could get messy for NEXUS files with lots of trees. (Although it's kind of neat-looking.)
  4. You can move the nodes around by clicking on them, or click anywhere else to move the entire diagram.
  5. I would dearly love to know if, for some reason, it does not work for a given file.
Enjoy!

23 July 2009

Two "Names on Nodes"-Related Launches

I'm still a clear way away from launching the beta application, but I've just made a couple of launches related to my long-time work-in-progress, Names on Nodes.

First up, and probably of more interest to most people, I've begun the documentation for the MathML definitions used by Names on Nodes. The document includes general reviews of relevant mathematical and biological concepts, a quick review of MathML and the technologies it's based on, some comments on correlating mathematical and biological concepts, and definitions for all entities (including operations) used by Names on Nodes. Note that this covers a lot of the same ground as in my 2007 paper, with a few minor changes in the symbols and terminology (e.g., I now call the ancestor of a clade a "cladogen" rather than a "cladogenetic set").

Secondly, I've made the project open-source, by moving it to Google Code. If you are a developer interested in checking this out, go here. It's incomplete, so I don't know if anyone will have any real interest in looking at it yet. (Honestly, I mostly posted so that, on the off chance that I unexpectedly kick the bucket, my magnum opus won't be lost forever.)

This information is also on the new Names on Nodes home page.

16 December 2008

My Yuletide Gift: Open Source ActionScript 3.0 Libraries!

I finally got around to setting up a Google Code site:

A Three-Pound Monkey Brain: ActionScript 3.0 Libraries

As you can see, there is still much to be done. But it's a start, and it's available to anyone.

Merry Solsticetime, everyone!

10 December 2008

Uncle Sam wants YOU!

In case you all were curious about what I actually do for a living, this just launched:


This is a project I worked on with several other developers. (Well, I still am working on it—there are a couple of revisions we'll be rolling out before too long.) I also did some work on the main Army Experience Center website.

I believe this is the first project I've worked on involving Papervision3D that has made its way online. Hoo-ah!

20 November 2008

Names on Nodes: Viewing Phylogenies

One of the primary uses for Names on Nodes will be as a viewer for phylogenetic hypotheses. The first incarnation will be able to digest hypotheses from NEXUS files; later versions will allow other file formats and ad hoc creation. I've been working on this aspect of the application lately and thought I'd post a few screen shots. (Warning: This is not the final look. I am definitely going to use a more legible font!)

Here's a very simple tree from a study on carnivoran phylogeny using supertrees (Bininda-Emonds et al. 1999):


(Note: the feliform side is a little outdated by now.)

This is a directed acyclic graph (and specifically a tree) rendered using the Flare ActionScript library, an extremely powerful (if sometimes frustrating) data visualization tool. It's based on the only tree in that particular NEXUS file. But what if a NEXUS file has more than one tree? This is where it gets kind of neat (I think)—Names on Nodes can show multiple hypotheses at once!

Here's a combination of two hypotheses from Novacek's (1989) study of mammalian phylogeny:


(Note: Much of this was changed by the subsequent molecular revolution in eutherian phylogeny.)

The NEXUS file has one tree based on extant organisms and another with some extinct taxonomic units. This network represents the phylogeny if both trees were true. Obviously, it shouldn't be taken too literally—there's no way carnivorans are descended from a hybridization of two disparate lineages, for example. But it shows a sort of consensus, and can be used for the application of phylogenetic definitions.

For the more botanically-inclined, here's a similar network for Rodman et al.'s (1984) analysis of Centrospermae:


(I have no idea how outdated this one is.)

Another thing that can be done in Names on Nodes is linking phylogenies together. For the aforementioned study by Bininda-Emonds et al. there is another NEXUS file focusing on Canidae. A user could open both files, drag the root node of the Canidae phylogeny to the terminal Canidae node in the Carnivora phylogeny, and equate the units with each other. This would produce something like this (cropped):


The root node in this phylogeny, then, could be equated with the Carnivora node in Novacek's phylogeny, and so on. In this way, gigantic networks can be compiled, representing the complete Tree of Life. Outdated hypotheses can be filtered to taste.

Next step: automated taxonomy.

Next next step: relating anything and everything to the Tree of Life.

17 August 2008

Sets for ActionScript

It's been a busy couple of months!

One of the things keeping me busy is, of course, Names on Nodes, the web application I am developing that will automate phylogenetic nomenclature. As part of that project, I have developed a mathematics package that I would eventually like to release as its own package. One class, however, is so useful that I have decided to jump the gun and offer it on its own.

We (ActionScript programmers) all know how useful the Array class is. It can be used to store a sequence of anything, so it can be repurposed as a list, a vector, an edge—all manner of collections.

Well, not all manner of collections. Just ordered collections that allow duplicate elements. What if you want a set: an unordered collection with no duplicates? I find I need sets all the time, but I have to use arrays. And arrays are not optimal for looking up an element's membership, or preventing duplication. As lists they're great, but as sets they suck.

For a while I used a class I'd made called ArraySet that wrapped an array, but this was only an improvement in API, not in performance. Then I took a cue from Java and created: HashSet.


The HashSet class wraps a Dictionary object, which it uses as a hash table. If an element belongs to the set, then that element is a self-referential key in the dictionary. If it doesn't, then there is no such key in the dictionary. And HashSet extends Proxy, so you can use bracket notation for many operations,. You can also use for..in and for each..in loops.

Here's a quick example:


// Create and populate the set.
var s:HashSet = HashSet.fromObject([1, 2, 3]);

trace(s.size); // 3
trace(s[1]); // 1
trace(s[2]); // 2
trace(s[0]); // undefined
trace(s.has(1)) // true

// Trace all elements of the set.
for each (var i:int in s)
{
trace(i);
}
// Trace all elements of the set (different method).
for (var x:* in s)
{
trace(x);
}

trace(s); // {1, 2, 3}
s.add(1);
trace(s); // {1, 2, 3}
s.add(4);
trace(s); // {1, 2, 3, 4}
s.remove(1);
trace(s); // {2, 3, 4}
delete s[2];
trace(s); // {3, 4}
s[3] = undefined;
trace(s); // {4}


...and so on. Full documentation is in the class itself, so you can figure out the details for yourself. I will mention that HashSet also has a number of functions in common with Array (every, filter, forEach, map, some) and others that are unique to sets (get empty, diff, intersect, prSubsetOf, subsetOf, union). It also has a few functions that Array really ought to have (clone, equals, remove).

Download it and try it! The full version is integrated into the mathematics package that I'm still tweaking, but this is too useful to keep to myself any longer. At least, I think so—let me know what you think.

06 June 2008

Three-Pound Monkey Brain: The Open Source Project

In an earlier post, I was bemoaning the unimaginative (and self-centered) name I was using for my general open source ActionScript project: net.tmkeesey. But someone pointed out to me this morning that a better name was staring me in the face all this time. Thus, I have changed the packages from net.tmkeesey to ... threelbmonkeybrain! (A bit long-winded, but unfortunately you cannot start package names with numerical digits.)

Along with this much-better name is a new location for the code. Point your Subversion clients to:
(Or, if you just want the code itself without unit tests, etc.: http://svn3.cvsdude.com/keesey/PROJECTS/ threelbmonkeybrain/as3/trunk/src/threelbmonkeybrain)

I've added a lot of new packages under the rubrics of threelbmonkeybrain.load and threelbmonkeybrain.net, but I have not had time to build full unit tests for them. Once that's done, I'll write more about those.

04 June 2008

More Additions to Open Code: Collections and Connectivity

I've added two new utility packages to net.tmkeesey. SVN repository here.)

net.tmkeesey.utils.mx
Static classes with utilities for handling Flex objects.
net.tmkeesey.utils.mx.ArrayCollectionUtil
Contains a convenience method for converting arrays to ArrayCollection objects with filters and/or sorts.
net.tmkeesey.utils.mx.Filtration
Contains handy functions which can be used for ICollectionView.filterFunction.
net.tmkeesey.utils.mx.ListCollectionViewUtil
Contains a convenience method for converting ListCollectionView objects to arrays, using filters and/or sorts.

net.tmkeesey.utils.net
Static classes with utilities for handling flash.net objects.
net.tmkeesey.utils.net.URLRequestHeaderUtil
Contains methods for cloning and comparing URLRequestHeader objects.
net.tmkeesey.utils.net.URLRequestUtil
Contains methods for cloning and comparing URLRequest objects.
net.tmkeesey.utils.net.URLVariablesUtil
Contains methods for cloning and comparing URLVariables objects.

As always, I commit nothing until I've created ASDoc comments and flexunit tests for everything.

(O.K., not the most exciting update, but....)

03 June 2008

Motion Blur

O.K., last one for the day—I promise.

I just committed a small addition to net.tmkeesey. As alluded to in my last post, it's motion blur. How easy is it to use? Here:

import net.tmkeesey.anim.effects.MotionBlur;
new MotionBlur(myDisplayObject);

Done. Now myDisplayObject will blur whenever you move it. It even works with preexisting filters. (Note that the blur looks best for horizontal and vertical motion, though. I may work on an improvement for that later.) There are also a few optional parameters: blurFactor (how much to blur per pixel moved), optimized (optimization flag—only uses powers of two for blurring if set to true the default), and quality (blur quality).

In the future I'd like to update this so that the parameters can be changed on the fly, but I'm not sure how useful that would really be. Good enough for now.

Once again, the code can be checked out from:
http://svn3.cvsdude.com/keesey/PROJECTS/tmkeesey/trunk

Updates to Open AS3 Code

Pursuant to my last post, I've added some general utility classes to the net.tmkeesey repository. They are arranged in two packages: utils.core and utils.display:

net.tmkeesey.utils.core
  • ClassUtil
  • ObjectUtil
  • StringUtil
  • TimerUtil
  • UIntUtil
  • XMLListUtil
  • XMLUtil
net.tmkeesey.utils.display
  • ColorUtil
  • DisplayObjectUtil

A couple of highlights:

UIntUtil.closestPowerOf2() can be used to optimize blur filters. (Coming soon: MotionBlur class.)

DisplayObjectUtil.findAncestor() searches an object's display ancestry for an object of a certain class. This can greatly facilitate communication between visual components. (And even nonvisual objects, as long as they have a parent property which is an instance of DisplayObjectContainer.)

As always, all classes come with unit tests and all code is commented with ASDoc (except for unit test code, where it would really be superfluous).

Once again, the repository is at: http://svn3.cvsdude.com/keesey/PROJECTS/tmkeesey/trunk

02 June 2008

I'm Going Open Source!

Over the years, I've come up with a large number of ActionScript packages that I reuse on projects. I've been meaning for a long time to release some of these packages to the public. Well, there's no time like the present, so I'm going to start.

One note: I'm using net.tmkeesey as a package name, but eventually I'd like to name it after something other than myself. So this is just provisional until I start opening up collaboration.

The repository is located at:



(I'm assuming that anyone who's read this far knows how to check out a project from a Subversion repository.)

I figured I'd start with the basics. I've included three very low-level packages: assert, core, and relate. These are distilled from packages I am using for Names on Nodes and other projects.

net.tmkeesey.assert.Assertion
Utility class with methods for making assertions.

net.tmkeesey.assert.AssertionError
Generic error type for a failed assertion.

net.tmkeesey.core.Property
Utility class for object properties.

net.tmkeesey.relate.ComparisonStack
Stores a stack of ordered, two-object comparisons. Used to prevent recursion.

net.tmkeesey.relate.Equality
Utility class for determining equality (either qualititave equality or identity) of two objects. Works with Equatable.

net.tmkeesey.relate.Equatable
Interface with a single method, equals(Object):Boolean, for determining qualitative equality.

net.tmkeesey.relate.Order
Utility class for determining the relative order of two objects. Works with Ordered.

net.tmkeesey.relate.Ordered
Interface which extends Equatable and adds a single method, findOrder(Object):int, for determining relative order.

There is also a full complement of unit tests in the flexunit_src folder. All code has full ASDoc comments.

Future additions may include: management of loaded assets, digital puppetry, some general user interface components, animation assistance, collection-related code, buttloads of utility classes, triggers, XML translation, MathML processing, "exoskeleton", and "champagne".

P.S. You may note that I'm defying my previous stance on uncradled brackets. I have to say, I gave them a chance, and I'm starting to understand why people like them. I can't put it into words just yet, but....

30 May 2008

Exopolis Online Ads

Just launched a new Flex minisite: Exopolis Online Ads.

(If you poke around long enough you might find a few little bugs, but it's mostly done.)

This is (obviously) a promotional piece for our banner ad capabilities. Doing the project in Flex made a lot of things easier: transitions, placement, deep-linking, back/forward button capabilities.

It's a bit risky loading banners directly into Flash, but fortunately Flex's AVM1Movie component largely keeps the banner functionality in its own "sandbox" (with a few exceptions that need tending to). Flash banner ads have some of the hackiest programming you'll ever care to see, but fortunately AVM1Movie prevents 99% of it from affecting the rest of the site.

I did get one nice, reuseable thing out of it, too: the MouseScrollCanvas component that controls those scrolling lists of links.

Which reminds me ... I really have to consolidate all the reuseable code I've written someday and release it....

Names, Nodes, and CRUD

The Third ISPN Meeting (mentioned here) is fast approaching. I'm still hoping to have an alpha version of Names on Nodes online by then, but it's going to be tricky. Currently I'm involved in a massive refactoring.

The basic point of Names on Nodes, as I've mentioned before, is to automate taxonomy. That is, you feed it:
  1. a bunch of phylogenetic definitions,
  2. a phylogeny, and
  3. specifier links, that is, correlations between definition specifiers (apomorphies, species, specimens) and units in the phylogeny (e.g., taxa in NEXUS trees).
Once properly fed, it spits out taxonomies, that is, associations of scientific names with sets of subtaxa.

That part of it is pretty much done. But there are two tricky parts I have yet to complete: data persistence and user interface. And what both basically boil down to is CRUD.

I've mentioned CRUD before here. It's an acronym for the four basic operations involved with data persistence, the four things you can do to a stored object. Those are:
  • Create
  • Retrieve
  • Update
  • Delete


As often happens in programming, I started out with an ad hoc sort of approach that worked well enough up to a point, but then I started finding myself in trouble. Duplicated code. Unnecessarily complex code. Code that was hard to update.

It was time to refactor.


Here's a breakdown of the new system.

Every user interface involved with persistent objects is managed by something called a FlowManager. This stores a navigable tree of FlowEntry objects, each associated with a visual FlowComponent.

The main application handles requests from all components within. These are sent to the application as bubbling events, that is, events that "bubble" up through the display hierarchy (say, from a button, to the form that contains it, to the flow manager, on up to the main application). Two of the major types of request are EditEntityEvent and DemandEntityEvent.

An EditEntityEvent comes with a persistent object (e.g., a species, a definition, a NEXUS file, etc.). The application's responsibility is to create a FlowComponent object that will display the entity and allow the user to edit it (Update).

A DemandEntityEvent comes with a class of persistent object (e.g., Species, Definition, Nexus, etc.). The application's responsibility, then, is to provide the "demander" with an object of that class, either by making a new one (Create) or by selecting an existing one (Retrieve).

(Note that I haven't mentioned Delete. I'm leaving that out of the first version. Any deletions will have to be made by myself, manually.)

One problem with my old approach was that I had different user interface components for each combination of CRU[D] action and persistent object. Take a couple dozen types of persistent object and multiply by three: that's how many components I had to make.

The new system, though, has just two types of FlowComponent: one for handling EditEntityEvent requests and the other for handling DemandEntityEvent requests.

The first one is the simplest: EntityEditor. It basically consists of the following components:
  • a form which shows all data in the persistent entity;
  • a bit of text that summarizes the entity in its current state (e.g., for a Binomen entity, something like "Prenomen nomen Author 1970");
  • a button that updates the entity in the database, or, if it is a new entity, creates it in the database; and
  • a "cancel" button.
The form has to be done individually for each type of persistent entity, but the rest is completely generic.

The other FlowComponent object, EntitySupplier, actually uses an EntityEditor object. Once the EntitySupplier object is given the class of entity that it's supposed to supply, it creates a default instance of that class and gives it to an EntityEditor, which it displays to the left. To the right, it displays a SuggestionBox, a grid showing various existing entities that might match what's in the editor.

The SuggestionBox uses a nonvisual object called an EntitySuggester, whose job is to watch for changes that the user makes to the persistent entity and come up with relevant, existing suggestions. For example, suppose the user is editing a new Publication object and starts to type in the authorship as "Linn". The PublicationSuggester sees this and checks the database for possible matches, coming up with "Linnaeus 1758". If this is the publication that the user wanted, then they can select it from the SuggestionBox without having to fill in any more information.

I still have to create a form and a suggester for every type of persistent entity, but this is a much neater division of labor than I had in the last version, where forms generated their own suggestions (which would be wasteful if you were just editing an existing entity).

Hope to get much done this weekend.
(Have to get much done this weekend....)

19 May 2008

Vectors in Flash Player 10

Last week Adobe released a beta version of Flash Player 10. Many exciting new features: 3D effects, a replacement for those clunky old TextField objects (finally!), improvements to the drawing API (which interestingly mirror some work I'd done for my puppet package), access to low-level audio functionality, local file access (no more stupid scripts to bounce files off a server!), etc. One of the most exciting things for me, though, is the addition of vectors.

The word "vector" has a lot of meanings, but in computer science and some branches of mathematics, it basically means "list". Of course, we already have Array objects for creating lists in ActionScript. Indeed, vectors are very similar to arrays, but with one very important difference: the elements must be of a specified type.

Here's an illustration of the difference:
import flash.display.DisplayObject;
import flash.display.MovieClip;
import flash.display.Shape;
import flash.display.Sprite;

var list:Array = [];
list.push(1);
list.push("A String");
list.push(new Object());
list.push(new MovieClip());
list.push(new Shape());
list.push(new Sprite());
trace(list.join(", "));
// Output:
// 1, A String, [object Object], [object MovieClip], [object Shape], [object Sprite]

Note that the elements of the array are of all kinds of different types: a number, a string, a plain vanilla object, and several display objects. But suppose we changed list from an array to a vector with elements of the type DisplayObject:
import flash.display.DisplayObject;
import flash.display.MovieClip;
import flash.display.Shape;
import flash.display.Sprite;

var list:Vector.<DisplayObject> = new Vector.<DisplayObject>();
list.push(1); // throws TypeError
list.push("A String"); // throws TypeError
list.push(new Object()); // throws TypeError
list.push(new MovieClip());
list.push(new Shape());
list.push(new Sprite());

Now the elements must be of a particular type, and attempting to add objects of any other type will throw an error.

Note the syntax for specifying the type of the vector's elements. This is actually an early introduction of parameterized classes, which are going to be part of the ECMAScript 4.0 standard. (They're already features of languages such as Java.) I was surprised that they'd include an ES4 feature so early, but it seems to be implemented only for vectors. I was unable to make my own parameterized classes in the alpha version of Flash CS4. Also, since Vector is a final class, you can't make subclasses, parameterized or not.

Even so, it'll be great to finally have some kind of type-safe collection. I can't tell you how many times I've had to make my own specialized, type-safe classes for this kind of thing.

Vectors will also improve performance, since the compiler can optimize code for vectors of integers, etc. When initializing a vector, you can also fix its length, allowing for further optimization. For example, to store a 3D spatial position as a list of exactly 3 numbers (x, y, and z coordinates), you can use:
var point3D:Vector.<Number> = new Vector.<Number>(3, true);


Can't wait to start using these....

17 April 2008

Comments on the Flex Best Coding Practices

Adobe recently published preliminary coding guidelines for people making contributions to the Flex framework (mx packages). Here's the link:



Although it's specifically meant for the Flex project, the vast majority of their guidelines are applicable to ActionScript 3.0 code in general. Overall, I really like their direction. But I thought I'd take some time to comment on what I don't like or find questionable.

1. Acronyms

When using acronyms in code, the programmer faces a dilemma: convert the case to whatever is appropriate for the context, or leave them all in caps? They opt for the latter, and usually this is fine. However, names that use two acronyms can suffer from ambiguity, as in their hypothetical example loadCSSURL (which some programmers would prefer be rendered loadCssUrl).

Personally, I think there's no good solution here, so I just go with their approach. But I recognize that this approach has problems. As they say about loadCSSURL, "[T]ry to avoid such names."

2. Package names should always be nouns or gerunds

Actually, guys, a gerund is a noun. You're thinking of participles, which are verbs and, in English, look exactly like gerunds. (Gerund: "Walking is fun." Participle: "I was walking.")

Anyway, I don't see why this should be so. I've named a lot of packages after verbs, myself. Is it really that bad to name a package of things that draw something draw as opposed to drawers or drawing?

3. Start interface names with "I"

I've gone back and forth on this one and have finally decided that I actually hate it. Suppose I start out making something an abstract class and then later decide it should be an interface (or vice versa)? Why should I have to rename it when, to external code, nothing has changed? In most cases, external code shouldn't care whether an entity is an interface or a class (the obvious exception being when external code is expected to implement the interface).

I tend to use adjective for interfaces when possible, but often I just use plain old nouns. What's the harm?

4. Brackets on their own lines

They never explicitly recommend this, but all the examples show it. To illustrate what I mean, they recommend this:
function foo():void
{
if (test())
{
doSomething();
doSomethingElse();
}
else
{
doAnotherThing();
}
}
Over this:
function foo():void {
if (test()) {
doSomething();
doSomethingElse();
} else {
doAnotherThing();
}
}


Now I've heard people swear by the former, saying it makes blocks of code much easier to spot. But to me, it seems like a huge waste of space. I can only see so many lines at once, and if half of them are brackets, I'm going to have to be paging up and down an awful lot. Besides, I've been using cradled brackets for over a decade and I don't have any problems spotting blocks.

That said, I've never tried the other way, so I reserve final judgment until I give it a fair chance.

5. Event handler names

The recommend the form eventNameHandler. I like the older ActionScript convention onEventName. Not only is it more succinct, but it has the added benefit of placing all your handlers together when you sort methods alphabetically.

6. Postfix vs. prefix operators

They recommend postfix over prefix operators, despite the fact that prefix operators are generally faster. This completely baffles me. If this:
for (var i:int = 0; i < n; ++i) {
trace(i);
}
...is faster than this:
for (var i:int = 0; i < n; i++) {
trace(i);
}
... then why on Earth would you ever use the latter? It's not like one is more readable than the other. They're equally legible, and one is faster—no contest.

7. Single-statement if blocks

They recommend leaving brackets off. Personally, I prefer to always use brackets—it's more visually cohesive, and it makes things easier when you later realize you do need another statement in there, after all.




By this time it probably sounds like I hate their ideas, but actually, these are the only ones (and I follow that first one, anyway). Everything else is great and much of it had me going, "Yes! Preach it!"

This is something every ActionScript coder should read. Like me, you may not agree on every detail, but overall, it's an excellent guide.