<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8998567056484984795</id><updated>2011-11-28T00:49:32.837+01:00</updated><category term='Internet explorer'/><category term='lotus connections'/><category term='dojo'/><category term='IE8'/><title type='text'>The Semicolon Report ;</title><subtitle type='html'>In some computer languages a statement ends with a semicolon. These are my thoughts on these languages, in particularly Javascript, which is my favourite language with semicolon syntax. Web-development is another topic that might turn up.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://semicolonreport.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8998567056484984795/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://semicolonreport.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Henrik Hjelte</name><uri>http://www.blogger.com/profile/14572554303466957938</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>9</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8998567056484984795.post-8225478787785215054</id><published>2010-04-14T09:31:00.004+02:00</published><updated>2010-04-14T09:44:57.546+02:00</updated><title type='text'>PhoneGap is ok with section 3.3.1</title><content type='html'>PhoneGap is &lt;a href="http://blogs.nitobi.com/jesse/2009/11/20/phonegapp-store-approval/"&gt;reported&lt;/a&gt; to be compliant with section 3.3.1. So now you can use Javascript to do iPhone and iPad apps. I tried out my iPhone app on the iPad yesterday and it worked fine.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8998567056484984795-8225478787785215054?l=semicolonreport.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semicolonreport.blogspot.com/feeds/8225478787785215054/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://semicolonreport.blogspot.com/2010/04/phonegap-is-ok-with-section-331.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8998567056484984795/posts/default/8225478787785215054'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8998567056484984795/posts/default/8225478787785215054'/><link rel='alternate' type='text/html' href='http://semicolonreport.blogspot.com/2010/04/phonegap-is-ok-with-section-331.html' title='PhoneGap is ok with section 3.3.1'/><author><name>Henrik Hjelte</name><uri>http://www.blogger.com/profile/14572554303466957938</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8998567056484984795.post-597009362436786476</id><published>2010-04-12T20:28:00.004+02:00</published><updated>2010-04-12T21:20:14.872+02:00</updated><title type='text'>Why the Apple 3.3.1 policy is bad for consumers, economic arguments</title><content type='html'>Sorry, I make an exception and talk some politics in this blog. Computer programmers over the world are upset about the new Apple policy 3.3.1, for a background see this &lt;a href="http://www.wired.com/gadgetlab/2010/04/iphone-developer-policy/"&gt;Wired article&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The counterarguments are usually from a technical perspective, see for example this post from &lt;a href="http://37signals.com/svn/posts/2273-five-rational-arguments-against-apples-331-policy"&gt;37 signals&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I want to give some &lt;span style="font-weight:bold;"&gt;economic&lt;/span&gt; arguments, hopefully that is a language that politicians understand.&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;br /&gt;Higher costs for consumers argument A.&lt;/span&gt;&lt;br /&gt;Claim A1. Apples restriction on allowed programming languages decreases productivity.&lt;br /&gt;Claim A2. This increases the cost of software development.&lt;br /&gt;Claim A3. This will increase the cost of software products.&lt;br /&gt;Claim A4. Consumers will have to pay more for software.&lt;br /&gt;&lt;br /&gt;I think claim 2-4 are obvious, given claim 1. &lt;br /&gt;For some scientific support for the claim 1 that not all programming languages have the same productivity, see the the 2000 IEEE paper &lt;a href="http://www.computer.org/portal/web/csdl/doi/10.1109/2.876288"&gt;An Empirical Comparison of Seven Programming Languages&lt;/a&gt;(draft &lt;a href="http://page.mi.fu-berlin.de/~prechelt/Biblio/jccpprt_computer2000.pdf"&gt;PDF&lt;/a&gt;)&lt;br /&gt;&lt;blockquote&gt;The following statements summarize the findings of the comparative analysis of 80 implementations of the phonecode program in 7 different languages:&lt;br /&gt;– Designing and writing the program in Perl, Python, Rexx, or Tcl takes no more than half as much time as writing it in C, C++, or Java and the resulting program is only half as long.&lt;br /&gt;– No unambiguous differences in program reliability be- tween the language groups were observed&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;There are more productive languages than C and C++. I believe Objective-C is similar to these languages, but even if Apple Objective-C is more productive, there can not really argue that there might not ever be another language, language X, that is more productive.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Higher costs for consumers, argument B.&lt;/span&gt;&lt;br /&gt;B1. Of the worlds programmers, there are some X percent that know the Apple approved languages, some Z percent that know other languages.&lt;br /&gt;B2. If the Z percent are not allowed to develop software for the iPhone, the supply of programmers are less than Z + X.&lt;br /&gt;B3. Lower supply gives higher prices.&lt;br /&gt;B4. Higher prices for software development, well see claim A2-A4.&lt;br /&gt;&lt;br /&gt;Now it would be interesting to see what evidence Jobs have for &lt;a href="http://www.taoeffect.com/blog/2010/04/steve-jobs-response-on-section-3-3-1/"&gt;his claim:&lt;/a&gt;&lt;br /&gt;&lt;blockquote&gt;We’ve been there before, and intermediate layers between the platform and the developer ultimately produces sub-standard apps and hinders the progress of the platform.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;I will not be surprised to see the European Union taking actions against Apple soon, not only because of section 3.3.1, but given the iPhone platform and the ways companies are not allowed to compete with the built-in software. &lt;a href="http://en.wikipedia.org/wiki/European_Union_Microsoft_competition_case"&gt;Remember EU and Microsoft&lt;/a&gt;. Apple: please start to behave like gentlemen.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8998567056484984795-597009362436786476?l=semicolonreport.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semicolonreport.blogspot.com/feeds/597009362436786476/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://semicolonreport.blogspot.com/2010/04/why-apple-331-policy-is-bad-for.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8998567056484984795/posts/default/597009362436786476'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8998567056484984795/posts/default/597009362436786476'/><link rel='alternate' type='text/html' href='http://semicolonreport.blogspot.com/2010/04/why-apple-331-policy-is-bad-for.html' title='Why the Apple 3.3.1 policy is bad for consumers, economic arguments'/><author><name>Henrik Hjelte</name><uri>http://www.blogger.com/profile/14572554303466957938</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8998567056484984795.post-3278213805887027406</id><published>2010-02-27T15:25:00.002+01:00</published><updated>2010-04-09T10:29:17.377+02:00</updated><title type='text'>Using Javascript to do iPhone apps</title><content type='html'>&lt;p&gt;Mobile Safari has got native-speed animations, a built in SQL-Lite database for client-side storage, local caching, access to touch events and more. And the great javascript programming language. You can do apps that feel and look like traditional apps, but with direct install from a website rather than through app-store. I recently did a proof of concept for a client that was very impressive. It felt just like a &amp;quot;real&amp;quot; app, with sweeping animations, touch events and more.&lt;/p&gt;&lt;p&gt;Here are some decision points to choose a strategy:&lt;/p&gt;&lt;p&gt;Code an app on the browser:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;If you want to do something cheaper and faster.&lt;/li&gt;&lt;li&gt;If you don't want to publish it on app-store.&lt;/li&gt;&lt;li&gt;If you wan't to be able to upgrade it instantaneously.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Code an objective-C application:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;If you like to do just as everyone else&lt;/li&gt;&lt;li&gt;If you want to do something in need of really high speed like a 3d game or a face recognition algorithm.&lt;/li&gt;&lt;li&gt;If you appreciate to have a for-profit organziation like Apple approving or disapproving what you have done.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Here are some links for developers that want to try the browser way:&lt;/p&gt;&lt;p&gt;&lt;a href="http://developer.apple.com/safari/"&gt;Apple Safari Documentation&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://developer.apple.com/safari/library/documentation/InternetWeb/Conceptual/SafariVisualEffectsProgGuide/Introduction/Introduction.html"&gt;Safari Visual Effects Guide&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://developer.apple.com/safari/library/documentation/UserExperience/Reference/TouchEventClassReference/TouchEvent/TouchEvent.html"&gt;The Touch-Event&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://building-iphone-apps.labs.oreilly.com/"&gt;A new O'Reilly book&lt;/a&gt; about this way to do apps, a very good introduction. It a bit thin on animations and events, so also read the Apple docs.&lt;/p&gt;&lt;p&gt;If you need to get on app-store or access even more native features, there is a project Phonegap that wraps some objective-C around your files. But first take a look at what you can do without it.&lt;/p&gt;&lt;p&gt;Some observations:&lt;/p&gt;&lt;p&gt;Mobile Safari is impressive, but WTF: You can't have scrolling inside a div. I wonder how they came up with the idea to remove that standard feature.&lt;/p&gt;&lt;p&gt;To get a logging facility, on your iPhone go to Settings &amp;gt; Safari &amp;gt; Developer &amp;gt; Debug Console. If you have a good development environment like emacs + flymake + jslint you don't feel the need of a real debugger that much anyway, print statements (logging) is an underrated technique.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8998567056484984795-3278213805887027406?l=semicolonreport.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semicolonreport.blogspot.com/feeds/3278213805887027406/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://semicolonreport.blogspot.com/2010/02/using-javascript-to-do-iphone-apps.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8998567056484984795/posts/default/3278213805887027406'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8998567056484984795/posts/default/3278213805887027406'/><link rel='alternate' type='text/html' href='http://semicolonreport.blogspot.com/2010/02/using-javascript-to-do-iphone-apps.html' title='Using Javascript to do iPhone apps'/><author><name>Henrik Hjelte</name><uri>http://www.blogger.com/profile/14572554303466957938</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8998567056484984795.post-2530981827133827673</id><published>2009-10-28T10:16:00.003+01:00</published><updated>2009-10-28T10:23:14.455+01:00</updated><title type='text'>Functional object-oriented programming in Javascript</title><content type='html'>I have written a tutorial on the best and easiest way to do object-oriented programming in javascript. It is the method described as "functional" by Douglas Crockford in "Javascript the good parts", the chapter on inheritance. All deep thinking was done by Crockford, the only smart thing I have done is to understand to appreciate the ideas. And I have made a new example, and possibly some new arguments for the method. What is funny is that I like this method but not really what Crockford points out as the killer argument for it (real privacy).&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.henrikhjelte.com/files/func-oo-js/func-oo.html"&gt;Here it is&lt;/a&gt;, text, code and demo.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8998567056484984795-2530981827133827673?l=semicolonreport.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semicolonreport.blogspot.com/feeds/2530981827133827673/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://semicolonreport.blogspot.com/2009/10/functional-object-oriented-programming.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8998567056484984795/posts/default/2530981827133827673'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8998567056484984795/posts/default/2530981827133827673'/><link rel='alternate' type='text/html' href='http://semicolonreport.blogspot.com/2009/10/functional-object-oriented-programming.html' title='Functional object-oriented programming in Javascript'/><author><name>Henrik Hjelte</name><uri>http://www.blogger.com/profile/14572554303466957938</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8998567056484984795.post-105786656025623543</id><published>2009-10-22T01:38:00.004+02:00</published><updated>2009-10-22T02:00:59.853+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IE8'/><category scheme='http://www.blogger.com/atom/ns#' term='Internet explorer'/><category scheme='http://www.blogger.com/atom/ns#' term='lotus connections'/><category scheme='http://www.blogger.com/atom/ns#' term='dojo'/><title type='text'>Why feature-sniffing? Sample from an IE8-bug in Dojo</title><content type='html'>&lt;p&gt;I am going to give a real-world example of when browser-sniffing fails, and that browser-sniffing is not the same as user-agent sniffing.&lt;/p&gt;&lt;p&gt;Some weeks ago I made a note to myself. Never use native DOM-methods if you have a library at hand. I had discovered an Internet Explorer bug, and noticed that if I had used the dojo.attr code instead of setAttribute it would never have been a problem. But today I discovered that the exact same code that I praised some weeks ago now totally broke on Internet Explorer 8. And it was Dojos fault not Microsofts. I repeat it was &lt;em&gt;not&lt;/em&gt; a Microsoft bug. Microsoft actually had &lt;em&gt;fixed&lt;/em&gt; a bug.&lt;/p&gt;&lt;p&gt;The reason was browser-sniffing instead of feature-sniffing. The Dojo code checks whether the browser is Internet Explorer, and assumes that it behaves in a certain way if it is. But just because it is is a bug in todays Internet Explorer, it does not need to be in Internet Explorer 9 or 10. The brand name will probably stay. There are two solutions to the problem, one not so good and one good.&lt;/p&gt;&lt;h2 id="browser-detection"&gt;Browser-detection&lt;/h2&gt;&lt;p&gt;The not very good one is to check on a certain version of the browser that you know about. If you know the bug is in IE6 or IE7 or IE8 you can test for that particular version. But wait, what if they fix the bug? This could be the case for IE8. It is not unthinkable. Then your code would break.&lt;/p&gt;&lt;h2 id="user-agents"&gt;User-agents&lt;/h2&gt;&lt;p&gt;An additional question, but less important, is how you detect the browser version. If it is based on an user-agent string you might have additional problems, this string could be set by another browser in some sort of compatiblity-mode, or even changed by the user. When you &lt;a href="http://www.sitepoint.com/blogs/2009/05/31/why-browser-sniffing-stinks/"&gt;read about&lt;/a&gt; browser sniffing it usually sounds like it is detection based on user-agents that is the main problem. And people respond that only 0.025 percent fakes user-agents anyway so it is no problem. In a way I agree, the main problem is not using user-agents. It is assuming a bug exists without testing for the exact bug, but assuming it exists because we are on a certain browser. Testing for the presence of certain objects (like document.all) and then assuming a certain behaviour can be just as unreliable. What if the bug is fixed in the next service-pack but document.all remains?&lt;/p&gt;&lt;h2 id="feature-detection"&gt;Feature-detection&lt;/h2&gt;&lt;p&gt;The best way to do it I can think of is to test if the bug exists, not if we are on a certain browser. You can call it feature-detection, or bug-detection. Sure, it might take some extra milliseconds and some coding effort. But I think it is worth it, especially in a general purpose library. And I was just visually inspecting jQuerys support.js, it seems it can be done in a fast way.&lt;/p&gt;&lt;h2 id="unobtrusive-websites"&gt;Unobtrusive websites&lt;/h2&gt;&lt;p&gt;Of course you can use the same way to do accessible website with graceful degradation. Test for features, not browser versions.&lt;/p&gt;&lt;h2 id="details-on-the-bug"&gt;Details on the bug&lt;/h2&gt;&lt;p&gt;This might not be very interesting, but if you really want to know. Dojo 1.2.3 has a function dojo.attr that fixes some issues with the native setAttribute method. One thing is that when setting the (css) class the attibute is named className for Internet Explorer 6 and 7. But that was fixed in Internet Explorer 8. However, line 1085 in html.js checks for isIE rather than ieLT8 (which would have worked). Here is my &lt;a href="http://bugs.dojotoolkit.org/ticket/10179"&gt;bug-report&lt;/a&gt;.&lt;/p&gt;&lt;h2 id="sample-bug-sniffing"&gt;Sample bug sniffing&lt;/h2&gt;&lt;p&gt;This is the feature sniffing I have used for this bug.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;var featureSniffClassNameAttributeIsClass = function () {&lt;br /&gt;    var d = dojo.doc.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;    try {&lt;br /&gt;        d.setAttribute(&amp;quot;className&amp;quot;, &amp;quot;c&amp;quot;);&lt;br /&gt;        var h = d.outerHTML;&lt;br /&gt;        // if setting className on a node alters the class, we are on IE6 or 7&lt;br /&gt;        var convertClassToClassName = ! /classname/.exec(h.toLowerCase());&lt;br /&gt;        return convertClassToClassName;&lt;br /&gt;    } catch (e) {&lt;br /&gt;        //probably we are on a non IE browser because an error occurred&lt;br /&gt;        return false;&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="why-dont-you-upgrade-to-the-latest-dojo"&gt;Why don't you upgrade to the latest dojo?&lt;/h2&gt;&lt;p&gt;Now that is a good question. I don't know if this bug is fixed yet, maybe it is. But sometimes you don't have an option. We are doing a chat-widget for Lotus Connections. Lotus Connections is a commercial social software for intranets made by IBM. And it does not have a chat. Almost unbelievable. If you are running &lt;a href="http://www-01.ibm.com/software/lotus/products/connections/"&gt;Lotus Connections&lt;/a&gt; and want a chat, of course you do, &lt;a href="mailto:henrik.hjelte@stix.to"&gt;contact me&lt;/a&gt; for more information. Or if you are a systems-integrator and want one to sell. Anyway, widgets for Lotus Connections do not sit in isolated iframes, so your Javascript runs on the actual page. And IBM has decided on the Dojo version, not me. So I don't think I can persuade them to patch it.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8998567056484984795-105786656025623543?l=semicolonreport.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semicolonreport.blogspot.com/feeds/105786656025623543/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://semicolonreport.blogspot.com/2009/10/why-feature-sniffing-sample-from-ie8.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8998567056484984795/posts/default/105786656025623543'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8998567056484984795/posts/default/105786656025623543'/><link rel='alternate' type='text/html' href='http://semicolonreport.blogspot.com/2009/10/why-feature-sniffing-sample-from-ie8.html' title='Why feature-sniffing? Sample from an IE8-bug in Dojo'/><author><name>Henrik Hjelte</name><uri>http://www.blogger.com/profile/14572554303466957938</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8998567056484984795.post-8223587056273424808</id><published>2009-09-17T14:04:00.005+02:00</published><updated>2009-09-17T14:23:18.756+02:00</updated><title type='text'>Plug for Improved jQuery Flip effect plugin</title><content type='html'>I have improved the &lt;a href="http://lab.smashup.it/flip/"&gt;jQuery Flip Plugin&lt;/a&gt; quite a lot. I contributed the updates in july, but there is no release yet. So in case someone wants to use the jquery flip effect plugin, let me plug &lt;a href="http://www.henrikhjelte.com/files/henrik-flip/fliptest.html"&gt;my version&lt;/a&gt; ( zip &lt;a href="http://www.henrikhjelte.com/files/flip.zip"&gt;here&lt;/a&gt;)until a new official release is out.&lt;br /&gt;&lt;br /&gt;Below are my notes of changes vs 0.5, if you are curious on details.&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Added a testpage fliptest.html to show the bug I fixed. It can also be good to have included in the plugin for future hackers.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Version 0.5 failed fliptest nr 3 with tb and bt on Firefox 3,3.5, Opera 9.64 maybe more. You can see that there is a white border over the text, especially if you run it in the slow mode. This does not look good over an element with a background image.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Solution: Don't pick up transparent from the parent node. Instead add a background-color transparent to the style of the cloned node (it will override background-colors applied from a stylesheet, for example with a class).&lt;/p&gt;&lt;p&gt;This didn't work for IE6. But instead of picking up colors from the parent node, use a special trick for IE6. In order to do that, I added a function isIE6orOlder. Removed getTransparent.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Problem with named colors (like &amp;quot;yellow&amp;quot;), on IE7. I made an acceptHexColors function that forces the use of hex colors.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;for &amp;quot;tb&amp;quot; borderLeftColor and borderRight color need not be set to transparent in first or second animation, because it is already set on the start. Also it caused a white background on Firefox, maybe since transparent is a special kind of color.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;It was difficult to read a very long line, so it split dirOptions into one line per property.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;That made it into 147 lines of setting up the dirOptions. I wanted to simplify it.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Also note, that we set up the four different directions but only one of them is used per call. So there is some unnecessary code being run.&lt;/p&gt;&lt;p&gt;First I split it into four functions, each one returning a dirOption. Then I looked at was common options, in the end it became a few functions in 100 lines, I think you will agree it is more readable and less prone of typing errors.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;jslint error missing radix parameter in int_prop.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;use of global jQuery variable inside the big wraping. This will make flip not work if using jQuery.noConflict(); And it is totally unnecessary. jQuery is passed in as the $ parameters by the call in the last line of the file. So, in two place around jQuery.extent jQuery.fx.step and jQuery.fn.flip I change jQuery to $.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The cloneId is unnecessary. It is used to get the clone we made, but it is returnde directly when we create it. Instead I made a $clone variable.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The inner function queue(_this,_self) is unnecessary, also the variables _this and _self become just rebindings of my new $clone and $this. So I removed them.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;I made the onBefore,onAnimation and onEnd send the $clone and $this as parameters that can be used if you want to. Why? Here is a real world sample.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$me.flip({direction:'tb',&lt;br /&gt;          dontChangeColor: true,&lt;br /&gt;          onBefore:function ($clone) {&lt;br /&gt;              $clone.css({'background-image': &amp;quot;none&amp;quot;});&lt;br /&gt;          },&lt;br /&gt;          onEnd:toggClass});&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;I added the dontChangeColor settings option. For example, I have an element with no background color. Instead I have a background image, first a bit yellow and then a little grey. I want to use the flip effect, but not change background color. Instead I want to change background image when the flip has finished.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;'0px' is the same as 0. Zero is always zero whatever measurement unit.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Added 0.6 and some comments to the ChangeLog.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;I can't work with tabs, if you want you can convert it back, 4 chars indentation level.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The compressed (YUICompress) size has decreased from 4903 to 3903 bytes.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8998567056484984795-8223587056273424808?l=semicolonreport.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semicolonreport.blogspot.com/feeds/8223587056273424808/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://semicolonreport.blogspot.com/2009/09/plug-for-improved-jquery-flip-effect.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8998567056484984795/posts/default/8223587056273424808'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8998567056484984795/posts/default/8223587056273424808'/><link rel='alternate' type='text/html' href='http://semicolonreport.blogspot.com/2009/09/plug-for-improved-jquery-flip-effect.html' title='Plug for Improved jQuery Flip effect plugin'/><author><name>Henrik Hjelte</name><uri>http://www.blogger.com/profile/14572554303466957938</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8998567056484984795.post-94734553176722476</id><published>2009-08-29T14:27:00.003+02:00</published><updated>2009-08-29T14:45:52.181+02:00</updated><title type='text'>Code-writing code in Javascript ;</title><content type='html'>&lt;p&gt;When you are coding in Lisp it is perfectly natural to write code that writes code. You make your own language as you go. This is with Lisp macros. I have &lt;a href="http://semicolonreport.blogspot.com/2009/06/lisp-macros-explained-in-javascript.html"&gt;explained macros in Javascript&lt;/a&gt; in another post. You actually can use a similar technique in Javascript, but without macros.&lt;/p&gt;&lt;p&gt;One thing which is very use for code-writing code is to implement a specification of some kind. It can be many kinds of specifications, in this example the spec is a &lt;a href="http://en.wikipedia.org/wiki/Comma-separated_values"&gt;CSV file&lt;/a&gt;. That is a comma separated file. You have a list of headers meaning something, and you want to make a program to read this file and access the different rows and columns.&lt;/p&gt;&lt;p&gt;Imagine the specification defines customerNr, hairColorId, and so on, in total maybe 53 fields. You want to access these properties in different ways and have some nice solution to keep it all together. Perhaps you want an event system, so other objects can listen to when the hairColorId changes and update something on the screen.&lt;/p&gt;&lt;p&gt;If you are a certain kind of consultant you will want to store the 53 fields in an array and remember the index number of each property. Now if someone inserts a changes the spec you will have to spend a lot of time updating the index numbers. Also it will make it very unreadable, what does theArray[11] really mean? If you are lucky you are the only one that knows and you will be irreplaceable.&lt;/p&gt;&lt;p&gt;I don't want to store it as a JSON type object literal. If we use direct access it makes it difficult to add the event feature, checking the validity of the data and things like this. Access should be through functions.&lt;/p&gt;&lt;p&gt;I don't want the upcoming javascript &lt;a href="http://robertnyman.com/2009/05/28/getters-and-setters-with-javascript-code-samples-and-demos/"&gt;magic set/get handing&lt;/a&gt; of properties. It hides the fact that access is made through a function and makes it difficult to find things that need to be refactored. You can't tell if someclass.customerId is direct access like in the previous section (refactor in my opinion) or a magic setter. The ugly smell has gone, and we need the smell to be able to refactor.&lt;/p&gt;&lt;p&gt;I would want to access this with read/write set/get och what ever you call them, accessor functions. They are a nice spot to throw out events and makes it easy to change the specification. But I don't want to make all these getter and setter functions manually. It makes it error prone and quite difficult to update. And I definitely don't want some magic XML spec outside the file generate the code for me. I want to have control.&lt;/p&gt;&lt;p&gt;I want something like this:&lt;/p&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;    &lt;!--&lt;br /&gt;      .snippet .keyword {&lt;br /&gt;        /* font-lock-keyword-face */&lt;br /&gt;        color: #a020f0;&lt;br /&gt;      }&lt;br /&gt;      .snippet .string {&lt;br /&gt;        /* font-lock-string-face */&lt;br /&gt;        color: #006400;&lt;br /&gt;      }&lt;br /&gt;      .snippet .variable-name {&lt;br /&gt;        /* font-lock-variable-name-face */&lt;br /&gt;        color: #b8860b;&lt;br /&gt;      }&lt;br /&gt;--&gt;&lt;br /&gt;    &lt;/style&gt;&lt;br /&gt;&lt;pre class="snippet"&gt;&lt;br /&gt;&lt;span class="keyword"&gt;var&lt;/span&gt; &lt;span class="variable-name"&gt;specification&lt;/span&gt; = [&lt;span class="string"&gt;'customerId'&lt;/span&gt;,&lt;span class="string"&gt;'hairColorId'&lt;/span&gt;];&lt;br /&gt;&lt;span class="keyword"&gt;var&lt;/span&gt; &lt;span class="variable-name"&gt;customer&lt;/span&gt; = makeCSVwrapper(specification);&lt;br /&gt;customer.setCustomerId(56);&lt;br /&gt;customer.setHairColorId(&lt;span class="string"&gt;'blue'&lt;/span&gt;);&lt;br /&gt;customer.onHairColorIdChange(&lt;span class="keyword"&gt;function&lt;/span&gt; () {&lt;br /&gt;   alert(&lt;span class="string"&gt;"Changed hair: "&lt;/span&gt; + customer.getHairColorId());&lt;br /&gt;});&lt;br /&gt;&lt;span class="keyword"&gt;var&lt;/span&gt; &lt;span class="variable-name"&gt;csv&lt;/span&gt;=customer.formatCSV();&lt;br /&gt;sendToServer(csv);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;What is the deal?&lt;/p&gt;&lt;p&gt;The whole specification is defined in one line of code. set- and get- functions are created automatically based on the spec.&lt;/p&gt;&lt;p&gt;If a new field is added to the specification we only need to update in one line of code. No editing of setters and getters.&lt;/p&gt;&lt;p&gt;If hairColorId is removed from the specification, we only need to change in one line. And we will spot deprecated code because customer.setHairColorId will now be an error. But if we had direct access as customer.hairColorId = 'blue' this would not cause an error. It would be a bug more difficult to detect.&lt;/p&gt;&lt;p&gt;The risk of typing errors in your setters and getters decrease. The file size decrease. Finally it shows something Javascript can do but most languages can't.&lt;/p&gt;&lt;h3&gt;Demo&lt;/h3&gt;&lt;p&gt;I have a flashy alert-message based &lt;a href="http://semicolonreport.blogspot.com/2009/08/code-writing-demo.html"&gt;demo and source code&lt;/a&gt; you can try.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8998567056484984795-94734553176722476?l=semicolonreport.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semicolonreport.blogspot.com/feeds/94734553176722476/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://semicolonreport.blogspot.com/2009/08/code-writing-code-in-javascript.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8998567056484984795/posts/default/94734553176722476'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8998567056484984795/posts/default/94734553176722476'/><link rel='alternate' type='text/html' href='http://semicolonreport.blogspot.com/2009/08/code-writing-code-in-javascript.html' title='Code-writing code in Javascript ;'/><author><name>Henrik Hjelte</name><uri>http://www.blogger.com/profile/14572554303466957938</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8998567056484984795.post-5995608425975569804</id><published>2009-08-29T10:43:00.023+02:00</published><updated>2009-08-29T14:25:01.627+02:00</updated><title type='text'>Code Writing Demo ;</title><content type='html'>&lt;h1&gt;Code Writing Demo&lt;/h1&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;What is the deal?&lt;/p&gt;&lt;p&gt;The whole specification is defined in one line of code. set- and get- functions are created automatically based on the spec.&lt;/p&gt;&lt;p&gt;If a new field is added to the specification we only need to update in one line of code. No editing of setters and getters.&lt;/p&gt;&lt;p&gt;If hairColorId is removed from the specification, we only need to change in one line. And we will spot deprecated code because customer.setHairColorId will now be an error. But if we had direct access as customer.hairColorId = 'blue' this would not cause an error. It would be a bug more difficult to detect.&lt;/p&gt;&lt;p&gt;The risk of typing errors in your setters and getters decrease. The file size decrease. Finally it shows something Javascript can do but most languages can't.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;I also have a &lt;a href="http://semicolonreport.blogspot.com/2009/08/code-writing-code-in-javascript.html"&gt;longer post&lt;/a&gt; about this.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://semicolonreport.blogspot.com/"&gt;Henrik Hjelte / Semicolon report&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;&lt;br /&gt;Click button to try demo:&lt;br /&gt;&lt;/h2&gt;&lt;br /&gt;&lt;input onclick="javascript:demo();" value="Run demo" type="button"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- Created by htmlize-1.34 in css mode. --&gt;&lt;br /&gt;  &lt;style type="text/css"&gt;&lt;br /&gt;    &lt;!--          .codechunk { font-size: small;}    .builtin {         /* font-lock-builtin-face */         color: #da70d6;       }       .comment {         /* font-lock-comment-face */         color: #b22222;       }       .function-name {         /* font-lock-function-name-face */         color: #0000ff;       }       .js2-function-param {         /* js2-function-param-face */         color: #2e8b57;       }       .keyword {         /* font-lock-keyword-face */         color: #a020f0;       }       .string {         /* font-lock-string-face */         color: #006400;       }       .variable-name {         /* font-lock-variable-name-face */         color: #b8860b;       }        pre a {         color: inherit;         background-color: inherit;         font: inherit;         text-decoration: inherit;       }       pre a:hover {         text-decoration: underline;       }     --&gt;&lt;br /&gt;    &lt;/style&gt;&lt;br /&gt;&lt;br /&gt;  &lt;pre style="font-size: xx-small; line-height: 70%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;var&lt;/span&gt; &lt;span class="function-name"&gt;makeSetterGetter&lt;/span&gt; = &lt;span class="keyword"&gt;function&lt;/span&gt; (&lt;span class="js2-function-param"&gt;definitionArray&lt;/span&gt;) {&lt;br /&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;function&lt;/span&gt; &lt;span class="function-name"&gt;each&lt;/span&gt; (&lt;span class="js2-function-param"&gt;array&lt;/span&gt;,&lt;span class="js2-function-param"&gt;fn&lt;/span&gt;) {&lt;br /&gt;      &lt;span class="keyword"&gt;var&lt;/span&gt; &lt;span class="variable-name"&gt;len&lt;/span&gt; = array.length;&lt;br /&gt;      &lt;span class="keyword"&gt;for&lt;/span&gt; (&lt;span class="keyword"&gt;var&lt;/span&gt; &lt;span class="variable-name"&gt;i&lt;/span&gt; = 0; i &amp;lt; len; i=i+1) {&lt;br /&gt;          &lt;span class="keyword"&gt;var&lt;/span&gt; &lt;span class="variable-name"&gt;el&lt;/span&gt; = array[i];&lt;br /&gt;          fn(el);&lt;br /&gt;      }&lt;br /&gt;  };&lt;br /&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;function&lt;/span&gt; &lt;span class="function-name"&gt;capitalize&lt;/span&gt; (&lt;span class="js2-function-param"&gt;str&lt;/span&gt;) {&lt;br /&gt;      &lt;span class="keyword"&gt;return&lt;/span&gt; str.charAt(0).toUpperCase()+str.substring(1);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;function&lt;/span&gt; &lt;span class="function-name"&gt;fireEventName&lt;/span&gt; (&lt;span class="js2-function-param"&gt;propertyName&lt;/span&gt;) {&lt;br /&gt;      &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="string"&gt;"fire"&lt;/span&gt; + capitalize(propertyName) + &lt;span class="string"&gt;"Change"&lt;/span&gt;;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;var&lt;/span&gt; &lt;span class="variable-name"&gt;self&lt;/span&gt; = {&lt;br /&gt;      &lt;span class="comment"&gt;// You can override these functions for tweaking&lt;/span&gt;&lt;br /&gt;      &lt;span class="function-name"&gt;_internalPropertyName&lt;/span&gt; : &lt;span class="keyword"&gt;function&lt;/span&gt; (&lt;span class="js2-function-param"&gt;propertyName&lt;/span&gt;) {&lt;br /&gt;          &lt;span class="keyword"&gt;return&lt;/span&gt; propertyName;&lt;br /&gt;      },&lt;br /&gt;&lt;br /&gt;      &lt;span class="function-name"&gt;_setParam&lt;/span&gt; : &lt;span class="keyword"&gt;function&lt;/span&gt; (&lt;span class="js2-function-param"&gt;paramName&lt;/span&gt;, &lt;span class="js2-function-param"&gt;value&lt;/span&gt;) {&lt;br /&gt;          &lt;span class="builtin"&gt;this&lt;/span&gt;[&lt;span class="builtin"&gt;this&lt;/span&gt;._internalPropertyName(paramName)] = value;&lt;br /&gt;          &lt;span class="keyword"&gt;var&lt;/span&gt; &lt;span class="variable-name"&gt;fireFn&lt;/span&gt; = &lt;span class="builtin"&gt;this&lt;/span&gt;[fireEventName(paramName)];&lt;br /&gt;          fireFn(value);&lt;br /&gt;          &lt;span class="keyword"&gt;return&lt;/span&gt; value;&lt;br /&gt;      },&lt;br /&gt;&lt;br /&gt;      &lt;span class="function-name"&gt;_getParam&lt;/span&gt; : &lt;span class="keyword"&gt;function&lt;/span&gt; (&lt;span class="js2-function-param"&gt;paramName&lt;/span&gt;) {&lt;br /&gt;          &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="builtin"&gt;this&lt;/span&gt;[&lt;span class="builtin"&gt;this&lt;/span&gt;._internalPropertyName(paramName)];&lt;br /&gt;      },&lt;br /&gt;    &lt;br /&gt;      &lt;span class="function-name"&gt;getDefinitionArray&lt;/span&gt; : &lt;span class="keyword"&gt;function&lt;/span&gt; () {&lt;br /&gt;          &lt;span class="keyword"&gt;return&lt;/span&gt; definitionArray;&lt;br /&gt;      }&lt;br /&gt;  };&lt;br /&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;function&lt;/span&gt; &lt;span class="function-name"&gt;makeSetterAndGetterMethod&lt;/span&gt; (&lt;span class="js2-function-param"&gt;propertyName&lt;/span&gt;) {&lt;br /&gt;      &lt;span class="keyword"&gt;var&lt;/span&gt; &lt;span class="variable-name"&gt;getterName&lt;/span&gt; = &lt;span class="string"&gt;"get"&lt;/span&gt; + capitalize(propertyName);&lt;br /&gt;      &lt;span class="keyword"&gt;var&lt;/span&gt; &lt;span class="variable-name"&gt;setterName&lt;/span&gt; = &lt;span class="string"&gt;"set"&lt;/span&gt; + capitalize(propertyName);&lt;br /&gt;      self[getterName] = &lt;span class="keyword"&gt;function&lt;/span&gt; () {&lt;br /&gt;          &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="builtin"&gt;this&lt;/span&gt;._getParam(propertyName);&lt;br /&gt;      };&lt;br /&gt;      self[setterName] = &lt;span class="keyword"&gt;function&lt;/span&gt; (&lt;span class="js2-function-param"&gt;value&lt;/span&gt;) {&lt;br /&gt;          &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="builtin"&gt;this&lt;/span&gt;._setParam(propertyName,value);&lt;br /&gt;      };&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;function&lt;/span&gt; &lt;span class="function-name"&gt;makeEventFunction&lt;/span&gt;(&lt;span class="js2-function-param"&gt;propertyName&lt;/span&gt;) {&lt;br /&gt;      &lt;span class="comment"&gt;// subscribers is a closure that will be unique for each call to&lt;/span&gt;&lt;br /&gt;      &lt;span class="comment"&gt;// makeEventFunction.&lt;/span&gt;&lt;br /&gt;      &lt;span class="keyword"&gt;var&lt;/span&gt; &lt;span class="variable-name"&gt;subscribers&lt;/span&gt; = [];&lt;br /&gt;&lt;br /&gt;      &lt;span class="keyword"&gt;var&lt;/span&gt; &lt;span class="function-name"&gt;registerSubscriberFn&lt;/span&gt; = &lt;span class="keyword"&gt;function&lt;/span&gt; (&lt;span class="js2-function-param"&gt;fn&lt;/span&gt;) {&lt;br /&gt;          subscribers.push(fn);&lt;br /&gt;      };&lt;br /&gt;      &lt;span class="keyword"&gt;var&lt;/span&gt; &lt;span class="function-name"&gt;fireEventFn&lt;/span&gt; = &lt;span class="keyword"&gt;function&lt;/span&gt; (&lt;span class="js2-function-param"&gt;value&lt;/span&gt;) {&lt;br /&gt;          &lt;span class="comment"&gt;// subscribers is an array of callback functions,&lt;/span&gt;&lt;br /&gt;          &lt;span class="comment"&gt;// call each of them with value and self (optional parameters)&lt;/span&gt;&lt;br /&gt;          each(subscribers,&lt;span class="keyword"&gt;function&lt;/span&gt; (&lt;span class="js2-function-param"&gt;fn&lt;/span&gt;) {&lt;br /&gt;                   fn(value,self);&lt;br /&gt;          });&lt;br /&gt;      };&lt;br /&gt;      &lt;span class="keyword"&gt;var&lt;/span&gt; &lt;span class="variable-name"&gt;eventSubscribe&lt;/span&gt; = &lt;span class="string"&gt;"on"&lt;/span&gt; + capitalize(propertyName) + &lt;span class="string"&gt;"Change"&lt;/span&gt;;&lt;br /&gt;      &lt;span class="keyword"&gt;var&lt;/span&gt; &lt;span class="variable-name"&gt;fireEventFnName&lt;/span&gt; = fireEventName(propertyName);&lt;br /&gt;      &lt;span class="comment"&gt;// Add the methods to self.&lt;/span&gt;&lt;br /&gt;      &lt;span class="comment"&gt;// if eventSubscibe is onHairColorIdChange then&lt;/span&gt;&lt;br /&gt;      &lt;span class="comment"&gt;// it will be callable with self.onHairColorIdChange&lt;/span&gt;&lt;br /&gt;      self[eventSubscribe] = registerSubscriberFn;&lt;br /&gt;      self[fireEventFnName] = fireEventFn;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  each(definitionArray, makeSetterAndGetterMethod);&lt;br /&gt;  each(definitionArray, makeEventFunction);&lt;br /&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;return&lt;/span&gt; self;&lt;br /&gt;  &lt;span class="comment"&gt;// Put the result of calling makeSetterGetter in a variable x&lt;/span&gt;&lt;br /&gt;  &lt;span class="comment"&gt;// You can now call x.setHairColorId which through _setParam&lt;/span&gt;&lt;br /&gt;  &lt;span class="comment"&gt;// calls x.fireHairColorIdChange which is one of the fireEventFn &lt;/span&gt;&lt;br /&gt;  &lt;span class="comment"&gt;// added that has access to the subscribers array and &lt;/span&gt;&lt;br /&gt;  &lt;span class="comment"&gt;// can call the callback functions you might have added with &lt;/span&gt;&lt;br /&gt;  &lt;span class="comment"&gt;// onhairColorIdChange(function (value,obj) {doStuff();});&lt;/span&gt;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;function&lt;/span&gt; &lt;span class="function-name"&gt;demo&lt;/span&gt;() {&lt;br /&gt;  &lt;span class="keyword"&gt;function&lt;/span&gt; &lt;span class="function-name"&gt;map&lt;/span&gt; (&lt;span class="js2-function-param"&gt;array&lt;/span&gt;,&lt;span class="js2-function-param"&gt;fn&lt;/span&gt;) {&lt;br /&gt;      &lt;span class="keyword"&gt;var&lt;/span&gt; &lt;span class="variable-name"&gt;result&lt;/span&gt; = [];&lt;br /&gt;      &lt;span class="keyword"&gt;var&lt;/span&gt; &lt;span class="variable-name"&gt;len&lt;/span&gt; = array.length;&lt;br /&gt;      &lt;span class="keyword"&gt;for&lt;/span&gt; (&lt;span class="keyword"&gt;var&lt;/span&gt; &lt;span class="variable-name"&gt;i&lt;/span&gt; = 0; i &amp;lt; len; i=i+1) {&lt;br /&gt;          &lt;span class="keyword"&gt;var&lt;/span&gt; &lt;span class="variable-name"&gt;el&lt;/span&gt; = array[i];&lt;br /&gt;          result.push(fn(el));&lt;br /&gt;      }&lt;br /&gt;      &lt;span class="keyword"&gt;return&lt;/span&gt; result;&lt;br /&gt;  };&lt;br /&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;var&lt;/span&gt; &lt;span class="variable-name"&gt;specification&lt;/span&gt; = [&lt;span class="string"&gt;'customerId'&lt;/span&gt;,&lt;span class="string"&gt;'hairColorId'&lt;/span&gt;];&lt;br /&gt;  &lt;span class="keyword"&gt;var&lt;/span&gt; &lt;span class="variable-name"&gt;customer&lt;/span&gt; = makeSetterGetter(specification);&lt;br /&gt;&lt;br /&gt;  customer.onHairColorIdChange(&lt;span class="keyword"&gt;function&lt;/span&gt; (&lt;span class="js2-function-param"&gt;value&lt;/span&gt;,&lt;span class="js2-function-param"&gt;object&lt;/span&gt;) {&lt;br /&gt;      alert(&lt;span class="string"&gt;"3.Customer id "&lt;/span&gt;+ object.getCustomerId() +&lt;br /&gt;            &lt;span class="string"&gt;" has new haircolor "&lt;/span&gt; + value);&lt;br /&gt;  });&lt;br /&gt;&lt;br /&gt;  customer.onCustomerIdChange(&lt;span class="keyword"&gt;function&lt;/span&gt; () {&lt;br /&gt;      &lt;span class="comment"&gt;// This is ugly, but you can also access properties&lt;/span&gt;&lt;br /&gt;      &lt;span class="comment"&gt;// directly. This way I know no events will be triggered.&lt;/span&gt;&lt;br /&gt;      customer.hairColorId=&lt;span class="string"&gt;'DONT KNOW'&lt;/span&gt;;&lt;br /&gt;  });&lt;br /&gt;  alert(&lt;span class="string"&gt;"1.Customer starts with undefined color: "&lt;/span&gt; + customer.getHairColorId());&lt;br /&gt;  customer.setCustomerId(10);&lt;br /&gt;  alert(&lt;span class="string"&gt;"2.Secretly it has been set to don't know: "&lt;/span&gt; + customer.getHairColorId());&lt;br /&gt;  customer.setHairColorId(&lt;span class="string"&gt;'blue'&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;  customer.&lt;span class="function-name"&gt;commaSeparated&lt;/span&gt; = &lt;span class="keyword"&gt;function&lt;/span&gt; () {&lt;br /&gt;      &lt;span class="keyword"&gt;var&lt;/span&gt; &lt;span class="variable-name"&gt;self&lt;/span&gt; = &lt;span class="builtin"&gt;this&lt;/span&gt;;&lt;br /&gt;      &lt;span class="keyword"&gt;return&lt;/span&gt; map(&lt;span class="builtin"&gt;this&lt;/span&gt;.getDefinitionArray(), &lt;span class="keyword"&gt;function&lt;/span&gt;(&lt;span class="js2-function-param"&gt;paramName&lt;/span&gt;) {&lt;br /&gt;                     &lt;span class="keyword"&gt;return&lt;/span&gt; self._getParam(paramName);&lt;br /&gt;                 }).join(&lt;span class="string"&gt;','&lt;/span&gt;);&lt;br /&gt;  };&lt;br /&gt;&lt;br /&gt;  alert(&lt;span class="string"&gt;"4.Send this to the server:"&lt;/span&gt; + customer.commaSeparated());&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;   &lt;br /&gt;var makeSetterGetter = function (definitionArray) {&lt;br /&gt;    &lt;br /&gt;    function each (array,fn) {&lt;br /&gt;        var len = array.length;&lt;br /&gt;        for (var i = 0; i &lt; len; i=i+1) {&lt;br /&gt;            var el = array[i];&lt;br /&gt;            fn(el);&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;    function capitalize (str) {&lt;br /&gt;	return str.charAt(0).toUpperCase()+str.substring(1);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    function fireEventName (propertyName) {&lt;br /&gt;        return "fire" + capitalize(propertyName) + "Change";&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    var self = {&lt;br /&gt;        // You can override these functions for tweaking&lt;br /&gt;	_internalPropertyName : function (propertyName) {&lt;br /&gt;            return propertyName;&lt;br /&gt;	},&lt;br /&gt;&lt;br /&gt;	_setParam : function (paramName, value) {&lt;br /&gt;	    this[this._internalPropertyName(paramName)] = value;&lt;br /&gt;            var fireFn = this[fireEventName(paramName)];&lt;br /&gt;            fireFn(value);&lt;br /&gt;	    return value;&lt;br /&gt;	},&lt;br /&gt;&lt;br /&gt;	_getParam : function (paramName) {&lt;br /&gt;	    return this[this._internalPropertyName(paramName)];&lt;br /&gt;	},&lt;br /&gt;        &lt;br /&gt;        getDefinitionArray : function () {&lt;br /&gt;            return definitionArray;&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;    &lt;br /&gt;    function makeSetterAndGetterMethod (propertyName) {&lt;br /&gt;	var getterName = "get" + capitalize(propertyName);&lt;br /&gt;	var setterName = "set" + capitalize(propertyName);&lt;br /&gt;	self[getterName] = function () {&lt;br /&gt;	    return this._getParam(propertyName);&lt;br /&gt;	};&lt;br /&gt;	self[setterName] = function (value) {&lt;br /&gt;	    return this._setParam(propertyName,value);&lt;br /&gt;	};&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    function makeEventFunction(propertyName) {&lt;br /&gt;        // subscribers is a closure that will be unique for each call to&lt;br /&gt;        // makeEventFunction.&lt;br /&gt;        var subscribers = []; &lt;br /&gt;&lt;br /&gt;        var registerSubscriberFn = function (fn) {&lt;br /&gt;            subscribers.push(fn);&lt;br /&gt;        };&lt;br /&gt;        var fireEventFn = function (value) {&lt;br /&gt;            // subscribers is an array of callback functions,&lt;br /&gt;            // call each of them with value and self (optional parameters)&lt;br /&gt;            each(subscribers,function (fn) {&lt;br /&gt;                     fn(value,self);&lt;br /&gt;            });&lt;br /&gt;        };&lt;br /&gt;        var eventSubscribe = "on" + capitalize(propertyName) + "Change";&lt;br /&gt;        var fireEventFnName = fireEventName(propertyName);&lt;br /&gt;        // Add the methods to self.&lt;br /&gt;        // if eventSubscibe is onHairColorIdChange then&lt;br /&gt;        // it will be callable with self.onHairColorIdChange&lt;br /&gt;        self[eventSubscribe] = registerSubscriberFn;&lt;br /&gt;        self[fireEventFnName] = fireEventFn;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    each(definitionArray, makeSetterAndGetterMethod);&lt;br /&gt;    each(definitionArray, makeEventFunction);&lt;br /&gt;&lt;br /&gt;    return self;&lt;br /&gt;    // Put the result of calling makeSetterGetter in a variable x&lt;br /&gt;    // You can now call x.setHairColorId which through _setParam&lt;br /&gt;    // calls x.fireHairColorIdChange which is one of the fireEvemntFn &lt;br /&gt;    // added that has access to the subscribers array and &lt;br /&gt;    // can call the callback functions you might have added with &lt;br /&gt;    // onhairColorIdChange(function (value,obj) {doStuff();});&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;function demo() {&lt;br /&gt;    function map (array,fn) {&lt;br /&gt;        var result = [];&lt;br /&gt;        var len = array.length;&lt;br /&gt;        for (var i = 0; i &lt; len; i=i+1) {&lt;br /&gt;            var el = array[i];&lt;br /&gt;            result.push(fn(el));&lt;br /&gt;        }&lt;br /&gt;        return result;&lt;br /&gt;    };&lt;br /&gt;    &lt;br /&gt;    var specification = ['customerId','hairColorId'];&lt;br /&gt;    var customer = makeSetterGetter(specification);&lt;br /&gt;    &lt;br /&gt;    customer.onHairColorIdChange(function (value,object) {&lt;br /&gt;        alert("3.Customer id "+ object.getCustomerId() + &lt;br /&gt;              " has new haircolor " + value);&lt;br /&gt;    });&lt;br /&gt;&lt;br /&gt;    customer.onCustomerIdChange(function () {&lt;br /&gt;        // This is ugly, but you can also access properties&lt;br /&gt;        // directly. This way I know no events will be triggered.&lt;br /&gt;        customer.hairColorId='DONT KNOW';&lt;br /&gt;    });&lt;br /&gt;    alert("1.Customer starts with undefined color: " + customer.getHairColorId());&lt;br /&gt;    customer.setCustomerId(10);&lt;br /&gt;    alert("2.Secretly it has been set to don't know: " + customer.getHairColorId());&lt;br /&gt;    customer.setHairColorId('blue');&lt;br /&gt;    &lt;br /&gt;    customer.commaSeparated = function () {&lt;br /&gt;        var self = this;&lt;br /&gt;        return map(this.getDefinitionArray(), function(paramName) {&lt;br /&gt;                       return self._getParam(paramName);&lt;br /&gt;                   }).join(',');&lt;br /&gt;    };&lt;br /&gt;    &lt;br /&gt;    alert("4.Send this to the server:" + customer.commaSeparated());&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;--&gt;&lt;br /&gt;&lt;!-- I needed to compress it for blogger, you can kill/yank from above instead --&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;var makeSetterGetter=function(B){function E(L,K){var H=L.length;for(var I=0;I&lt;H;I=I+1){var J=L[I];K(J)}}function C(H){return H.charAt(0).toUpperCase()+H.substring(1)}function F(H){return"fire"+C(H)+"Change"}var A={_internalPropertyName:function(H){return H},_setParam:function(J,I){this[this._internalPropertyName(J)]=I;var H=this[F(J)];H(I);return I},_getParam:function(H){return this[this._internalPropertyName(H)]},getDefinitionArray:function(){return B}};function G(I){var J="get"+C(I);var H="set"+C(I);A[J]=function(){return this._getParam(I)};A[H]=function(K){return this._setParam(I,K)}}function D(I){var K=[];var H=function(N){K.push(N)};var M=function(N){E(K,function(O){O(N,A)})};var J="on"+C(I)+"Change";var L=F(I);A[J]=H;A[L]=M}E(B,G);E(B,D);return A};function demo(){function C(I,H){var E=[];var D=I.length;for(var F=0;F&lt;D;F=F+1){var G=I[F];E.push(H(G))}return E}var A=["customerId","hairColorId"];var B=makeSetterGetter(A);B.onHairColorIdChange(function(E,D){alert("3.Customer id "+D.getCustomerId()+" has new haircolor "+E)});B.onCustomerIdChange(function(){B.hairColorId="DONT KNOW"});alert("1.Customer starts with undefined color: "+B.getHairColorId());B.setCustomerId(10);alert("2.Secretly it has been set to don't know: "+B.getHairColorId());B.setHairColorId("blue");B.commaSeparated=function(){var D=this;return C(this.getDefinitionArray(),function(E){return D._getParam(E)}).join(",")};alert("4.Send this to the server:"+B.commaSeparated())};&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8998567056484984795-5995608425975569804?l=semicolonreport.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semicolonreport.blogspot.com/feeds/5995608425975569804/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://semicolonreport.blogspot.com/2009/08/code-writing-demo.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8998567056484984795/posts/default/5995608425975569804'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8998567056484984795/posts/default/5995608425975569804'/><link rel='alternate' type='text/html' href='http://semicolonreport.blogspot.com/2009/08/code-writing-demo.html' title='Code Writing Demo ;'/><author><name>Henrik Hjelte</name><uri>http://www.blogger.com/profile/14572554303466957938</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8998567056484984795.post-4044352009156793881</id><published>2009-06-24T17:35:00.009+02:00</published><updated>2009-08-29T11:48:07.458+02:00</updated><title type='text'>Lisp macros explained in Javascript</title><content type='html'>&lt;p&gt;My two favourite programming languages are Common Lisp and Javascript.&lt;/p&gt;&lt;p&gt;I want to explain some of the features of Lisp in a syntax that is understandable to everyone. Of course everyone does not understand Javascript, but this example is simple and understandable also to C and Java coders.&lt;/p&gt;&lt;h2 id="the-story"&gt;The story&lt;/h2&gt;&lt;p&gt;One day you see that you have a lot of small fragments in your code looking more or less like this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;if (someFunction(blaha)) {&lt;br /&gt;   doSomeThingWith(someFunction(blaha))&lt;br /&gt;   log(&amp;quot;I did something with&amp;quot;, someFunction(blaha));&lt;br /&gt;};&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You make a temporary variable to avoid running someFunction three times.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;var temp=someFunction(blaha);&lt;br /&gt;if (temp) {&lt;br /&gt;   doSomeThingWith(temp);&lt;br /&gt;   log(&amp;quot;I did something with&amp;quot;, temp);&lt;br /&gt;};&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You have now done this 2344 times in your career and at 34 places in your current project. SomeFunction takes 9999 ms. It smells. How long will it take until you want to refactor it?&lt;/p&gt;&lt;p&gt;In Javascript you can create new functions, but not syntactical constructs. And I can't really see how you would make a function to improve on this. But it would be cool if we could invent our own statements. What about this idea: An if statement that makes an automatic temporary variable that you can use later?&lt;/p&gt;&lt;pre&gt;&lt;code&gt;ifTemp (someFunction(blaha)) {&lt;br /&gt;   doSomeThingWith(temp);&lt;br /&gt;   log(&amp;quot;I did something with&amp;quot;, temp);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ifTemp would create a temp variable behind the scenes, put the result of someFunction in it and you could then refer to temp in the if clause. Now, if we are to hardcode the name of the variable, I would rather choose &amp;quot;it&amp;quot; instead of &amp;quot;temp&amp;quot;. It makes the code almost poethic when read out loud.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;ifit (someFunction(blaha)) {&lt;br /&gt;   doSomeThingWith(it);&lt;br /&gt;   log(&amp;quot;I did something with&amp;quot;, it);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I don't know who was the first to invent this, but I got the idea from Paul Graham and his book &lt;a href="http://www.paulgraham.com/onlisp.html"&gt;OnLisp&lt;/a&gt;. He calls this if-construct anaphoric if, as all we scholars instantly recognize from Greek rethorics. We could call this statement aif (a for anapahoric) instead of ifit.&lt;/p&gt;&lt;h2 id="an-anaphoric-if-macro-in-javascript"&gt;An anaphoric if-macro in Javascript&lt;/h2&gt;&lt;p&gt;Disclaimer: Don't try this at home. It won't work. This is just an example for how we probably would go about to do it, if it was possible.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;macro.defineMacro(&amp;quot;ifit&amp;quot;,function() {&lt;br /&gt;   macro.defineSyntax(&amp;quot;ifit&amp;quot;,&lt;br /&gt;     macro.expression,&lt;br /&gt;     macro.block,&lt;br /&gt;     macro.startOptional,&lt;br /&gt;     &amp;quot;else&amp;quot;, macro.block);&lt;br /&gt;   macro.defineExpander(function (context) {&lt;br /&gt;      var testExpression=context.getExpression();&lt;br /&gt;      context.moveForward();&lt;br /&gt;      var block=context.getBlock();&lt;br /&gt;&lt;br /&gt;      context.addStatement(&amp;quot;var it=&amp;quot;,textExpression);&lt;br /&gt;      context.addStatement(&amp;quot;if (it) &amp;quot;,block);&lt;br /&gt;&lt;br /&gt;      // Handle else part&lt;br /&gt;      context.moveForward();&lt;br /&gt;      if (context.hasMore) {&lt;br /&gt;          context.skipForward(&amp;quot;else&amp;quot;);&lt;br /&gt;          var elseBlock=context.getBlock();&lt;br /&gt;          context.addStatement(&amp;quot;else&amp;quot;,elseBlock);&lt;br /&gt;      };&lt;br /&gt;   });&lt;br /&gt;};&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In theory we could make something like this, parsing js files on the server, expanding macros and creating new js files to be loaded by the browser. But I won't do it. If I wanted to I would use a Lisp-like dialect instead (like &lt;a href="http://common-lisp.net/project/parenscript/"&gt;Parenscript&lt;/a&gt;).&lt;/p&gt;&lt;h2 id="translating-the-javascript-to-lisp"&gt;Translating the Javascript to Lisp&lt;/h2&gt;&lt;p&gt;Lisp statements have a simple syntax. The whole statement is surrounded by a pair of parenthes.&lt;/p&gt;&lt;p&gt;In semicolon based languages:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;someFunction(someValue,someOtherValue); &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In Lisp:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;(someFunction someValue someOtherValue)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Exactly the same number of parenthes by the way, and one less meaningless semicolon.&lt;/p&gt;&lt;p&gt;Javascript:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;ifit (someFunction(blaha)) {&lt;br /&gt;   doSomeThingWith(it);&lt;br /&gt;   log(&amp;quot;I did something with&amp;quot;, it);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Translated to Lisp:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;(whenit (someFunction blaha)&lt;br /&gt;   (doSomeThingWith it)&lt;br /&gt;   (log &amp;quot;I did something with&amp;quot; it))&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;quot;When&amp;quot; in Lisp is an &amp;quot;if&amp;quot; with no &amp;quot;else&amp;quot; clause. There is also an if-statement, but if we are to use it we need to put &amp;quot;doSomething&amp;quot; and &amp;quot;log&amp;quot; into a block (otherwise it thinks the log-statement is the else clause). A block in Lisp is actually a function called &amp;quot;progn&amp;quot;. Progn means execute statements in order and use the last value as value.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;(ifit (someFunction blaha)&lt;br /&gt;   (progn&lt;br /&gt;     (doSomeThingWith it)&lt;br /&gt;     (log &amp;quot;I did something with&amp;quot; it)))&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Defining a variable in Lisp is a statement &amp;quot;let&amp;quot; that takes a list of variables and value pairs as the first parameter, and then any number of statements where the variable is visible.&lt;/p&gt;&lt;p&gt;The thing we looked at first was this piece of Javascript:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;var temp=someFunction(blaha);&lt;br /&gt;if (temp) {&lt;br /&gt;   doSomeThingWith(temp);&lt;br /&gt;   log(&amp;quot;I did something with&amp;quot;, temp);&lt;br /&gt;};&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Translated to Lisp:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;(let ((temp (someFunction blaha)))&lt;br /&gt;   (if temp&lt;br /&gt;     (progn&lt;br /&gt;       (doSomeThingWith temp)&lt;br /&gt;       (log &amp;quot;I did something with&amp;quot; temp))))&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="an-anaphoric-macro-in-lisp"&gt;An anaphoric macro in Lisp&lt;/h2&gt;&lt;p&gt;Lisp macros are defined with defmacro. It is evaluated at compile time, and simply returns a Lisp statement. You get pieces of source-code as input parameters. These parameters are not evaluated. The macro can do things witht the source code it gets in and should return some new source code as output. Since Lisp has such a simple uniform syntax, creating and inspecting source code is not a difficult task.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;(defmacro ifit (testForm thenForm elseForm)&lt;br /&gt;   (let ((srcCode &amp;quot;(let ((temp EXPRESSION))&lt;br /&gt;                      (if temp THEN ELSE&amp;quot;))&lt;br /&gt;      (replace srcCode &amp;quot;EXPRESSION&amp;quot; testForm)&lt;br /&gt;      (replace srcCode &amp;quot;THEN&amp;quot; thenForm)&lt;br /&gt;      (replace srcCode &amp;quot;ELSE&amp;quot; elseForm)&lt;br /&gt;      (return srcCode))))))&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To be truthful, actually the real world syntax it is even shorter and prettier using the backquote and comma subsitution mechanism. Notice that this is quite a bit shorter than the fake Javascript macro earlier.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;(defmacro ifit (testForm thenForm elseForm)&lt;br /&gt;  `(let ((it ,testForm))&lt;br /&gt;     (if it ,thenForm ,elseForm)))&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="what-is-the-deal"&gt;What is the deal?&lt;/h2&gt;&lt;p&gt;Macros can be used for a lot of things. From small utilities like these to advanced embedded languages. Offloading lengthy calculations to compile time (Substitute &amp;quot;compile time&amp;quot; to on the &amp;quot;the server&amp;quot; for Javascript). Everything that Java uses &amp;quot;Annotations&amp;quot; for, but with more flexibility. If you get bored with Javascript, i suggest you take a look at Lisp. I recommend the book &lt;a href="http://gigamonkeys.com/book/"&gt;Practical Common Lisp&lt;/a&gt; as a good start. Some other great things about (Common) Lisp is a fresh view of object-orientation and unique exception-handling with restarts.&lt;/p&gt;&lt;h2 id="disclaimer"&gt;Disclaimer&lt;/h2&gt;&lt;p&gt;I have made Lisp a little more mainstream in these examples in order to arguable make it easier to grasp. I would not call this simplification. On the contrary. Some would call it obfuscating.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8998567056484984795-4044352009156793881?l=semicolonreport.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semicolonreport.blogspot.com/feeds/4044352009156793881/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://semicolonreport.blogspot.com/2009/06/lisp-macros-explained-in-javascript.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8998567056484984795/posts/default/4044352009156793881'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8998567056484984795/posts/default/4044352009156793881'/><link rel='alternate' type='text/html' href='http://semicolonreport.blogspot.com/2009/06/lisp-macros-explained-in-javascript.html' title='Lisp macros explained in Javascript'/><author><name>Henrik Hjelte</name><uri>http://www.blogger.com/profile/14572554303466957938</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
