Zen and the Art of (Pair) Programming
Since this book is so general, it can be interpreted in many different ways. I choose to interpret some of the advice it offers in terms of programming.
Programming is an intellectual activity. It takes sufficient intellect, great concentration and lots of patience. And there are some things that can easily sap a programmer's concentration and patience. Robert Pirsig, author of Zen and the Art of Motorcycle Maintenance uses the term gumption as a reference to the gasoline that motivates a person to continue working on what he needs to get done. And he calls the little things that retard the progress of work gumption traps.
Anyone who has done programming before is certainly aware of some gumption traps. When your IDE that has been working fine for the whole day suddenly starts throwing peculiar errors and exceptions, you feel infuriated. Or when you try to chase down a bug that prevents your program from working only to discover that you had somehow used a stale version of the source file and that the bug had already been fixed. It is not the encounter with these incidents that causes you to lose your zen as you are programming; rather it is your reaction to these incidents that cause the state of zen to be broken.
An anecdote would illustrate this better. Pirsig uses the South Indian Monkey Trap parable to illustrate this:
The "South Indian Monkey Trap" was developed by villagers to catch the ever-present and numerous small monkeys in that part of the world. It involves a hollowed-out coconut chained to a stake. The coconut has some rice inside which can be seen through a small hole. The hole is just big enough so that the monkey can put his hand in, but too small for his fist to come out after he has grabbed the rice.
Tempted by the rice, the monkey reaches in and is suddenly trapped. He is not able to see that it is his own fist that traps him, his own desire for the rice. He rigidly holds on to the rice, because he values it. He cannot let go and by doing so retain his freedom. So the trap works and the villagers capture him.
The normal reaction a programmer has for a gumption trap is to lash out and probably try to find the solution fast. However, like the case of the monkey trap, sometimes even when the solution is apparently within your grasp, you tend to forget that there could be a different solution. It takes a great amount of brain power (to use the cliche term) to perform a paradigm shift and try a different route even if the end goal is within your grasp.
As a concrete example, think of how many times you had fixed a bug only to realize that it was but a tiny manifestation of a bigger bug? Or that the bug that you are seeing could be a transient one that exhibits itself every 500 hours and that it would be better to provide some tolerance for it rather than trying to fix it?
Look one way and you see a duck. Look another way and you see a rabbit. Different ways of looking at the same thing requires a paradigm shift. And programmers need to be able to do this numerous times each day.
This idea of taking a step back from what you are doing to actually think about your actions is also highlighted in Edward De Bono's Six Thinking Hats. De Bono proposes six different colored hats: white, red, black, yellow, green and blue. The blue hat captures this notion that you need to be cognizant of the bigger picture and how to react accordingly.
Which brings me to my point: pair programming might help alleviate some of the gumption traps. After all, it is rather unlikely that two programmers with completely different mind sets would fall into the same trap at the same time. Having someone watch over your shoulders does prevent some rather embarrassing episodes of barking up the wrong tree since you now need to convince your partner to do the same.
Even if you do not have the luxury of having someone to pair program with, you can easily just keep a log of all the tiny mistakes or observations that you have encountered during your programming sprint. It's those moments of "a-ha" that seasoned programmers reflect upon to give them the edge over the newbies.
You can find more information about gumption from Chapter 26 of the book. It's a book that has continuation from chapter to chapter but you can easily grasp the advice that Pirsig dispenses by reading each chapter independently. Like I mentioned in the beginning, the book is general enough that you can interpret it differently and mould it to fit various situations.
Crimes Against Logic
After reading the Tipping Point by Malcolm Gladwell, I have been slowly following a trail of books that were part of the "Customers Who Bought This Item Also Bought..." list from Amazon. And I can say that this approach seems to work quite well. All the books that I have picked up so far have been really enjoyable.
This method of choosing new books to read also has it drawbacks -- mainly that I am only reading the same sort of things over and over. However, while browsing for the book at the local Borders (I am a member so I get 20% discount coupons each week to buy some new book) I also see some other books that are interesting and would be buy them once I run out of recommendations to read. One that has caught my fancy is Zen and the Art of Motorcycle Maintenance.
I have almost completed Freakonomics and while it is an interesting read (full of unexpected outcomes) it does not warrant any real blogging on my part. In fact, I find those stories to be more entertaining -- think of coffee table conversations material with someone whom you have just met -- but not really useful in any other sense. I have some reservations toward the anecdotes in the book since there isn't enough proof to convince me of their credibility. Again, like I said, it's a book worth reading just to stump your friends on some aspect of life in the US.
But Crimes of Logic by Jamie Whyte is something different. And did I mention that this book is thin, being around 130 pages, so you don't have to make a great commitment to read it. Probably all you need is about 4 hours before bed time. And since the chapters are short and non-continuous, you could easily read one or two during the times you are free and the book will still feel coherent.
Compared to Blnk, The Tipping Point and Freakonomics, there are no out-of-the-box anecdotes that would stump most people. In fact, Whyte uses only simple examples that everyone has probably heard about through the media. And using this simple examples, he points out logical fallacies about them! And he writes with such clarity that it is impossible to miss the punch-line at the end of each chapter. And when you get it, you would be thinking to yourself: how did I fall for that in the first place?!
I was surprised too that I had fallen for some of the logical fallacies while reading the newspaper or listening to the news. In fact this was really surprising. When I read academic papers, I tend to be more critical in my reading and can detect if certain sections are there just to finagle the reader into believing the paper. On the other hand when I read a non-technical article such as an article in a magazine or the newspaper, sometimes it feels that I just turn off part of my brain that does logical thinking. Yes, this is a very illogical thing to do since fallacies present themselves in all forms of writing and they especially abound in journalism.
So why does my logical side of my brain turn itself off? Probably because I don't really care about the news that much so I cannot be bothered to analyze it. Or more likely that I had somehow succumb to the journalistic writing style that favors gossip and shenanigans such that those elements seem more interesting than the gist itself. Whatever the reason, Whyte has certainly produced a nice little catalogue of common fallacies that people commit and how to detect them.
Now all he needs to do is convince the people who commit such fallacies to read them.
Crimes Against Logic
After reading the Tipping Point by Malcolm Gladwell, I have been slowly following a trail of books that were part of the "Customers Who Bought This Item Also Bought..." list from Amazon. And I can say that this approach seems to work quite well. All the books that I have picked up so far have been really enjoyable.
This method of choosing new books to read also has it drawbacks -- mainly that I am only reading the same sort of things over and over. However, while browsing for the book at the local Borders (I am a member so I get 20% discount coupons each week to buy some new book) I also see some other books that are interesting and would be buy them once I run out of recommendations to read. One that has caught my fancy is Zen and the Art of Motorcycle Maintenance.
I have almost completed Freakonomics and while it is an interesting read (full of unexpected outcomes) it does not warrant any real blogging on my part. In fact, I find those stories to be more entertaining -- think of coffee table conversations material with someone whom you have just met -- but not really useful in any other sense. I have some reservations toward the anecdotes in the book since there isn't enough proof to convince me of their credibility. Again, like I said, it's a book worth reading just to stump your friends on some aspect of life in the US.
But Crimes of Logic by Jamie Whyte is something different. And did I mention that this book is thin, being around 130 pages, so you don't have to make a great commitment to read it. Probably all you need is about 4 hours before bed time. And since the chapters are short and non-continuous, you could easily read one or two during the times you are free and the book will still feel coherent.
Compared to Blnk, The Tipping Point and Freakonomics, there are no out-of-the-box anecdotes that would stump most people. In fact, Whyte uses only simple examples that everyone has probably heard about through the media. And using this simple examples, he points out logical fallacies about them! And he writes with such clarity that it is impossible to miss the punch-line at the end of each chapter. And when you get it, you would be thinking to yourself: how did I fall for that in the first place?!
I was surprised too that I had fallen for some of the logical fallacies while reading the newspaper or listening to the news. In fact this was really surprising. When I read academic papers, I tend to be more critical in my reading and can detect if certain sections are there just to finagle the reader into believing the paper. On the other hand when I read a non-technical article such as an article in a magazine or the newspaper, sometimes it feels that I just turn off part of my brain that does logical thinking. Yes, this is a very illogical thing to do since fallacies present themselves in all forms of writing and they especially abound in journalism.
So why does my logical side of my brain turn itself off? Probably because I don't really care about the news that much so I cannot be bothered to analyze it. Or more likely that I had somehow succumb to the journalistic writing style that favors gossip and shenanigans such that those elements seem more interesting than the gist itself. Whatever the reason, Whyte has certainly produced a nice little catalogue of common fallacies that people commit and how to detect them.
Now all he needs to do is convince the people who commit such fallacies to read them.
Fewest dropped calls? Doesn't matter when everything else is bad
AT&T Mobility - Wikipedia, the free encyclopedia:
"The research company later stated that Cingular did indeed have a 'statistically-significant lower dropped-call rate than the competition across some market/time period groupings,' but that Telephia had 'no knowledge of the specific methodology (markets, time periods or statistical thresholds) that Cingular used for its 'lowest dropped call' claim.'"
If you live in the US and watch television, you would have certainly come across one of the AT&T commercials where they claim that they have the fewest dropped calls. The commercials are definitely funny to watch but having the fewest dropped calls might not even matter all that much....
Especially when your calls do not even get through in the first place! This is not even funny. This is the epitome of unreliability. Important calls cannot even get through to me. This has happened not once, not twice, but more than 10 times in the one month that I switched to AT&T from T-Mobile. Most calls are not that important and people will try a couple of times. But last week I was expecting a call from my insurance agent and he was not able to get through. He was not even able to hit my voice mail! It was as though my phone was turned off. Since it was a Friday and they don't work on weekends, he was only able to get to me on Monday morning.
I do realize that calls cannot get through if I am using the EDGE service on my iPhone but rest assured that I was not using that. The times that people told me that they were not able to get through to me were times when I was not even using the phone! It was either just sitting on the table or in my pocket. And since it is in my apartment, I get great reception and the phone was showing full bars.
And not only that, today I was not even able to make calls. I had to redial twice or thrice to get through. That is more annoying than dropped calls.
Furthermore, ever since getting onto AT&T my mom has also been complaining that every time I call her the voice quality is not as good as last time. Previously I had a Razr and was on T-Mobile. Because the iPhone is tied down to AT&T it is impossible to tell which one is the culprit for the lousy voice quality. I do not exonerate the iPhone from all blame since it is not possible to test it on any other network. So the iPhone could potentially be the culprit here.
Moreover, compared to T-Mobile, AT&T has terrible international calling rates. I have a brother who is studying in Australia and to call him using AT&T I need to pay $3.67 a minute (it's $0.25 a minute if I sign up for AT&T World Connect which costs $3.99 a month). With T-Mobile, I pay a mere $0.34 a minute without signing up for anything. I don't call that often and I don't want to sign up for World Connect.
What about international roaming? In Malaysia, T-Mobile charges $1.99 a minute to make a call. AT&T wants to charge me $2.29. They charge $1.99 if I sign up for AT&T World Traveller! Another stupid plan that I need to sign up for before I get decent rates that T-Mobile is able to give me.
And AT&T is really evil. I am not sure if this is even legal but they signed me up for a trial of their road side assistance service! It'll cost me $3.99 a month if I decide to continue with it. I did not even sign up for it! I just received a letter one day telling me that I had been automatically enrolled in their Asurion road side assistance program. And they have been sending useless offer letters to my mailbox. I never received this kind of stuff from T-Mobile.
So, I would gladly take a few dropped calls from other networks (actually I have never experienced dropped calls with T-Mobile at all) compared to having important calls not even reach me in the first place and all the other crap that I have to take. Rest assured that if T-Mobile begins to support the iPhone in the US I will gladly pay the early termination fee of $200 and just get away from AT&T. Verizon or Sprint are not really options since they are even more ridiculous - their phones do not use SIM cards!
Multilingual Developer
"For many developers, the one-language notion is a sign of lack of professionalism. This is best exemplified by the Pragmatic Programmers' advice to learn a new language every year. The point here is that programming languages do affect the way you think about programming, and learning new languages can do a lot to help you think about solving problems in different ways. (It's important to learn languages that are quite different in order to get the benefit of this. Java and C# are too similar to count.)"
"LISP is worth learning for a different reason - the profound enlightenment experience you will have when you finally get it. That experience will make you a better programmer for the rest of your days, even if you never actually use LISP itself a lot. (You can get some beginning experience with LISP fairly easily by writing and modifying editing modes for the Emacs text editor, or Script-Fu plugins for the GIMP.)
It's best, actually, to learn all five of Python, C/C++, Java, Perl, and LISP. Besides being the most important hacking languages, they represent very different approaches to programming, and each will educate you in valuable ways."
For simplicity, let's assume that there are two types of programmers out there: 1)those who are only extremely proficient in one language (most likely C++, Java or C#) and know everything about the language including the obscure corner cases of its implementation 2) those who know multiple programming languages and enough of each to be able to write applications with it with some form of reference by their side. Now, these are two extreme ends of the gamut and any programmer worth his or her pay will definitely be able to use multiple languages.
Imagine that you are trying to solve a programming problem. You go ask a developer from category 1). He replies that you should try to use language feature #x together with library #z and that you should be careful of some of the dependencies - make sure that you use version 2.1 even if it is in the unstable branch since previous versions cannot work with library #z. Now, you go ask a developer from category 2). He replies that he has seen this problem in one of the languages that he knows and that it is called the "some person's name problem". He explains what the gist of the problem is, some solutions that people have proposed and what he thinks is the best approach to the problem without suggesting a specific language or library (he gives a few that you could try but never ever just one).
Which developer would you prefer? If you go with developer 1), you get the exact language feature and library to use to solve your problem. You might of course run into problems later but for the most part you can get started immediately. If you go with developer 2), you are now able to understand the problem better, possibly google the "some person's name problem" and be able to form you own conclusions on the matter. With 1) you get an immediate solution but with 2) you get a solution that you can potentially apply again and again in different environments.
Of course, the choice of which developer to go with depends on your current situation. The gist of the example above, is that by knowing a few more languages, you are able to distill the actual problem (the "some person's name problem"). From my experience this comes from the fact that most languages are able to solve certain problems better. Furthermore, if you ever read the literature, you will discover that programming languages were invented to address certain inadequacies in other programming languages. Programming languages are turing-complete so you can solve all the solvable problems (problems that do not reduce to the halting problem) with them.
Consider the simple Quicksort algorithm. I remember learning about this in my introductory CS class. The explanation was easy to understand but when we had to actually implement it in Java, the beauty of the algorithm was lost amidst all the noise that the programming language had. Contrast this to the naive - it's naive because it uses list concatenation which is slow - Haskell implementation below:
qsort [] = []
qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++ qsort (filter (>= x) xs)"
While you do need to know a bit of Haskell syntax to comprehend the snippet above, once you do, it becomes almost ethereally clear and concise. The Haskell snippet expresses not only the implementation but also the algorithm itself clearly. The time that you invested in learning a different language like Haskell pays off because it allows you to think about the problem and how to solve it. In the Haskell implementation you solve it using list comprehension whereas in the Java/C version you manipulate data structures with indices or pointer arithmetic. Don't worry too much about the syntax since it is just a way to express the underlying idea.
I claim that the ability to think about the problem itself is an important skill. In the simplest case, it allows you to formulate a query to feed into google. You will be amazed at how many people do not know how to formulate a good query to feed into google.
But isn't it a waste to know so many languages but not be able to use them together? Sure, most languages are able to interface with C because C is still the language to use when you need performance (Fortran programmers will probably disagree since they live in their own world of super high performance computing where the laws of normal CS no longer apply to them). So while the bridge from C to "your favorite language" is pretty good, the bridge from "your favorite language" to "another language that you need" is not that good.
Things are beginning to change of course. I think that the advent of projects like the CLR and JLR will be able to make multilingual programming possible. There might be other implementations out there but admit it, the Java Virtual Machine and the .NET virtual machine are the two most popular ones right now.
As far as I know, right now the way to use different languages would be to create libraries in one language and then export it. You can then use that library in either Java or one of the .NET core languages. Even the JVM supports Javascript and Ruby, I don't think that you can use them together yet.
Multilingual Developer
"For many developers, the one-language notion is a sign of lack of professionalism. This is best exemplified by the Pragmatic Programmers' advice to learn a new language every year. The point here is that programming languages do affect the way you think about programming, and learning new languages can do a lot to help you think about solving problems in different ways. (It's important to learn languages that are quite different in order to get the benefit of this. Java and C# are too similar to count.)"
"LISP is worth learning for a different reason - the profound enlightenment experience you will have when you finally get it. That experience will make you a better programmer for the rest of your days, even if you never actually use LISP itself a lot. (You can get some beginning experience with LISP fairly easily by writing and modifying editing modes for the Emacs text editor, or Script-Fu plugins for the GIMP.)
It's best, actually, to learn all five of Python, C/C++, Java, Perl, and LISP. Besides being the most important hacking languages, they represent very different approaches to programming, and each will educate you in valuable ways."
For simplicity, let's assume that there are two types of programmers out there: 1)those who are only extremely proficient in one language (most likely C++, Java or C#) and know everything about the language including the obscure corner cases of its implementation 2) those who know multiple programming languages and enough of each to be able to write applications with it with some form of reference by their side. Now, these are two extreme ends of the gamut and any programmer worth his or her pay will definitely be able to use multiple languages.
Imagine that you are trying to solve a programming problem. You go ask a developer from category 1). He replies that you should try to use language feature #x together with library #z and that you should be careful of some of the dependencies - make sure that you use version 2.1 even if it is in the unstable branch since previous versions cannot work with library #z. Now, you go ask a developer from category 2). He replies that he has seen this problem in one of the languages that he knows and that it is called the "some person's name problem". He explains what the gist of the problem is, some solutions that people have proposed and what he thinks is the best approach to the problem without suggesting a specific language or library (he gives a few that you could try but never ever just one).
Which developer would you prefer? If you go with developer 1), you get the exact language feature and library to use to solve your problem. You might of course run into problems later but for the most part you can get started immediately. If you go with developer 2), you are now able to understand the problem better, possibly google the "some person's name problem" and be able to form you own conclusions on the matter. With 1) you get an immediate solution but with 2) you get a solution that you can potentially apply again and again in different environments.
Of course, the choice of which developer to go with depends on your current situation. The gist of the example above, is that by knowing a few more languages, you are able to distill the actual problem (the "some person's name problem"). From my experience this comes from the fact that most languages are able to solve certain problems better. Furthermore, if you ever read the literature, you will discover that programming languages were invented to address certain inadequacies in other programming languages. Programming languages are turing-complete so you can solve all the solvable problems (problems that do not reduce to the halting problem) with them.
Consider the simple Quicksort algorithm. I remember learning about this in my introductory CS class. The explanation was easy to understand but when we had to actually implement it in Java, the beauty of the algorithm was lost amidst all the noise that the programming language had. Contrast this to the naive - it's naive because it uses list concatenation which is slow - Haskell implementation below:
qsort [] = []
qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++ qsort (filter (>= x) xs)"
While you do need to know a bit of Haskell syntax to comprehend the snippet above, once you do, it becomes almost ethereally clear and concise. The Haskell snippet expresses not only the implementation but also the algorithm itself clearly. The time that you invested in learning a different language like Haskell pays off because it allows you to think about the problem and how to solve it. In the Haskell implementation you solve it using list comprehension whereas in the Java/C version you manipulate data structures with indices or pointer arithmetic. Don't worry too much about the syntax since it is just a way to express the underlying idea.
I claim that the ability to think about the problem itself is an important skill. In the simplest case, it allows you to formulate a query to feed into google. You will be amazed at how many people do not know how to formulate a good query to feed into google.
But isn't it a waste to know so many languages but not be able to use them together? Sure, most languages are able to interface with C because C is still the language to use when you need performance (Fortran programmers will probably disagree since they live in their own world of super high performance computing where the laws of normal CS no longer apply to them). So while the bridge from C to "your favorite language" is pretty good, the bridge from "your favorite language" to "another language that you need" is not that good.
Things are beginning to change of course. I think that the advent of projects like the CLR and JLR will be able to make multilingual programming possible. There might be other implementations out there but admit it, the Java Virtual Machine and the .NET virtual machine are the two most popular ones right now.
As far as I know, right now the way to use different languages would be to create libraries in one language and then export it. You can then use that library in either Java or one of the .NET core languages. Even the JVM supports Javascript and Ruby, I don't think that you can use them together yet.
Meta-Object Protocol implementation for programming languages 1
The past week I had the opportunity to play around with Groovy. Groovy is an "agile dynamic language for the Java Platform". In short, you can think of Groovy as adding dynamic features to the Java language with some syntactic sugar to the Java syntax. Like JRuby and Jython, Groovy runs on the JVM and plays well with Java code.
Groovy offers functionality similar to that of Ruby, Python and other dynamic languages. Of course, Groovy has its own way of doing things but some of the most interesting things that I have seen are:
- Integrated support for XML processing directly via GPath (akin to XPath)
- Support for multimethods. The type of an object is determined at run-time. This leads to the interesting behavior that even if you write
Object foo = "Hello", foo actually has the typeStringinstead ofObject. - Option to declare the type for variables. Though not required, you have the option of declaring the static type of an object. The only other system that I have seen that offers this option is Strongtalk.
While Groovy is certainly an interesting and useful language (personally, any language that reduces the verbosity of Java is useful), what is more interesting is the way in which the dynamic features are done. Groovy relies on an internal implementation of the Metaobject Protocol. As far as I know, the term Metaobject Protocol was first made popular in the book The Art of the Metaobject Protocol. You can read more about this concept from any of the previous links but in a nutshell, designing a programming language so that it conforms to some Metaobject Protocol is a good thing. It allows the programmer (and not only the designer) to change the semantics of the language so that it can not only modify the current features of the language but also incorporate new features easily.
This might seem like an absurd thing to do if you are used to programming in more traditional languages like C which does not even offer the ability for reflection. However, the ability for actually modifying the programming language itself is becoming more useful. Modifying does not only mean adding some form of syntactic sugar on top of the existing language but also the ability to add new features to the programming language itself. For instance, the foreach control structure could be viewed as some form of syntactic sugar. foreach could be easily implemented as a macro that is expanded before execution into the normal for loop or while loop. On the other hand, adding object-oriented features on top of a "non-object-oriented" language would be viewed as adding a new feature (and not just syntactic sugar) to the language itself. This was what was done with CLOS in Lisp.
One could always argue that there is no need for such a feature to be an inherent part of the programming language. A valid argument against implementing something like the Metaobject Protocol is the issue of speed and performance. Having the infrastructure to modify the behavior of the programming language is going to have some form of overhead on the execution of the program. Furthermore, the ability to change the programming language would lead to problems with a proliferation of different versions of the same programming language with subtle differences. Moreover, one might also argue that if a feature is that important, why not just add it in the next version of the programming language. That is exactly the case with Java and C#; newer editions keep adding features to the language.
While those arguments are certainly valid, the ability to be able to modify the semantics of the programming language should not be discounted. As computers get faster, the speed overhead from having the Metaobject Protocol built-in to the language is negligible save for the most performance intensive machines. And how many people actually want to wait for the designers of the programming language to add some new feature? The desired feature might not be important for everyone and might not be added to the core of the language. Should that be a reason why it is not there if your application actually requires it? For instance, as the ability to express domain knowledge clearly in programming languages become more important, more and more forms of domain-specific languages are surfacing. These domain-specific languages provide a concise way to express essential concepts of the domain which might otherwise be hidden through the syntax and semantics of a traditional programming language. No sane programming language designer is going to design multiple domain languages and give them multiple names such as C-Telecommmunication, C-Accounting, C-Transactions1.
While the idea of having a full-fledged Metaobject Protocol might be too idealistic for some, some of the newer ideas in the software engineering world are taking advantage of a more moderate form of it. The designers of programming languages can certainly vary the degree of dynamic behavior. For instance, Ruby does not have a fully modifiable underlying semantics but it does provide enough for programmers to accomplish most of what needs to be done.
In conclusion, I feel that more and more languages would incorporate some form of the Metaobject protocol. Dynamic languages are becoming increasingly prominent in the software engineering world today and the logical next step would be to expand on their dynamic behavior to improve on the extensibility2. It should be possible for both programming language designers and programmers to modify and/or features to the programming language in a hygienic way without resorting to ugly hacks.
For an example use of the Metaobject Protocol in Groovy, take a look at Pratically Groovy: Of MOPs and mini-languages.1 An alternative would be to design your own language from scratch if it is simple enough. Tools like Antlr and even Maude have made this process less painful. Even then, designing a language from scratch -- albeit being fun -- requires a lot more devotion than modifying an existing language.
2 Some features might also be extremely hard if not impossible to add to an exiting system whether or not it has an Metaobject Protocol. For instance, (I think) having the ability to do multi-stage programming might require extensive changes to the language itself and is not accomplishable with just some hacking on the language itself.
Meta-Object Protocol implementation for programming languages 1
The past week I had the opportunity to play around with Groovy. Groovy is an "agile dynamic language for the Java Platform". In short, you can think of Groovy as adding dynamic features to the Java language with some syntactic sugar to the Java syntax. Like JRuby and Jython, Groovy runs on the JVM and plays well with Java code.
Groovy offers functionality similar to that of Ruby, Python and other dynamic languages. Of course, Groovy has its own way of doing things but some of the most interesting things that I have seen are:
- Integrated support for XML processing directly via GPath (akin to XPath)
- Support for multimethods. The type of an object is determined at run-time. This leads to the interesting behavior that even if you write
Object foo = "Hello", foo actually has the typeStringinstead ofObject. - Option to declare the type for variables. Though not required, you have the option of declaring the static type of an object. The only other system that I have seen that offers this option is Strongtalk.
While Groovy is certainly an interesting and useful language (personally, any language that reduces the verbosity of Java is useful), what is more interesting is the way in which the dynamic features are done. Groovy relies on an internal implementation of the Metaobject Protocol. As far as I know, the term Metaobject Protocol was first made popular in the book The Art of the Metaobject Protocol. You can read more about this concept from any of the previous links but in a nutshell, designing a programming language so that it conforms to some Metaobject Protocol is a good thing. It allows the programmer (and not only the designer) to change the semantics of the language so that it can not only modify the current features of the language but also incorporate new features easily.
This might seem like an absurd thing to do if you are used to programming in more traditional languages like C which does not even offer the ability for reflection. However, the ability for actually modifying the programming language itself is becoming more useful. Modifying does not only mean adding some form of syntactic sugar on top of the existing language but also the ability to add new features to the programming language itself. For instance, the foreach control structure could be viewed as some form of syntactic sugar. foreach could be easily implemented as a macro that is expanded before execution into the normal for loop or while loop. On the other hand, adding object-oriented features on top of a "non-object-oriented" language would be viewed as adding a new feature (and not just syntactic sugar) to the language itself. This was what was done with CLOS in Lisp.
One could always argue that there is no need for such a feature to be an inherent part of the programming language. A valid argument against implementing something like the Metaobject Protocol is the issue of speed and performance. Having the infrastructure to modify the behavior of the programming language is going to have some form of overhead on the execution of the program. Furthermore, the ability to change the programming language would lead to problems with a proliferation of different versions of the same programming language with subtle differences. Moreover, one might also argue that if a feature is that important, why not just add it in the next version of the programming language. That is exactly the case with Java and C#; newer editions keep adding features to the language.
While those arguments are certainly valid, the ability to be able to modify the semantics of the programming language should not be discounted. As computers get faster, the speed overhead from having the Metaobject Protocol built-in to the language is negligible save for the most performance intensive machines. And how many people actually want to wait for the designers of the programming language to add some new feature? The desired feature might not be important for everyone and might not be added to the core of the language. Should that be a reason why it is not there if your application actually requires it? For instance, as the ability to express domain knowledge clearly in programming languages become more important, more and more forms of domain-specific languages are surfacing. These domain-specific languages provide a concise way to express essential concepts of the domain which might otherwise be hidden through the syntax and semantics of a traditional programming language. No sane programming language designer is going to design multiple domain languages and give them multiple names such as C-Telecommmunication, C-Accounting, C-Transactions1.
While the idea of having a full-fledged Metaobject Protocol might be too idealistic for some, some of the newer ideas in the software engineering world are taking advantage of a more moderate form of it. The designers of programming languages can certainly vary the degree of dynamic behavior. For instance, Ruby does not have a fully modifiable underlying semantics but it does provide enough for programmers to accomplish most of what needs to be done.
In conclusion, I feel that more and more languages would incorporate some form of the Metaobject protocol. Dynamic languages are becoming increasingly prominent in the software engineering world today and the logical next step would be to expand on their dynamic behavior to improve on the extensibility2. It should be possible for both programming language designers and programmers to modify and/or features to the programming language in a hygienic way without resorting to ugly hacks.
For an example use of the Metaobject Protocol in Groovy, take a look at Pratically Groovy: Of MOPs and mini-languages.1 An alternative would be to design your own language from scratch if it is simple enough. Tools like Antlr and even Maude have made this process less painful. Even then, designing a language from scratch -- albeit being fun -- requires a lot more devotion than modifying an existing language.
2 Some features might also be extremely hard if not impossible to add to an exiting system whether or not it has an Metaobject Protocol. For instance, (I think) having the ability to do multi-stage programming might require extensive changes to the language itself and is not accomplishable with just some hacking on the language itself.
iPhone
Apple's New Calling: The iPhone -- Tuesday, Jan. 09, 2007 -- Page 2 -- TIME:
"Because there's no intermediary input device like a mouse or a keyboard there's a powerful illusion that you're physically handling data with your fingers. You can pinch an image with two fingers and make it smaller."
(Via Projectionist: A tumbleblog.)
I was actually expecting some announcement about Mac OS X 10.5 Leopard during yesterday's Macworld Conference. Unfortunately, the spotlight seems to be taken by the iPhone and Apple TV. I do not see myself getting the iPhone just yet. It's too expensive, has a touch screen that is probably going to have smudges all over and, I believe, requires a service plan (most probably the higher end ones) with Cingular.
However, what is more interesting about the iPhone is the multi-touch display. Most tablet PCs out there today only support interaction via the stylus. This is good. You do not want your fingers to interfere with the process of writing. However, for some tasks, using the stylus is no better than using a mouse in the first place. For instance, for drag-and-drop, the gesture for the stylus resembles using the mouse.
With multi-touch display, however, you get more interaction. Like the TIMES article says, you should be able to "pinch" with two fingers and have the image shrink. No more having to point at the corner of the picture and drag. This opens a new world of interaction. HCI enthusiasts should begin analyzing and researching new idioms and metaphors for such interactions.
If you have seen the BumpTop videos, you will notice that it is more suited for use with a multi-touch display rather than a conventional tablet.
So, for me, the iPhone itself is not that revolutionary: integrated music player, cell-phone and smart-phone. It's the multi-touch screen that will be interesting in the long run. And it will be nice to see what else can be done with the multi-touch screen for normal computers and laptops.
Performance... performance... performance
ArticleS.UncleBob.PerformanceTuning:
"All this just leads back to the title. Performance tuning is perverse. What you think is going on is seldom what really is going on. Who could have guessed that limiting the outer iteration to the square root of the maximum would yeild just a 2X increase in performance? Who could have guessed that the algorithm itself was linear?!"
Optimizing is a dangerous game. It's always tempting to try to make small tricks here and there which you think are going to help your program run faster. However, unless you actually check out the speed increase, you will realize that those small tricks do not matter significantly.
I used to do little tricks such as that in C/C++ or Java as well. Maybe it's the nature of the language that allows such "optimizations". I don't do such optimizations when using Smalltalk or Ruby. At this stage, some of you might decide to jump in and say: 'cos that languages are so darn slow to begin with. Ruby might be slow (for now) but there are variants of Smalltalk that run almost on par with C.
For instance, in a function, I might think that a calling another function (say pow()) a couple of times is going to really slow. So I cache this value whenever possible by assigning it to some variable. Sure, everyone knows that calling pow() is going to slow so caching that value especially if you are going to use is going to make great difference right? Not true. Caching variables for something like this is what a compiler ought to be able to do by itself. Caching variables can be something short-termed because when you actually have to modify your code, you might forget to change all the places where you use that cached variable. Maybe you cached the value for pow(number, 3) and used it in four different places, then if you ever need to use pow(number, 2) you have to allocate a new variable and all that again. The changes that need to be made to your code to accommodate that change might not be trivial.
So unless you have a profiler at hand and real world usage data, your suspicions on what part to optimize is going to be wrong. For an algorithm that is always going to be linear, O(n) at most what you can do is speed it up by a constant amount. Unless you change the algorithm, there is no way you can suddenly get to O(lg n) performance.
Five Worlds - Joel on Software:
"Embedded Software has the unique property that it goes in a piece of hardware and in almost every case can never be updated. This is a whole different world, here. The quality requirements are much higher, because there are no second chances. You may be dealing with a processor that runs dramatically more slowly than the typical desktop processor, so you may spend a lot of time optimizing. Fast code is more important than elegant code."
But then again, such tricks are important when you do not have a great compiler. For instance, on embedded systems. It's hard for people to write great C compilers for every microchip there is out there. You can be pretty sure that the C compiler you are using for the ATMegatel chip is not going to be as good as the one you have your desktop. In such cases, little tricks on the developer's part does work. That was pretty much the reason why people wrote in assembly last time when the first C compiler came out: it just wasn't good enough yet for demanding tasks like games that push the limits of the computer.
The Emperor’s New Clothes Syndrome:
"The problem is that although we know exactly what doesn't work right and how it should be fixed, most of us will never say anything. We don't say anything because there's a very good chance the minute we do we will be marked as uncooperative, pessimistic, or simply detached from the business reality."
So the next time your team member suggests so clever little optimizing trick, please think it through before actually implementing it. Most clever little tricks that used to work great in the past might not be so necessary anymore. Things like loop unravelling should definitely be left to the compiler so that you do not generate weird amounts of code that no one else can clean up after you. Seriously, think about it. The same goes for over-engineering, I guess but that would require more articles before I can come to a valid conclusion.
I read the three articles I quoted at different times during the week but I clobbered them together just now and they actually fit rather nicely. I hope.