My Stuff
My Email
My Presentations
My Front Page
My Projects
My Music
My Favorite Quotes
Dynamic Language User's Group

Love
Michelle Buxton

Respect
Vincent Foley-Bourgon
Sam Griffith
LeRoy Mattingly
Colin Putney
Matt Secoske
Sam Tesla
Andres Valloud

Admiration
Leo Brodie
Avi Bryant
Alan Cooper
Steve Dekorte
Stephane Ducasse
Doug Engelbart
Eric Evans
Brian Foote
Martin Fowler
Paul Graham
Dan Ingalls
Alan Kay
John McCarthy
Steve McConnell
Peter Norvig
Niall Ross
Randall Smith
Gerald Jay Sussman
David Ungar
Rebecca Wirfs-Brock
...And So Many More...

My Amps
Squeak
JavaScript
Scheme
Java
Corman Lisp
Ruby
Dolphin Smalltalk
Cincom Smalltalk
Self

Archives
05/01/2003 - 06/01/2003
06/01/2003 - 07/01/2003
07/01/2003 - 08/01/2003
08/01/2003 - 09/01/2003
09/01/2003 - 10/01/2003
10/01/2003 - 11/01/2003
11/01/2003 - 12/01/2003
12/01/2003 - 01/01/2004
01/01/2004 - 02/01/2004
02/01/2004 - 03/01/2004
03/01/2004 - 04/01/2004
04/01/2004 - 05/01/2004
05/01/2004 - 06/01/2004
06/01/2004 - 07/01/2004
07/01/2004 - 08/01/2004
08/01/2004 - 09/01/2004
09/01/2004 - 10/01/2004
10/01/2004 - 11/01/2004
11/01/2004 - 12/01/2004
12/01/2004 - 01/01/2005
01/01/2005 - 02/01/2005
02/01/2005 - 03/01/2005
03/01/2005 - 04/01/2005
04/01/2005 - 05/01/2005
05/01/2005 - 06/01/2005
06/01/2005 - 07/01/2005
07/01/2005 - 08/01/2005
08/01/2005 - 09/01/2005
09/01/2005 - 10/01/2005
10/01/2005 - 11/01/2005
11/01/2005 - 12/01/2005
12/01/2005 - 01/01/2006
01/01/2006 - 02/01/2006
02/01/2006 - 03/01/2006
03/01/2006 - 04/01/2006
04/01/2006 - 05/01/2006
05/01/2006 - 06/01/2006
06/01/2006 - 07/01/2006
07/01/2006 - 08/01/2006
08/01/2006 - 09/01/2006
09/01/2006 - 10/01/2006
10/01/2006 - 11/01/2006
11/01/2006 - 12/01/2006
12/01/2006 - 01/01/2007
01/01/2007 - 02/01/2007
02/01/2007 - 03/01/2007
03/01/2007 - 04/01/2007
04/01/2007 - 05/01/2007
05/01/2007 - 06/01/2007
06/01/2007 - 07/01/2007
07/01/2007 - 08/01/2007
08/01/2007 - 09/01/2007
09/01/2007 - 10/01/2007
10/01/2007 - 11/01/2007
11/01/2007 - 12/01/2007
12/01/2007 - 01/01/2008
01/01/2008 - 02/01/2008
02/01/2008 - 03/01/2008
03/01/2008 - 04/01/2008
04/01/2008 - 05/01/2008
05/01/2008 - 06/01/2008

Feed

Add this feed to a running copy of BottomFeeder

Wednesday, May 14, 2008

Standards Gone Wild

 
There was a discussion recently on standards where one poster said that they were big on alignment. Here's an exchange:
Hi__ jwen,

jhdn> Simple solution: set in your coding standards that ALL
jhdn> classnames MUST be a specific length, and also dictate specific
jhdn> lengths for all member variables, method names, etc. etc.

Hmmm_, I___ thnk that mght caus more prbs, mayb even a___ rvln from
the_ devs. Not_ to__ mntn that it__ lmts your cr8v ablt to__ use_ good
nams and bild a dict* that hlps bild betr apps.

Grgg

* I Just couldn't come up with a four letter substitution for
"vocabulary". :)

Classic. I laughed coffee through my nose. It hurt, but was well worth it. I'm glad I don't work somewhere they have standard on the size of my variables. I don't think I would be working there much longer.

Labels:


Comments

Tuesday, May 13, 2008

Javascript: Stop Fighting It

 
I recently came to the realization that I've been fighting Javascript too much. It's because I've been going against the grain with it. It's like trying to force the OO paradigm in a functional language or the opposite. You might say that I've been treating Javascript like an OO language and you would be right. But, I've been forcing my class-based thinking on it and it's been not so nice.

I've been reacquainting myself with Self and Io again. And it hit me like a rhino slamming into me. I've been doing Javascript all wrong. I should have treating it like the prototype-based language that it is. Sure, it doesn't have the ability to inherit from multiple prototypes like Self, but the way to succeed is with prototypes. Forcing class-based OO is like walking up the rainbow and finding no pot of gold at the end.

First, let's write the following:
Object.prototype.clone=function() {
var creator=function() { this.constructor=arguments.callee };
creator.prototype=this;
return new creator();
}

Object.prototype.mixIn=function(definitions) {
for (var each in definitions) if (definitions.hasOwnProperty(each)) {
this[each]=definitions[each];
}
}

It's just two methods up on the Object prototype. Why clone is not part of the Javascript standard is beyond me. Clone is required in all the other prototype-bases languages I have seen. It is the only way to create new objects. Enough complaining, it was only a few lines of code. All my clone method does is make the object I call it on the prototype of the result. I get a clean object with all of the properties of the receiver inherited. Nice. This is the behavior we want. Next, I added a convenience method to Object to mix-in in other objects. This is helpful to keep my code organized. I can just create a hash object with my functions and properties like before. So far, this is standard stuff. But, here is how I use it:

Pounds = new Object();
Pounds.mixIn({
of: function(value) {
var result=this.clone();
result.value=value;
return result;
},
toString: function() {
return this.value.toString() + " lbs";
},
value: 0
});

print(Pounds.of(5)); // => 5 lbs
print(Pounds); // => 0 lbs
print(Pounds.isPrototypeOf(Pounds.of(5))); // => true

Notice, normally, you define the constructor with the first letter of the name upper cased. I no longer need the constructor, so I upper case on the prototype that will be the example for all the instances that I clone off it. The example above is a measurement class. "Pounds" is my example so I default it with values that the objects that I clone from will have. This is how prototype-based languages work. It feels slightly unusual coming from the class-based background, but I think it makes my Javascript look a lot less alien. I like it.

Let's look at a more complicated example shall we?

Animal = new Object();
Animal.mixIn({
name: "Unknown",
sound: function() {
return "?";
},
toString: function() {
return this.name
+ " goes " + this.sound()
+ " and weighs "
+ this.weight.toString();
},
weight: Pounds.of(0)
});

Cat = Animal.clone();
Cat.mixIn({
name: "Unknown Cat",
sound: function() {
return "Meow";
},
weight: Pounds.of(10)
});

grendel = Cat.clone();
grendel.mixIn({
name: "Grendel",
sound: function() {
return this.constructor.prototype.sound.call(this) + " and Purr";
},
weight: Pounds.of(20)
});

gracie = Cat.clone();
gracie.mixIn({
name: "Gracie",
sound: function() {
return "Purr";
}
});

print(Animal); // => Unknown goes ? and weighs 0 lbs
print(Cat); // => Unknown Cat goes Meow and weighs 10 lbs
print(Animal.isPrototypeOf(grendel)); // => true
print(grendel); // => Grendel goes Meow and Purr and weighs 20 lbs
print(gracie); // => Gracie goes Purr and weighs 10 lbs

"super" is implemented with "this.constructor.prototype". It seems wordy, but prototype on the object is not built-in to Javascript. Besides, you should use "super" sparingly. To me, this reads better and works better for inheritance. I have dropped all references to classes. This makes meta-programming easier as well (I simply walk up the prototype chain with "this.constructor.prototype" and iterate through the properties.

The constructor function used as a class always seemed awkward to me. It was inelegant, but the above fits Javascript coding better. The reason is because I'm now using it as a prototype-based language and not forcing class-based OO on it. The above is meant to get started playing around. Prototype-based programming is so cool and I'm still exploring all of the possibilities. There's little documentation, but the little that is well worth the effort to track down. Have fun!

The example above was tested in SpiderMonkey. A great little REPL for playing with Javascript.

Labels: , ,


Comments

Two years after XP

 
I feel like I can finally write about my XP experiences. I was once a member of the largest XP teams in the country for three years. The XP practices were the main reason for me joining the team. I had been experimenting with agile at my prior work places with great success, but no one wanted to jump in. I found this team and they were up to their necks in it. I loved the thought of it. The people were passionate, caring, and intelligent. What could go wrong?

Nothing went wrong. But, I'm a bit of a skeptic now when some company touts agile to me now. I'm a bit shell-shocked. How could this possibly happen? I'll just list them. Don't worry it's only a few.

  • Everyone owns the code

  • In theory, this sounds wonderful. It really does and I think it works on a small team of 3-4 dedicated developers. It doesn't scale beyond that. The 3-4 developers must be dedicated to keeping the code clean too. If someone fails to clean up ugly code, then it quickly turns into glue. It turns against you if everyone thinks that everyone else will do the cleanup. There are plenty of negatives to personal code ownership, but the point is to have at least two people as masters of each section. Multiple eyes should see any code commit. But, someone or a pair should own it.
  • Mandatory pairing

  • Pairing sounds so good on paper, but it completely takes away the human element. Programmers are introverts by and large. Pairing can wear out some people quickly. I found forced pairing tiresome because not all folks get along. There were some people that I would enjoy pairing with and I learned a lot from. I would always want to pair with them, but other folks it was a constant struggle. I think pairing should be an optional activity that developers should naturally want to do when brain storming or checking in code. I find that code reviews with a pair of eyes who have never seen the code that I am checking is always a good thing. This should be done often. If you think about it, what I am describing is collaboration. Pairing to me as a term basically means one side can turn off. Collaboration is where both sides are equally engaged.

You will notice I didn't list test-driven development above. If anything, XP got that one right. I write tests for everything and stand behind them. I don't see how anyone can stand behind their work without them. I even write tests for my research code. I'm still 100% agile, but I think each practice needs to be tailored to your team. Don't blindly follow the book. If something hurts, don't keep picking at it. You might lose the limb and your project.

This is only the beginning. I plan to write more the subject.

Labels: ,


Comments
  • Pair programming is great, but all pairs are not created equal. I used to pair with someone and we were extremely effective together, but when we were finished I would be exhausted. Somehow our interaction required a lot of energy even though we were not at odds with each other. After a few of these sessions I was reluctant to do it anymore. Funny thing.

    By Blogger Carl Gundel, at 3:41 PM   

Monday, May 12, 2008

My Passion

 
I guess I don't conceal my passion and love for Smalltalk very well:
...seeing Blaine’s eyes light up every time he got to either hear or utter a sentence that included the word “Smalltalk”.

To me, Smalltalk defines elegance. If you want to see elegance in computing, go download Squeak right now. The very least that will happen is it will warp your mind and make you a better programmer. It might even make you see the world a little differently.

Labels: ,


Comments
  • Indeed. I'm very happy with my "year of smalltalk", in which I get to remember and rediscover a language I had learned 27 years ago, and use it for commercial applications (via Seaside).

    By Blogger Randal L. Schwartz, at 12:47 AM   

Seaside Presentation

 
Just a reminder I have my Seaside presentation (scaled down a bit from the BarCampKC one ala no database mappings) and my Smalltalk Coding competition (100% Seaside) here. So, if you missed the presentation, feel free to download the Seaside presentation image and the coding competition. Lots of good examples to pour through in each. I'm going to try to put instructions with the new presentation and get it published. But, in the meantime, you can check out these older (not that old) materials. I will also remind folks to read Introduction to Seaside. It's a great and fast introduction into the coolest web framework on the planet!

Labels: , ,


Comments

BarCamp KC

 
I attended and presented at my first BarCamp this weekend. What a blast! I would like to thank Pete for putting on such a wonderful event. I'm always in need to mingle with brilliant folks and BarCampKC had them in spades. I enjoyed the discussions on Ruby, Situated Web Application Platforms, UML, customers, and of course, Seaside. It was well worth the 3 hours to attend and I would do it again in a heartbeat. My only wish is that it had been longer. I'll be making some more blog posts based on discussions had. If anyone has the chance to attend a BarCamp, please do. I know I made several new friends over the weekend.

And what would you know? No sooner that I have unpacked my bags and there's a webpage for BarCampOmaha. You can count me in being there and presenting something. Perhaps this time, I will give my Advanced Javascript talk (ran out of time in KC) or maybe I'll do something completely different. We'll see. I'll be having lots of fun this summer.

Labels: ,


Comments

Sunday, May 11, 2008

Quote that describes OO perfectly

 
I grabbed this from Io Language Guide:
In all other languages we've considered [Fortran, Algol60, Lisp, APL, Cobol, Pascal], a program consists of passive data-objects on the one hand and the executable program that manipulates these passive objects on the other. Object-oriented programs replace this bipartite structure with a homogeneous one: they consist of a set of data systems, each of which is capable of operating on itself.
- David Gelernter and Suresh J Jag

I couldn't have said it better myself. It's not what Paul Graham says at all. I can't help it if he never took the time to understand it.

Labels:


Comments
  • I infer from this that you've not read the Structure and Interpretation of Computer Programs. That book's all about blurring the line between code and data using Lisp/Scheme.

    Frankly, if you think that Lisp's imperative in the same way as the other languages in that list then you've not understood Lisp.

    I still prefer to program in an OO language, but Scheme and Lisp both have features that it would be very cool to see in Ruby, but one of the biggies is uniform representation of code and data which means that Lispers can take a chunk of data and write a custom interpreter for it without having to write a parser at the same time.

    By Blogger pdcawley, at 2:03 AM   

  • I wouldn't have listed SCiP if I had not read it. I own quite a lot of Lisp books and have studied it extensively. You are right, the way Lisp handles things is different from other imperative languages. I was really ripping on Paul Graham (who I admire deeply, but his rips on OO, really stem from Java and C++, are not accurate. And that quote just inspired me to write about it). I think functional programming and object-oriented programming go hand in hand. They need each other.

    I think one without the other is missing the point.

    By Blogger Blaine, at 5:47 AM   

  • Reminds me of http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html?page=1

    By Blogger Corey, at 9:27 AM   

Lost The Fight

 
You know you've lost the fight when you make direct attacks on your competitor on your front page. Do you see google slinging mud? You don't have to sling when you're so far in the lead. Only the company in 2nd place needs to do those things.

Labels:


Comments

Friday, May 09, 2008

Seaside at Bar Camp Kansas City

 
If you are in Kansas City tomorrow and want to learn more about Seaside, then come to BarCampKC. I will be giving a presentation on Seaside. It's the one you can download from SqueakMap, but beefed up. I've included how to do GLORP, script.aculo.us, and more! I will be showing off Smalltalk and Squeak in the process. If you ever wondered why Smalltalk was so cool, now is the time to find out. See you there!

Labels: , , ,


Comments

UML, Design, and Paper

 
Why did the UML design tools fail? By fail, I mean never gain popular acceptance. To this day, I still do my designs by hand and then do them in a drawing tool when they are solidified. The UML tool makers never understood that when designing, you need to be able to make mistakes and explore different options. Instead, they forced you to make decisions too early in the process so they could auto-generate your code. I always found it cumbersome and they got too much in the way. And that's why they failed. I love paper. All of my friends that design still use paper for their designs as well. The reason is that you can try out ideas and the design can always be thrown away. Design is an exploration journey. The tools only looked at the destination and not how to make the journey easier. The journey is what mattered.

Labels:


Comments
  • Hi, Blaine,
    Hi agree with you for what you say, but I use a different solution: I use an old (1998) version of Rose. Is fast, small, (everything on few mb), limited (but it has what I need, just a bit less than on UML Distilled) and allow me to go faster than using pencil and paper.
    Whenever I try a more modern designer, but full of (un-necesssary) stuff, slow and heavy, it seems to me that it require too much time to work with, and to much precision.
    Never found a better one that the old one.

    By Blogger giorgio, at 5:10 PM   

  • Blaine, I totally agree. And it's pretty obvious that the developers of Enterprise Architect never actually had to use it themselves. There are just too many clicks and things to type just to communicate something. Yet some people love it because if it's expensive and "enterprise" it must be good.

    Anyway, I use a combination of powerpoint and this little tool here: http://umlsculptor.sourceforge.net/
    which, like Rose circa 1998, is also fast, small, and limited.

    By Blogger Corey, at 9:18 AM   

Tuesday, May 06, 2008

Comments on Binstock on Software: Perfecting OO's Small Classes and Short Methods

 
OK, when I originally linked to Binstock on Software: Perfecting OO's Small Classes and Short Methods, I had not read the comments. Wow. Varied opinions and were a lot of fun to read. I would like to comment on a few.

One mentioned using automated enforcement software to make sure developers abide by these rules. I used to love this idea because I would run those tools over my own code. But, once I made it public what I was doing, my fellow developers would figure out ways around it. It's human nature. Now, I keep those tools to myself and use them on my own code. I think code beauty is a personal thing and strict enforcement to one standard is an open rally call to defy it. The end result is code that is worse than it was before.

Secondly, I took the rules to be a an exercise to limit your code in extreme ways so that the power of the message send comes through and the ugliness of data structures is exposed. The point is let go of central control in your objects. For that, I think this exercise is gorgeous.

Lastly, I think the recommendations are things to strive for. It makes you code more readable, testable, and flexible. Who wouldn't want to strive for those things?

Comments

I cried

 
I almost cried for joy when I read this post on one of my favorite topics: Small Classes, Short Methods. Someone has been reading my mind. I love the set of rules. It's something that I strive for in my code. I've run into problems with other developers though (they generally think I am nuts when I wrap things like phone numbers, ids, domain specific codes, etc into objects instead of strings). But, by wrapping the primitive into an object that states it's role, you start moving logic closer to where it belongs. The books "Genius Within" and "Prefactoring" were the books that really brought this home for me (especially "Genius Within"). Lots of great advice. Go read it now!

Labels: ,


Comments

Monday, April 14, 2008

Missing Explanations

 
I was looking over my last post and forgot that I didn't discuss these two methods below:
Function.prototype.everyTimeButFirst=function() {
var self=this;
var toCall=function() {
toCall=self;
return null;
};
return function() {
return toCall.apply(this, arguments);
};
}

Array.prototype.toString=function() {
var result="[";
var addComma=function() { result = result + ", " };
var addCommaOnlyAfterFirst=addComma.everyTimeButFirst();
Array.prototype.each.call(this, function(every) {
addCommaOnlyAfterFirst();
result = result + every;
});
return result + "]";
}

It might seem a little overkill to have the everytimeButFirst function, but I think it reads better in the method and communicates the intent. Normally, you could implement putting in the comma in between items in the collection like so:

Array.prototype.toString=function() {
var result="[";
var shouldAddComma=false;
Array.prototype.each.call(this, function(every) {
if (shouldAddComma) {
result = result + ","
} else {
shouldAddComma=true;
}
result = result + every;
});
return result + "]";
}

It's a little bit longer. I hate the boolean variable "shouldAddComma". I really do. It just doesn't read well. It's hard to see what's going on. The naming makes it better. But, it's just adding unnecessary noise.

But, all is not well in the first version that I used either. Not all programmers are versed in functional programming, but even a functional programmer would scoff at the first version. Why? It changes state. Plus, the implementation of everytimeButFirst while clever would not be obvious. Basically, what you're seeing is my experiment in using nothing but functions instead of a boolean. Fun for blogging and brain stretching, but not for production systems. Clever is the enemy of the maintenance programmer. But, what if we did this:
Function.prototype.everyTimeButFirst=function() {
var shouldExecute=false;
return function() {
if (shouldExecute) {
return toCall.apply(this, arguments);
} else {
shouldExecute=true;
return null;
}
};
}

You might say I just displaced the boolean to somewhere lese and you would be right. But, I got it out of the method toString which is where I didn't like it. It's safely behind a wall where it makes sense to have. The internal implementation of everyTimeButFirst was too clever the first time around. It is still using higher-order functions, but one is easier to understand than nested ones that change themselves out.

Remember I said the original implementation would make a functional programmer gag because of the side-effects. We could make it side-effect free by making it recursive. But, Javascript is not optimized for tail-recursion. So, I did what I thought was best.

Labels: , ,


Comments

Sunday, April 13, 2008

"Super" was wrong

 
My implementation of "super" was wrong. I did an implementation in this blog post. It was wrong for several reasons. The number one reason was because it was too complex. The first hint that it was too complex was when I was setting the "constructor" property manually. This is done for you and only needs to change if you set the constructor's "prototype" property with "{}" or "new Object()". I was guilty of the this sin. Turns out if I play by the rules, I don't need the "subclassFrom" function nor do I need to add the special "super" properties. It's actually less verbose and it's playing by the Javascript rules. When in Rome, do as the Romans.

My second mistake was that I thought each object had an immutable property "prototype". This is why I was getting "undefined" when I asked for it. I should have known that I was wrong and not the implementation. Anyway, my belief was WAY WRONG. I don't know where I got this piece of mythology from. I think I pulled it from the sky. The truth is that the "prototype" property is only on Function objects. It's set on the objects it constructs and it is not available. Mozilla and Adobe implementations have a property "__proto__" that stores it, but it is not in the standard and thus, not to be used. All objects by the standard should get their prototype from their "constructor" property. Learn something new everyday.

For the new implementation, I got rid of the "subclassFrom". It's not needed now and I'm only left with the "methods" function from before. It now simply moves properties from one object to another. It's only for syntactic shorthand now. I did add something new: function "proto". It's "super" basically. Here's the implementation:

Function.prototype.methods=function(funcs) {
for (each in funcs) if (funcs.hasOwnProperty(each)) {
this.prototype[each]=funcs[each];
}
}
Object.prototype.proto=function() {
return this.constructor.prototype;
}

So, how do you do super by playing by the rules? Here's how:
Function.prototype.methods=function(funcs) {
for (each in funcs) if (funcs.hasOwnProperty(each)) {
this.prototype[each]=funcs[each];
}
}

function Base() {
print("base constructor called");
}
Base.prototype.toString=function() { return "aBase"; }

function Sub() {
this.proto().constructor.call(this);
print("sub constructor called");
}
Sub.prototype=new Base();
Sub.prototype.toString=function() { return this.proto().toString.call(this) + " and aSub"; }

Output from the above:
base constructor called
********
base constructor called
aBase
********
base constructor called
sub constructor called
aBase and aSub

Notice the "this.proto().constructor.call" in the Sub constructor function, it expands to "this.constructor.prototype.constructor.call". This is calling the "super" constructor. We could also do "arguments.callee.prototype.constructor.call" instead, but really it's a lot to type in isn't it? We also couldn't put that into a function as easily without calling "arguments.callee".

I got a better implementation and something that's more like Javascript. I like keeping my Javascript close to what a Javascript developer would expect. Prototype-based programming is powerful and it's worth exploring things without classes. But, that's a small digression. All I wanted was super and some shorthands for grouping my methods. I have that now.

Labels: ,


Comments

Annotations and Aspects in Javascript

 
Here's the moment, I've been building up to:
var logAround=function(func,name) {
this[name]=defineAround(function(proceedFunc) {
print("before: "+name+" "+Array.prototype.slice.call(arguments,1));
var result=proceedFunc();
print("after: "+name+" "+result);
return result;
}, func);
}

var doesItLog=function(each) {
return each.log == true;
}

Transaction.prototype.eachFunction(logAround.onlyWhen(doesItLog));

var test=new Transaction();
test.begin();
test.commit();

Here's the output:
js> load("aspect.js")
before: begin []
begin
after: begin undefined
before: commit []
commit
after: commit undefined

Not much to explain at all. I think the code speaks for itself. The output shows the arguments passed in and what the results were from the call. I didn't return anything from either method, but it wouldn't be hard to verify that it does indeed work. I implemented my own "toString" for Arrays to print out the arguments and it's worth looking at. "arguments" is not an array, but we can call array functions on it. Most of the built-in Array functions can be called on any object. You just have to use the wordy "Array.prototype.functionName.call" to use it.

I wrote this for this blog post, but I'm planning on beefing it up with exception handling and un-weaving among other things. I also plan on adding more tests to my test suite that I did not show. The purpose was to show some cool tricks in Javascript and I hope it was fun.

And here's the entire implementation once more:
function defineBefore(beforeFunc, proceedFunc) {
return function() {
beforeFunc.apply(this,arguments);
return proceedFunc.apply(this, arguments);
};
}

function defineAfter(afterFunc, proceedFunc) {
return function() {
var result=proceedFunc.apply(this, arguments);
afterFunc.apply(this,arguments);
return result;
};
}

function defineAround(aroundFunc, proceedFunc) {
return function() {
var args=Array.prototype.slice.call(arguments,0);
args.unshift(proceedFunc.bindTo(this));
return aroundFunc.apply(this, args);
};
}

Function.prototype.bindTo=function(thisObject) {
var selfFunc=this;
return function() {
return selfFunc.apply(thisObject, arguments);
};
}

Function.prototype.everyTimeButFirst=function() {
var self=this;
var toCall=function() {
toCall=self;
return null;
};
return function() {
return toCall.apply(this, arguments);
};
}

Function.prototype.onlyWhen=function(ruleFunc) {
var self=this;
return function() {
if (ruleFunc.apply(this, arguments))
return self.apply(this, arguments);
}
}

Object.prototype.each=function(everyFunc) {
for (var name in this) if (this.hasOwnProperty(name)) {
everyFunc.call(this, this[name],name);
}
}

Object.prototype.eachFunction=function(everyFunc) {
this.each(everyFunc.onlyWhen(function(every) {
return every.constructor == Function;
}));
}

Object.prototype.run=function(func) {
func.call(this);
}

Object.prototype.define=function(name, annotations, func) {
this[name]=func;
annotations.each(function(each, name) {
func[name]=each;
});
}

Array.prototype.each=function(everyFunc) {
for (var index=0; index < this.length; index++)
everyFunc.call(this, this[index], index)
}

Array.prototype.toString=function() {
var result="[";
var addComma=function() { result = result + ", " };
addComma=addComma.everyTimeButFirst();
Array.prototype.each.call(this, function(every) {
addComma();
result = result + every;
});
return result + "]";
}

Labels: ,


Comments

Annotations in Javascript

 
Last post, I talked about how to implement crude aspect advices. I say crude because the implementation would need to be beefed up a bit for wider use. The ideas were more important. I wanted to spend the article on the tricky bits of implementation. I'll take the same tactic with this article.

Let's start with what our code will look like. In fact, let's implement something everyone is familiar with: a transaction. Now, our transaction will have a blank implementation (we'll print out the important bits). It's the API that we will care about later. Here's the definition:
function Transaction() {
}
Transaction.prototype.run(function() {
this.define(
"begin",
{log: true},
function() {
print("begin");
});
this.define(
"commit",
{log: true},
function() {
print("commit");
});
this.define(
"rollback",
{log: true},
function() {
print("rollback");
});
this.toString=function() {
return "i am transaction";
}
});

OK. There's some new functions named "run" and "define". I'll show their implementations soon. You can probably guess the implementation of "run". It's simply so that my hands don't get tired typing "Transaction.prototype". I could use "with {}", but I have found its implementation inconsistent among Javascript dialects. The next new function, "define", is how we're going to define our annotations. It's a shorthand for better readability and to reduce duplication. All it will do is add the function to our object and add the annotations as properties. Annotations are simple in Javascript because functions are just objects and we can add anything we want to them. How cool.

Here's the implementations:
Object.prototype.run=function(func) {
func.call(this);
}

Object.prototype.define=function(name, annotations, func) {
this[name]=func;
annotations.each(function(each, name) {
func[name]=each;
});
}

Both are straightforward. But, I introduced another function: "each". Those familiar with Ruby will notice what it does right away. For the non-Rubyists, it iterates over all the properties of the object. My implementation also sends the name of the property as an extra parameter. Here's how I did "each":
Object.prototype.each=function(everyFunc) {
for (var name in this) if (this.hasOwnProperty(name)) {
everyFunc.call(this, this[name],name);
}
}

It basically allows me not to have a "for" loop. Simple. You might have noticed my use of "call". The reason is because I wanted to pass along "this" to the function passed in.

That is it for implementing annotations. The query language is already built in (albeit a little verbose). We only have to iterate over the functions of an object. Here's some code I would like to use to test my annotations and query implementation:

var every=function(each,name) {
print(name);
}
var doesItLog=function(each) {
return each.log == true;
}
Transaction.prototype.eachFunction(every.onlyWhen(doesItLog));

Oh boy. Can you guess the output from the above? Here it is:
begin
commit
rollback

The annotations I have is to mark a function to be logged on entry and exit. I'll spend the rest of the article on the implementation and bring together the annotations, aspects, and logging in the next article.

Let's talk about the new functions: "onlyWhen" and "eachFunction". I think you can guess what each of them do. "onlyWhen" is defined on a function and takes a function to check the arguments for some condition. If the condition is true, it executes the receiver function. It returns a function that brings all of this together. This is more functional programming at work. "eachFunction" takes a function that will be called for each function that is a value of a property on the object.

Like always, here's how I implemented them:
Function.prototype.onlyWhen=function(ruleFunc) {
var self=this;
return function() {
if (ruleFunc.apply(this, arguments))
return self.apply(this, arguments);
}
}

Object.prototype.eachFunction=function(everyFunc) {
this.each(everyFunc.onlyWhen(function(every) {
return every.constructor == Function;
}));
}

In the "onlyWhen" implementation, I have to bind "this" (the function) to self so that we can use it later in the function that we use a result. "this" will be bound to a different object. "eachFunction" brings together the functions "each" and "onlyWhen".

That's it! You could of course add implementations to define annotations so that we make sure that only pre-defined ones are used in functions. I'll leave that as an exercise to the reader. It wouldn't take much to implement it. The next article will put everything together. All we have to do now is weave based on rules. We have the means to iterate over functions and we have the means to replace implementations through our advices. The next article will mix this batter.

Labels: ,


Comments

Friday, April 11, 2008

Aspects in Javascript

 
Just like I promised! I'm going to describe how to do aspects in Javascript. Now, this example will be simplified. You will probably want to beef up the implementation given here. I'm really showing off an idea and how you can apply it to your Javascript libraries. I did this for fun and was shocked how easy it was. In these examples, I will be using Spidermonkey.

I'm first going to show off how to implement advices. Let's start with "before" advice and then have a simple test for our implementation. I would recommend using JSUnit for testing. I'm simply going to output it for demonstration purposes.

The easiest advice to implement is "before". All we need to do is define a function that creates a new function that calls our before function and then calls the function we originally wanted to call. "defineBefore" handles this quite nicely. The rest of the code below is defining our "before" advice and the function we want to call and then doing the wrapping. Pretty simple.

function defineBefore(beforeFunc, proceedFunc) {
return function() {
beforeFunc.apply(this,arguments);
return proceedFunc.apply(this, arguments);
};
}

function printArg(x) {
print("proceed: " + x);
return x + 1;
}

before=function(x) {
print("before: " + x);
}
printArg=defineBefore(before, printArg);
print("result: "+printArg(6));

Here's the output:

js> load("aspect.js")
before: 6
proceed: 6
result: 7

You can see from the results that our "before" advice implementation can look at the arguments (but, not change them, we'll get to that). And be basically benign to the whole operation. Our weaving works!

"After" advice is equally as easy. We just need to remember the result and return that from our weaved function. Again, the "after" function will be benign and not be able to change the result. Here's the implementation:

function defineAfter(afterFunc, proceedFunc) {
return function() {
var result=proceedFunc.apply(this, arguments);
afterFunc.apply(this,arguments);
return result;
};
}

after=function(x) {
print("after: " + x);
}
printArg=defineAfter(after, printArg);
print("result: "+printArg(8));

Here's the results:

js> load("aspect.js")
before: 8
proceed: 8
after: 8
result: 9

Now, our "before" and "after" advice weaving did not allow us to change the arguments or results. I wanted to keep it simple without a lot of complications. If we need to change the arguments or tamper with the result, let's do it with an "around" advice.

The implementation for "around" is a little bit more complicated. I want to make calling the proceed function as simple as possible in the after advice function. To do this, I need to wrap the proceed function with another function that will bind the "this" so that we don't have to worry with sending "call" on the proceed function. The implementations before didn't have to deal with the proceed function in the advice and that made life easier. Now, we'll have that control and with that power, comes the ability to change arguments and results. Here's the implementation:

Function.prototype.bindTo=function(thisObject) {
var selfFunc=this;
return function() {
return selfFunc.apply(thisObject, arguments);
};
}

function defineAround(aroundFunc, proceedFunc) {
return function() {
var args=Array.prototype.slice.call(arguments,0);
args.unshift(proceedFunc.bindTo(this));
return aroundFunc.apply(this, args);
};
}

function concatAndPrint(first,second) {
print("first: "+first);
print("second: "+second);

var result=first + second;
print("concat result: "+ result);

return result;
}
around=function(proceedFunc, first, second) {
print("around first: "+first);
print("around second: "+second);
var result=proceedFunc(first, second);
return result + "c";
}
concatAndPrint=defineAround(around, concatAndPrint);

print("final result: "+concatAndPrint("a","b"));

And where would we be without the results?

js> load("aspect.js")
around first: a
around second: b
first: a
second: b
concat result: ab
final result: abc

One more detail, I didn't do an error handling or recovery. You will probably want to wrap any kind of exceptions that might happen in the proceed function and take appropriate action.

So far, our implementation is nice and clean. We're mainly using functional programming concepts for it. The next steps is writing the implementation for the pointcuts and combining that with what we did here. I'll also going to show how to define annotations. Trust me it's going to get more fun as we combine the batter and get ready to bake!

Labels: ,


Comments

Tuesday, April 08, 2008

Javascript Inheritance with super

 
One thing that has always bothered me about Javascript is there is no implementation of "super". Most texts suggest to simply call the super function explicitly via its prototype. It makes for refactoring your inheritance hierarchy no fun because of the direct calls. And let's not mention all the duplication.

Let's think for a minute. Everything in Javascript is an object. What if we added the super automatically to the overriden functions so we could get access to it? And while we are at it, why not make our object definitions a bit more explicit along the way?

So, I whipped up the following code:

Function.prototype.subclassFrom=function(superClassFunc) {
if (superClassFunc == null) {
this.prototype={};
} else {
this.prototype=new superClassFunc();
this.prototype.constructor=this;
this.superConstructor=superClassFunc;
}

}
Function.prototype.methods=function(funcs) {
for (each in funcs) if (funcs.hasOwnProperty(each)) {
var original=this.prototype[each];
funcs[each].superFunction=original;
this.prototype[each]=funcs[each];
}
}

It's two very short functions. But, it allows me to do this:

function Parent(z) {
this.z=z;
}
Parent.subclassFrom(null);
Parent.methods({
methodOne: function(x) {...},
methodTwo: function() {...}
});

function Child(z,y) {
arguments.callee.superConstructor.call(this,z);
this.y=y;
}
Child.subclassFrom(Parent);
Child.methods({
methodOne: function(x) {
arguments.callee.superFunction.call(this,x);
...
},
methodThree: function() {...}
});

"arguments.callee.superFunction.call" is a little verbose, but it's better than duplicating the name of my "super" implementation prototype all over the place. Plus, how often do you call "super". I generally think too many calls to "super" is a design smell.

I like this approach mostly. The only thing I don't like is the names I chose. But, I'll keep working on it. I was just happy in two functions, I have "super" in my constructors and functions. If anything, it's a different way of thinking about the problem.

Coming next, how to do aspects and annotations in Javascript.

Labels: ,


Comments
  • Take a look at Joose (http://use.perl.org/~malte/journal/35836 et. seq.) which is a port of the Moose meta-object model first from Perl6 to Perl5, and now to Javascript. It might have exactly what you're trying to build.

    By Blogger Randal L. Schwartz, at 9:29 AM   

  • Also take a look at Prototype's Class.addMethods. It is less verbose, and also requires you to declare in the arglist that you want to send to super, which meshes well with "super sends should be avoided".

    By Blogger Stephen, at 1:49 PM   

  • Unfortunately Javascript is still on my to-learn list, but to me this looks like a problem best solve either with list based or standard delegation, like you would find in Slate and Self respectively... or by creating a derive function that automatically assigns a super field.

    If I'm understanding you correctly Javascript has no mechanism for super calls, so you might need to derive a proxy object that can delegate automatically... I'm assuming here that Javascript provides a catch all field not found message that you can implement (it's been a while since I last looked at the design of Javascript).

    With such a proxy object, you simply use a custom constructor method that assigns to its clone the delegate field, and hey presto... super calls. You could even automatically add these catch all methods to automatically call the super object for you, if you wanted to.

    By Blogger Lorenz, at 5:57 AM   

  • Thanks for all of the comments. Joose was cool as was Prototype. I like looking how different developers looked at this issue. Anyway, I guess I should have not used the word "class". I really wanted to keep the Javascript prototype.

    On Javascript:
    There is no doesNotUnderstand or method_missing in Javascript so it makes proxies difficult. Also, unlike Self, Javascript's prototype implementation only gives you on slot so that you can not do what you would normally do in Self. You get one slot and the only way to access a a function that you inherit from (via the prototype immutable slot) is to call it explicitly. I find that quite repulsive.

    If I had a wishlist, I would have a method_missing implementation, cheap syntactical functions and adding more of the Self prototype implementation (parent slots, etc).

    Sadly, I don't think of any of those are in the ECMA Standards for future versions nor are they in ActionScript.

    By Blogger Blaine, at 7:39 AM   

  • Waiting with baited breath for the aspects and annotations post...

    By Blogger Sean, at 8:11 AM   

  • How about YUI's extend? I've used that many times with wonderful results.

    By Blogger MikeHoss, at 11:21 AM   

Saturday, April 05, 2008

A Phrase Past Its Expiration Date

 
I've been a fan of Roger von Oech for a long time. I love his books, blogs, and cards (yes, cards). His latest blog entry entitled, "A Phrase Past Its Expiration Date", struck a chord with me that I thought I would share. In it, he asks his readers what phrases are overused and should be put to rest. His phrase was "It is what it is." The reason why was because it is commonly used to end debate and thought.

There are several phrases that carry the same role. Here's mine:

  • "YAGNI" also known as "You Ain't Gonna Need It"
    If I never heard this phrase again in my entire life, it would be too soon. I hate it. The original intention was well meant, but many a poor developer took it the wrong way. I've heard it uttered too many times to end discussion because a weak mind couldn't support their assertion.

  • "Do The Simplest Possible Thing That Could Work"
    Another well-intentioned phrase that originally came from Albert Einstein. How could it be bad? Again, I've heard it from one too many hacks to be lazy and not think through their design. It was once used in a debate to store records in XML files instead of a relational database. Even though it was known that the system was to deal with lots of records that had to be randomly accessed. Why? Because they thought relation databases were "hard". The resulting XML files architecture turned out to be way more complex than any OO mapping tool could dream of being. On the surface, the XML seemed simpler, but only when you ignored all the other factors to take into account. The above phrase ended the debate despite cries of the obvious. Confusion abounds because simple is often confused with easy instead of elegant.

  • "If It Ain't Broke, Don't Fix It"
    The maddening catch all to stop refactoring code that everyone fears. This one has been used because apparently certain developers like hearing the buzzing of pagers at 3am. The code in their eyes "worked" even though it was riddled with bugs. The code need to be cleaned, but they just wouldn't let it go. Fear is a terrible thing to use matras to justify.


That's my list for now. I'm sure there's more. I'm really bothered by most mantras because they are used in the most inappropriate places. I'm for debate and rational thought. Anything that short-circuits that annoys me without measure.

Labels: ,


Comments
  • It seems to me the real issue is a general lack of vigorously intellectual communication. I know exactly what you mean by the use of these phrases used to end conversation. Fortunately, sooner or later evolution weeds out the good from the mess.

    What you do not learn by comprehension, you learn by suffering --- or so the saying goes...

    By Blogger Andres, at 6:53 PM   

Friday, April 04, 2008

Monkey Patching

 
Monkey patching seems to be all the debate rage currently in the dynamic language blogosphere. The one that caught my attention was Gilad Bracha's in particular. I don't disagree with him at all. I know it's strange reading that from a Smalltalker. But, I view monkey patching like inheritance. It's a great device to have in your programmer back pocket, but can be dangerous. Use with caution and look at your options. Don't use it without thinking of the implications it can cause. The reason its dangerous is because it's a global change that widens the protocol of the affected object or worse changes the contract for an already existing method.

The main reason monkey patching is so dangerous is the global change it makes and the increased probability of having a collision if another project names a method the same. Or worse, another project overrides the default behavior and replaces it with their own. Both can cause subtle bugs that can be hard to catch and find. It's the global nature of it that can bite. It's convenient, but you should think twice before doing it. It's limits your project's options.

Groovy has a novel approach to monkey patching in that it allows them to be scoped for the duration of a block called categories. This reduces the risk of a global change and the addition is only in affect for the duration of the block. Now, it can cause issues if something gets called outside of the block by accident, which is why I wish it had different ways of scoping (class, package, etc). But, with AspectJ these problems can be reduced. Categories reduce a lot of the risk of monkey patching in that collisions are highly unlikely and the protocol is only widened for that invocation. It also ensures that unknown project dependencies will not creep in. I worry less about monkey patching in this instance because if you get burned, it will be your project not everyone else. I think categories are the way to go (if they added class scoped categories, I would be in heaven).

I don't hate monkey patching. Far from it. It is handy to override method implementations during debugging. I can change pre-existing methods if they have bugs in them even before the next release is out. I don't have to wait on the vendor. These are great pluses. I'm just advocating thought before you monkey patch in your own projects. Much like before you swing the inheritance hammer, you should do the same with monkey patches.

Labels: , , ,


Comments

Tuesday, April 01, 2008

What's that Squeaking in Omaha?

 
If anyone in the Omaha area wants to learn how it's done in Squeak and Smalltalk, feel free to stop by at the Omaha Dynamic Language Users Group tonight. I will be speaking on what makes Smalltalk cool and how to setup your Squeak environment. Bring your curiosity and appetite. See you all there!

Labels:


Comments

Wednesday, March 12, 2008

Uh oh

 
I should have played the Adventure in Emacs before I went wildly blogging. It is not the original Adventure, but another one entirely. Oh well, it's still fun to play.

Labels: ,


Comments



Web hosting by ICDSoft

Metalheads Against Racism
This page is powered by Blogger. Isn't yours?


My Weekly Top 20 Artists