tag:blogger.com,1999:blog-49594267210555740102024-03-08T17:25:39.048-08:00Electronic IncantationsUbuntu, C/C++, JavaScript, PHP, (X)HTML, CSS, PythonChris "Jesdisciple"http://www.blogger.com/profile/00251874665739661016noreply@blogger.comBlogger12125tag:blogger.com,1999:blog-4959426721055574010.post-66233175745962055042013-04-10T12:50:00.000-07:002013-04-11T23:57:11.738-07:00Unity3D Serialization<br />
Another infrequent post, another entirely different programming topic.<br />
<br />
I'm developing a mobile game with Unity3D (C# only), and I rolled my own serialization and deserialization code for it. I recently decided to see what stable general solutions exist, and found these:<br />
<br />
<ul>
<li>Unity has built-in serialization functionality which is not the same as that in .NET. I haven't investigated this option yet, but I know that a derived type's stuff will not be stored in a serialization of a base-type variable (see the second link).</li>
<ul>
<li><a href="http://blogs.unity3d.com/2012/10/25/unity-serialization/">http://blogs.unity3d.com/2012/10/25/unity-serialization/</a></li>
<li><a href="http://www.codingjargames.com/blog/2012/11/30/advanced-unity-serialization/">http://www.codingjargames.com/blog/2012/11/30/advanced-unity-serialization/</a></li>
</ul>
<li>whydoidoit's Unity Serializer looks like a good Unity-specific option. I will probably end up settling on this as the proper thing in Unity. I was kind of hoping to use a vanilla XML NET solution, but that looks infeasible at this point, as described below.</li>
<ul>
<li><a href="http://whydoidoit.com/unityserializer/">http://whydoidoit.com/unityserializer/</a></li>
</ul>
<li>XmlSerializer is the very general .NET solution; it will do as much as it can for you (short of serializing anything other than public properties), and you can override its behavior with IXmlSerializable. But it requires that any IEnumerable or ICollection implementations have Add methods. UnityEngine.Transform implements IEnumerable and lacks an Add method, so GameObjects cannot be serialized this way.<br />But the deal-breaker for me is that I've already implemented a serializer for IDictionary (because XmlSerializer rejects anything with that interface), and my IXmlSerializable implementations keep multiplying. Maybe I'm just doing it wrong.</li>
<ul>
<li><a href="http://wiki.unity3d.com/index.php?title=Saving_and_Loading_Data:_XmlSerializer">http://wiki.unity3d.com/index.php?title=Saving_and_Loading_Data:_XmlSerializer</a></li>
<li><a href="http://www.danrigsby.com/blog/index.php/2008/03/07/xmlserializer-vs-datacontractserializer-serialization-in-wcf/">http://www.danrigsby.com/blog/index.php/2008/03/07/xmlserializer-vs-datacontractserializer-serialization-in-wcf/</a></li>
</ul>
<li>DataContractSerializer is the less-flexible, more-efficient counterpart to XmlSerializer that lets you serialize any and all read-write properties and fields, not just public properties. But the author of the class to be serialized must have specified that DataContractSerializer can serialize that class - so only custom classes/structs will work with this; forget everything in UnityEngine.</li>
<ul>
<li><a href="http://www.danrigsby.com/blog/index.php/2008/03/07/xmlserializer-vs-datacontractserializer-serialization-in-wcf/">http://www.danrigsby.com/blog/index.php/2008/03/07/xmlserializer-vs-datacontractserializer-serialization-in-wcf/</a></li>
</ul>
<li>BinaryFormatter is an attractive .NET-only option because binary can represent anything with ease, even circular references. The object model is already binary in RAM, after all. Unfortunately the results will naturally not be intelligible to humans and a level-designer could never be expected to generate/modify it by hand.</li>
<ul>
<li><a href="http://www.mono-software.com/blog/post/Mono/117/NET-Binary-serialization-the-pitfalls/">http://www.mono-software.com/blog/post/Mono/117/NET-Binary-serialization-the-pitfalls/</a></li>
<li><a href="http://www.codeproject.com/Articles/311944/BinaryFormatter-or-Manual-serializing">http://www.codeproject.com/Articles/311944/BinaryFormatter-or-Manual-serializing</a></li>
</ul>
</ul>
<br />Chris "Jesdisciple"http://www.blogger.com/profile/00251874665739661016noreply@blogger.com0tag:blogger.com,1999:blog-4959426721055574010.post-63994430355772924202012-02-05T06:40:00.000-08:002012-02-05T12:04:21.179-08:00Bazaar Explorer, Launchpad, Qt: Configuration IssuesTwo friends and I started <a href="https://launchpad.net/chaos2d">Chaos2D</a> yesterday. We ended up deciding to use QtCreator as the IDE and Launchpad (Bazaar) to manage the project. We downloaded Bazaar Explorer, naturally, and the fun began. This post is a guide for my past self; I'm sending it back next time the DeLorean passes by. Note that my experiences are from Ubuntu 11.10, but of course you have that by now.<br /><br />Firstly, in QtCreator select Tools > Options > Version Control > Bazaar. Enter /usr/bin/bzr in the Command field, and also fill in your Launchpad username and password (I'm not certain those are required). I guess QtCreator doesn't provide for getting the source, but once you have a Bazaar repository it can take it from there.<br /><br />While typing this, I couldn't remember a detail and had to get <a href="http://doc.bazaar.canonical.com/explorer/en/tutorials/foss-contribute.html">some help (important!)</a> from Google. I think I also had to <a href="https://help.launchpad.net/YourAccount/ImportingYourPGPKey">make an OpenPGP key</a> to get Launchpad to acquiesce to my request.<br /><br />Then Bazaar complained about not being able to authenticate Launchpad; I couldn't find anything on Google about that, so I just said yes and it added Launchpad as a trusted site. At this point I decided to sign the Ubuntu Code of Conduct since I had the OpenPGP key anyway.<br /><br />Finally, I didn't like retyping my SSH password every time. <a href="https://answers.launchpad.net/bzr/+question/164273">This</a> is apparently the proper, secure solution. I didn't know about it at the time, so I did <a href="https://answers.launchpad.net/bzr-explorer/+question/178357">this</a> and changed my Launchpad password to something I don't use promiscuously.<br /><br />Oh, I almost forgot. Bazaar Explorer seems to ignore all ignore rules, so I recommend directly using the less-<span style="font-weight:bold;">bold</span> bzr command. I might have said that anyway, after this bizarre experience.Chris "Jesdisciple"http://www.blogger.com/profile/00251874665739661016noreply@blogger.com0tag:blogger.com,1999:blog-4959426721055574010.post-67750273883420600822010-05-02T14:21:00.000-07:002010-05-02T14:43:52.076-07:00Learning Lisp<span style="font-style:italic;">This journal was originally <a href="https://wave.google.com/wave/#restored:wave:googlewave.com!w%252BPbkOIBPoA,restored:wave:googlewave.com!w%252BuE3x3-Z6G.1">posted to Google Wave</a> on February 7, 2010 and edited incrementally. The resulting discussions are not yet included.</span><br /><br />I've heard a lot about Lisp, especially now that I'm in an AI Programming course in college (but it's mainly regarded as a relic in there). I love JavaScript's functional features, but I hadn't managed to dive into their source until now. I'm using Common Lisp for now, with some elisp along the way, although Scheme probably won't be far behind. So this is going to start out as a journal of my experiences.<br /><br />Background: I know about eight programming languages already, and feel that I can learn any I like. My favorites so far are JavaScript and then Python, precisely because of the Lispy features, so I think I'll love Lisp once I'm fluent in it. On the other hand, I have only programmed as a hobby so far. Keep that in mind if you try Lisp out yourself; your mileage may vary.<br /><br />I installed clisp+slime using this guide: <a href="http://www.osix.net/modules/article/?id=912">http://www.osix.net/modules/article/?id=912</a><br /><br />I'm using this tutorial: <a href="http://www.gigamonkeys.com/book/">http://www.gigamonkeys.com/book/</a><br /><br /><span style="font-weight:bold;">2/7/10</span><br /><br />I can think of two gotchas I've run into so far: a function body doesn't get wrapped in parentheses, and the first parenthesis goes before the called function's name, not after. Oh, and lists aren't supposed to be comma-delimited.<br /><br />Naturally, macros are kind of hard to grasp. But I finally decided the most concise description is lazily-evaluated functions, based on the tutorial's explanation.<br /><br />Right now I'm wondering how to do classes (prototypes?!), although I saw define-class and define-method mentioned in library code. But I'll wait until the tutorial gets to those.<br /><span style="font-weight:bold;"><br />2/8/10</span><br /><br />For my inaugural Lisp project I'm implementing the JavaScript object model into Common Lisp. I'm learning a lot about CL's Lisp-2 nature and thinking I'll like Scheme more. But I won't decide that until I've mastered the essential features of CL such as macros and CLOS. (Note to self: Those ugly punctuation doo-hickies are called "read macros.")<br /><br />But I really need to learn how to debug in emacs+slime+clisp. For that matter I need to learn to use the REPL for programming.<br /><br /><span style="font-weight:bold;">2/11/10</span><br /><br />Because Common Lisp is a Lisp-2, that is a Lisp with two namespaces for variables and functions:<br /><br /><ul><li><code>(fdefinition `foo)</code> is the best place to SETF a global/dynamic function, if the global function FOO is already defined. I hack this up by saying <code>(defun foo () )</code> before I need to SETF it.</li><br /><li>If a function is instead assigned as a variable it must be called with <code>(funcall foo arg0 arg1 ...)</code> or <code>(apply foo args)</code>.</li><br /><li>To bind a function in the local/lexical scope and not need to call it with FUNCALL/APPLY you must alias it:<br /><pre>(let ((foo (lambda ()<br /> #| ... |#)))<br /> (flet ((foo (&rest args)<br /> (apply foo args)))<br /> ;Now we can call it without FUNCALL:<br /> (foo)))</pre></li><br /><li>Note that the above code demonstrates what "Lisp-2" means: The function FOO is in a different namespace than the variable FOO, and their values are not inherently related. The function FOO can be get'ed with #'foo.</li></ul><br /><br /><span style="font-weight:bold;">Why?</span><br /><br />The Common Lisp community explains that the power of CL macros justifies the Lisp-2 nature. I am not yet qualified to give an opinion on the matter.<br /><br /><span style="font-weight:bold;">2/13/10</span><br /><br />The LOOP macro had me stuck for a long while (no pun intended) on a syntax error. I finally got that cleared up, but now I have an infinite loop - bah. Anyway, here are the two things I learned, using <a href="http://www.ai.sri.com/pkarp/loop.html">http://www.ai.sri.com/pkarp/loop.html</a> as my primary reference... (The <a href="http://www.google.com/url?sa=D&q=http%3A%2F%2Fwww.gigamonkeys.com%2Fbook%2Fmacros-standard-control-constructs.html">chapter</a> in Practical Common Lisp helped too, but only by mentioning the word "do" - I got too excited to keep reading.)<br /><br /><ul><li>Sentry variables for a 'while' loop must be assigned outside the loop itself, in a LET for example. ("for x from y" might work too; I didn't check. But "for x = y" makes that assignment every iteration.)</li><br /><li>The 'do' after the condition-form of your 'while' is there for a reason. This is what kept me stumped for a few days, because the error just said "syntax error" instead of "'do' expected." I decided to put the 'do' on the same line as the 'while' since I don't see any reason they might ever be separated.</li></ul><br /><br /><span style="font-weight:bold;">2/16/10</span><br /><br />In JavaScript, <code>this</code> is a pseudo-variable that changes for each function but cannot be assigned to. I wanted to make my JS functions syntactically similar to native Lisp functions, so I declared the function's lambda list and body as parameters to the function that manufactures JS functions (the Function constructor).<br /><br />I managed to add this to the list of arguments passed from outside, and declared it in the lambda list. But then I needed to declare a new function using a (list "variable" "like" "this" "one") as the lambda list and the passed-in body. That didn't work; apparently the lazy compiler insists on knowing what each function looks like at compile-time. </self-deprecating-sarcasm><br /><br />Alright, enough about JS mechanics; here's the solution I got on a forum:<br /><br /><pre>(defvar *this* "JavaScript details")<br />(defun makefun (name lambda)<br /> (labels ((havefun (&rest args)<br /> (let ((*this* "more details"))<br /> (apply lambda args))))<br /> #'havefun))<br />(funcall (makefun "will travel" (lambda ()<br /> (print *this*))))</pre><br /><br />I didn't compile that, but it should print "more details." What's sad is that I had read about special variables shortly before asking that question (a day at most, I think). I understood them, but for some reason the long way around the tree occurred to me first, as always.<br /><br />One good thing about this way (other than that it works, isn't a hack, and looks cleaner) is that JavaScript's other variable that mysteriously shows up in every function with a different value - arguments - doesn't require that so many (two) pieces of code be changed in order to accommodate it.Chris "Jesdisciple"http://www.blogger.com/profile/00251874665739661016noreply@blogger.com0tag:blogger.com,1999:blog-4959426721055574010.post-15358285523195836472010-01-09T03:30:00.000-08:002010-01-09T03:54:18.035-08:00Where is Google's nemesis?I love Google's products. The other day I learned that Chrome had been released for Linux, and then that led me to also discover Wave (granted, it's federated and open-source). I started a project for an extension to Wave on Google Chrome. Then I had to get help building it at Google Groups, which will notify me of replies via Gmail. Now I'm posting about all this on Google's blog service.<br /><br />I know there are non-Google alternatives for some of these. I formerly used Firefox, but now I'm getting attached to Chrome - although WebKit and the lack of Java sometimes get annoying. I tried JavaForge for project hosting but was disappointed. I use non-Google forums frequently (when I'm into forums, anyway). I have email accounts with Opera, Microsoft, and maybe some other sites, but they don't work as well. I have a Wordpress blog for general topics. You might call me a Google fan-boy, but out of what they do they do much of it best.<br /><br />Google was founded by some young entrepreneurs who challenged the big players. The company still has that youthful, small-company air, but now it is the big player. Some people say Google is becoming Microsoft; I think Google is just doing well. But having only one or a few big kids on the block is a bad thing. Who's going to be the upstart that keeps Google on its toes? Is anyone concerned enough to do that right now, or does that youthful air reassure most of us that the big G is harmless? Is there enough creative talent not employed by Google to challenge it? Should we expect the nemesis to emerge from Google itself when things get bad enough? In the meantime, how should we regard Google products? And for all of your answers to the above: Why?Chris "Jesdisciple"http://www.blogger.com/profile/00251874665739661016noreply@blogger.com0tag:blogger.com,1999:blog-4959426721055574010.post-18745143105521252982009-07-12T15:10:00.000-07:002009-07-15T11:54:32.107-07:00Best practices?: Modifying HTMLCollections in IEI just ran into a very weird IE quirk, and I'm wondering what the best practice would be regarding it. (I've only tested in IE7; it might show up in other versions.)<br /><br />Before I had IE installed, I had to modify a form and then find my elements in it to modify them again, and the elements' names were the most convenient way to accomplish the second part. So of course I went for the form.elements collection, and this works fine in Firefox. But not only is this property <a href="http://www.claws-and-paws.com/node/1086">actually the form itself in IE</a>, the developers apparently didn't read this part of the spec:<br /><blockquote><a href="http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-1019015399">http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-1019015399</a><br /><span style="font-weight:bold;">Note:</span> Collections in the HTML DOM are assumed to be live meaning that they are automatically updated when the underlying document is changed.</blockquote>To demonstrate what this means, I threw together a small test page (post continues below):<div class="code"><html><br /> <head><br /> <title>IE DOM modifications</title><br /> <script type='text/javascript' <br /> src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script><br /> <script type="text/javascript"><br /> window.onload = function(){<br /> var form = document.forms.namedItem('test');<br /> var input = document.createElement('input');<br /> input.name = 'foo';<br /> input.type = 'hidden';<br /> input.value = 'bar';<br /> form.appendChild(input);<br /> console.log(form.childNodes[0]);<br />// form[input.name] = input;<br /> console.log(form['foo']);<br /> console.log(form.elements.namedItem('foo'));<br /> };<br /> </script><br /> </head><br /> <body><br /> <form name="test"><br /> <br /> </form><br /> </body><br /></html></div><br />If <span class="icode">form[input.name] = input;</span> (a very ugly hack) is commented, the first call to console.log works but the other two don't. Otherwise, the first two work but the last still doesn't.<br /><br />So here's my question: Is this the best way to workaround this quirk? The idea of form elements being direct properties of the form isn't in the standard, and the standard namedItem function remains broken. I managed to still use namedItem by default, but I really don't like the hack at all.<br /><br />Here's how I retrieved my element:<span class="icode">form.elements.namedItem(name) || form[name]</span>Chris "Jesdisciple"http://www.blogger.com/profile/00251874665739661016noreply@blogger.com0tag:blogger.com,1999:blog-4959426721055574010.post-68723163196707060212009-06-05T10:22:00.000-07:002009-06-05T10:26:21.063-07:00Pandora stopped working, Firefox's fault?Pandora suddenly stopped in the middle of a song today. I was afraid it wouldn't ever work again, which would seem to herald <a href="http://jesdisciple.blogspot.com/2009/05/my-ubuntu-adventure.html">the old problems</a> returning and a new laptop purchase. I refreshed the window, same problem. Then I closed Firefox (had to end it in System Monitor) and Pandora was revived. Yay!Chris "Jesdisciple"http://www.blogger.com/profile/00251874665739661016noreply@blogger.com0tag:blogger.com,1999:blog-4959426721055574010.post-37994017555407816342009-05-30T17:29:00.000-07:002009-05-30T20:54:36.118-07:00My Ubuntu AdventureA long time ago, I encountered the open-source movement as a hobbyist programmer (which I still am, unfortunately) and wanted to try Linux out. I found the Debian site, but the instructions were way over my head so I didn't dare touch it. I'm not sure whether I had my laptop at that time, but I was at least expecting to buy one. Some time later, I met a guy named Nathan and we became fast friends. While he had never used Linux, he knew of Ubuntu and suggested that I request a CD. I did, and what a learning experience it's been!<br /><br />I was completely ignorant of partitions, and I think I resized the one on which Windows XP Professional was pre-installed. Hey, where'd my data go? Over the next year, I had loads of newbie problems and started experiencing really weird bugs:<ul><br /><li>Certain keys would stop working for no apparent reason;[1]</li><br /><li>Firefox started giving JavaScript errors about ordinary whitespace;[2]</li><br /><li>Flash would crash Firefox;[3]</li><br /><li>sound of different types progressively failed until I had almost none left;[4]</li><br /><li>I tried to fix Apache by reinstalling and apt-get choked - hard;[5]</li><br /><li>programs compiled from the same source by gcc became inconsistent;[6]</li><br /><li>diffs contained corrupted data.[7]</li><br /></ul>So now, even though I was fighting to keep coding, I had run into crippling problems with JavaScript, PHP, and C. Even fixing really basic bugs in GNOME which didn't require testing, I was encumbered by diff's corruption. So now I was reduced to typing (also encumbered) and playing games until I could reinstall.<br /><br />After I finally got my /home directory backed up correctly, I used fdisk to repartition because I had been warned of the Live CD's "idiosyncrasies" (although I did have to tweak from the CD because of cylinder boundaries). I installed Jaunty and put the data back where it belonged. That messed GNOME up and broke the sudo command[8], both presumably because the data was generated on Intrepid. So for a while I only ran on the Live CD, which uses RAM as hard drive space; that got old really fast, although Google's storage came in handy.<br /><br />I tried to install Jaunty on another partition, but the Live CD's second option installed it on a very small one that I had intended for something else. I only found out when the JRE required more space than I had. I had to repartition because the second installation made new sections that I didn't want. After figuring out how to work around memory conversion bugs in the Live CD's partition editor, I finally got a clean install.<br /><br />I installed Jaunty again to get a programming partition, and again on the partition I intend for Windows so I can debug my /home data. All three use the same /home partition so I can easily transfer data. My backup has a profile folder named "chris" as does my main install, so I had to extract without ruining the clean profile. I managed that by renaming the real one "_chris" and copying the extracted data to the temporary installation's profile. The user ids were (I guess) the same for both users, so ownership was automatically transferred.<br /><br />The other time that I extracted my data, I only ran into problems after restarting. This time, I tried running Pandora, to lighten up my debugging tedium, and it froze Firefox like the bad old days. So now I know two things about the remaining bugs:<ol><br /><li>They reside in my profile;</li><br /><li>they are not <span style="font-style:italic;">all</span> triggered at startup.</li><br /></ol>This post is intended for two purposes. I would really like to get some help in the comments, as the gurus on Ubuntu Forums seem tired of my queries. I also hope to help the poor Googler who finds my experience all too familiar, and maybe even get whatever bug(s) are behind it fixed.<br /><br /><ol><br /><li><a href="http://ubuntuforums.org/showthread.php?t=1012239">http://ubuntuforums.org/showthread.php?t=1012239</a></li><br /><li><a href="http://forums.mozillazine.org/viewtopic.php?f=25&t=940905">http://forums.mozillazine.org/viewtopic.php?f=25&t=940905</a></li><br /><li>I didn't make a thread for this case, although <a href="http://ubuntuforums.org/showthread.php?t=1012239">this one</a> is related; the above case was later and (I think) cross-browser.</li><br /><li>No thread for this one either, but <a href="http://ubuntuforums.org/showthread.php?t=826043">this</a> is related.</li><br /><li><a href="http://ubuntuforums.org/showthread.php?t=1038787">http://ubuntuforums.org/showthread.php?t=1038787</a></li><br /><li><a href="http://cboard.cprogramming.com/c-programming/114634-exiting-gtkplus-allowing-cli-continue.html">http://cboard.cprogramming.com/c-programming/114634-exiting-gtkplus-allowing-cli-continue.html</a></li><br /><li><a href="http://ubuntuforums.org/showthread.php?t=1126698">http://ubuntuforums.org/showthread.php?t=1126698</a></li><br /></ol>Chris "Jesdisciple"http://www.blogger.com/profile/00251874665739661016noreply@blogger.com0tag:blogger.com,1999:blog-4959426721055574010.post-8683355551042171652008-07-19T09:56:00.000-07:002008-08-02T16:16:00.890-07:00Is JavaScript a type of Java?Nope, JavaScript and Java are completely different languages. Java is a language officially developed by the Java Community Process, but in practice Sun Microsystems is its author and maintainer (because their version is nearly universal). Java is a completely system-independent ('portable') language with syntax similar to C++, implemented for the main operating systems (Windows, GNU/Linux, Mac, Unix) and maybe some others. It's a multipurpose language like C++ but of a slightly higher level (generally less efficient but safer and easier to understand).<br /><br />A language originally named <span style="font-weight:bold;">Mocha</span> was invented by Netscape for Netscape Navigator; they renamed it to <span style="font-weight:bold;">LiveScript</span> until buying (from whom I don't know exactly, but mainly Sun) the right to re-rename it <span style="font-weight:bold;">JavaScript</span>. This was during the "browser wars" between Netscape and Microsoft, I think in the mid-90s. Determined to compete, Microsoft made a work-alike language named <span style="font-weight:bold;">JScript</span> for Internet Explorer. The European Computer Manufacturers Association later standardized the language, officially named <span style="font-weight:bold;">ECMAScript</span> to appease both Netscape and Microsoft. Microsoft ultimately won the browser wars and Netscape's source code, named Mozilla, was released as an open-source project. The current Mozilla Foundation carried it from there and derived its entire set of programs from it, the most notable being Firefox. (<span style="font-weight:bold;">ActionScript</span> is Adobe's ECMAScript implementation for Flash.)<br /><br />ECMAScript is normally known as JavaScript, except where clarity (or politics) is needed, but Microsoft generally uses JScript. Curiously, Opera Software and Apple Computer seem to get away with calling it JavaScript for their browsers Opera and Safari.Chris "Jesdisciple"http://www.blogger.com/profile/00251874665739661016noreply@blogger.com0tag:blogger.com,1999:blog-4959426721055574010.post-60534608423933438972007-12-09T18:52:00.000-08:002008-07-25T15:43:04.793-07:00JavaScript ClosuresClosures are a fairly advanced JavaScript feature which I have only seen discussed in special articles rather than tutorials. (Before anyone asks, I don't know how they got that name.) While I wish someone would write a tutorial that would introduce beginners to the concept, I don't have the time and might not have the expertise, so this is going to follow that trend.<br /><br><br />First, let's have a definition. A closure is the scope of an outer function made accessible to all inner functions. When I look at code which uses closures, it seems like common sense that outer variables would be available from inner functions, but, at the same time, I wouldn't expect the effect sometimes. The effect can manifest similarly to the <span style="font-style: italic;">private</span> declaration of properties in PHP or Java, or the <span style="font-style: italic;">static</span> declaration of PHP as used at the first of a PHP function. Like both of these, a closure allows variables to be accessible only from within a certain context, across repeated calls to a certain set of functions.<br /><br><br /><span style="font-weight: bold;"><a name="without">JavaScript With(out) Closures</a></span><br />If JavaScript is written strictly without using closures, it can get pretty cluttered. Let's say I want to return Function B from Function A, then call Function B to manipulate variables initialized in Function A. (What a mouthful.)<blockquote class="mycode"><html><br /> <head><br /> <title>Titled Document</title><br /> <script type="text/javascript"><br /> function funcA(){<br /> window.varA = 'a variable';<br /> function funcB(){<br /> alert(varA);<br /> }<br /> return funcB;<br /> }<br /> window.onload = function (){<br /> var funcB = funcA();<br /> alert(varA + '... Uh-oh...');<br /> funcB();<br /> }<br /> </script><br /> </head><br /></html></blockquote>(The mention of <span style="font-style: italic;">window</span> is unnecessary, but I want to make it obvious that <span style="font-style: italic;">varA</span> is global.) This works, but, as the call to <span style="font-style: italic;">alert</span> in <span style="font-style: italic;">window.onload</span> shows, it also exposes your variables to overwriting (and hacking, but a hacker can always overwrite your functions anyway). This is a more private way to do it (still without closures):<blockquote class="mycode"><html><br /> <head><br /> <title>Titled Document</title><br /> <script type="text/javascript"><br /> function funcA(){<br /> var result = {<br /> varA: 'a variable';<br /> funcB: function (){<br /> alert(this.varA);<br /> }<br /> return result;<br /> }<br /> window.onload = function (){<br /> var objA = funcA();<br />// alert(varA + '... Uh-oh...');<br /> objA.funcB();<br /> }<br /> </script><br /> </head><br /></html></blockquote>But that's not exactly what we wanted. Because I was restricting myself from using closures, I had to use some other mechanism to do the same thing. I used a custom object, whose member 'funcB' is the focal point of the script. Here's a script that accomplishes the same thing as the previous two, but privately and without the object:<blockquote class="mycode"><html><br /> <head><br /> <title>Titled Document</title><br /> <script type="text/javascript"><br /> function funcA(){<br /> var varA = 'a variable';<br /> function funcB(){<br /> alert(varA);<br /> }<br /> return funcB;<br /> }<br /> window.onload = function (){<br /> var funcB = funcA();<br />// alert(varA + '... Uh-oh...');<br /> funcB();<br /> }<br /> </script><br /> </head><br /></html></blockquote>Uncommenting the call to <span style="font-style: italic;">alert</span> in <span style="font-style: italic;">window.onload</span> causes an error, because <span style="font-style: italic;">varA</span> is only defined within <span style="font-style: italic;">funcA</span>'s scope (= <span style="font-style:italic;">funcB</span>'s closure). Closures allow you to set up code boundaries at your convenience.<br /><br><br /><span style="font-weight: bold;">Final Notes</span><br />Pay attention if you declare several inner functions in one outer, particularly in a loop; the closure is a variable scope (as it exists when the inner function in question is executed) rather than a permanent snapshot of that scope from when the function was declared, and so there is one per call to the outer function, not one per inner function per call to the outer function. So this doesn't work as it would if closures were snapshots specific to inner functions:<blockquote class="mycode">function loopyLooper(){<br /> var demos = [];<br /> for(var i0 = 0; i0 < 10; i0++){<br /> demos[i0] = function(){<br /> alert(i0);<br /> };<br /> }<br /> return demos;<br />}<br />var demos = loopyLooper();<br />for(var demo in demos){<br /> demo();<br />}</blockquote>Here's a correct solution to accomplish this in similar steps (but without using the closure):<blockquote class="mycode">function looper(){<br /> var demos = [];<br /> for(var i0 = 0; i0 < 10; i0++){<br /> demos[i0] = {<br /> func: function(){<br /> alert(this.num);<br /> },<br /> num: i0<br /> };<br /> }<br /> return demos;<br />};<br />var demos = looper();<br />for(var demo in demos){<br /> demo.func();<br />}</blockquote><br />Here's a loop-less function that expects a snapshot instead of the actual scope:<blockquote class="mycode">function loopyLoopless(){<br /> var i = 0;<br /> function result(){<br /> alert(i);//should alert 0<br /> }<br /> i = 1;<br /> return result;<br />}<br><br /><br><br />//user code<br><br />loopyLoopless()();//alerts 1 - The JavaScript interpreter must be broken!</blockquote>And here's a correct version that preserves the user's control over when and in what context the resulting function is executed (while still using a closure):</span><blockquote class="mycode">function loopless(callback){<br /> var i = 0;<br /> callback(function(){<br /> alert(i);//should alert 0<br /> });<br /> i = 1;<br />}<br />//user code<br />loopless(function(result){<br /> result();//alerts 0<br /> });</blockquote><br />As usual, discussion is invited.Chris "Jesdisciple"http://www.blogger.com/profile/00251874665739661016noreply@blogger.com0tag:blogger.com,1999:blog-4959426721055574010.post-36271846312571847142007-12-07T20:30:00.000-08:002008-07-25T15:43:04.795-07:00JavaScript FormatI'm pretty picky about my code, so I want to detail my pet peeves and preferences. I'll assume that everyone knows what objects, arrays, strings, regular expressions (or "regexes"), numbers, functions, classes, methods, procedures, and properties are.<br /><br><br /><span style="font-weight: bold;">Operators</span><br />I put spaces on each side of my operators (=, +, -, *, /, %, ?, :, &&, ||, ==, !=, ===, !==, <, <=, >, >=, ^, ~, &, |, <<, >>, >>>), except for commas, colons used for assignment/labeling, exclamation points, and increment/decrement signs (<span style="font-style: italic;">++</span> and <span style="font-style: italic;">--</span>). Commas and assignment/label colons get no spaces before and one space after.<br /><br><br />Most JavaScript strings are enclosed in single quotes. This makes it easier to write HTML attributes and user-friendly quotes from JavaScript, and causes problems only if apostrophes get involved (in which case double quotes may be used). Alternatively, either type of quote may be escaped with a single backslash, and this is valid for both types within both types ("so \'this\' is valid").<br /><br><br />Each line which would end with a semicolon in most languages will in my JavaScript. This way, code is more likely to be compatible in future versions of JavaScript, readability is enhanced (I believe), and some rare ambiguous situations are clarified for the browser. (I can't think of any of those ambiguous situations offhand, so you'll have to take my word for it and keep your eyes open.)<br /><br><br />Curly brackets are always reason to break the line if there's anything in them; round brackets, square brackets, and ternary operators are only when their contents get too long for the screen. All such containers increase the indentation of any contained lines by one.<br /><br><br /><span style="font-weight: bold;">Iterators</span><br />Most people use alphabetical iterator identifiers (<span style="font-style: italic;">i</span>, <span style="font-style: italic;">j</span>, <span style="font-style: italic;">k</span>, etc.) in their <span style="font-style: italic;">for</span> loops. However, I got very frustrated and embarrassed (in my high school Computer Science class) by a simple bug - a spelling error - and now use numeric identifiers (<span style="font-style: italic;">i0</span>, <span style="font-style: italic;">i1</span>, <span style="font-style: italic;">i2</span>, etc.) to make the difference between my first (<span style="font-style: italic;">i</span> or <span style="font-style: italic;">i0</span>) and second (<span style="font-style: italic;">j</span> or <span style="font-style: italic;">i1</span>) visually obvious. I also have a higher range of identifiers <span style="text-decoration: underline;">that don't cause confusion</span> available; whereas someone else's 19th iterator might be called "zi," mine would simply be "i18."<br /><br><br />When needed, my program-initialization procedure will be directly assigned to window.onload:<blockquote class="mycode"><html><br /> <head><br /> <title>Titled Document</title><br /> <script type="text/javascript"><br /> function main(){<br /> //<br /> }<br /> </script><br /> </head><br /> <body onload="main();"><br /> <br /> </body><br /></html></blockquote><br /><br><br />Here's a demonstration of everything mentioned above:<blockquote class="mycode">var one = 1;<br />var two = one * 2;<br />var three = two + one;<br />var yup = true;<br />if(!yup || (three <= two)){<br /> alert('This can't be happening!');<br />}<br />for(var i0 = 0; i0 < 10; i0++){<br /> //<br />}<br />var object = {<br /> numbers: [ //This array really isn't long enough to break, but<br /> one, //I want to show what I mean.<br /> two, //(This applies to argument lists, too.)<br /> three<br /> ],<br /> do: function(){<br /> alert(function dummy(){<br /> //This is just a dummy.<br /> });//The round brackets don't break, but the curly ones do.<br /> }<br />}<br />var something = yup ? object : null;<br />switch(something){<br /> case object:<br /> //<br /> break;<br /> case null:<br /> //<br /> break;<br /> default:<br /> //<br />}<br />window.onload = function(){<br /> //Do something.<br />};</blockquote>Chris "Jesdisciple"http://www.blogger.com/profile/00251874665739661016noreply@blogger.com0tag:blogger.com,1999:blog-4959426721055574010.post-29926473367432693042007-12-07T18:51:00.000-08:002008-07-26T22:10:03.011-07:00JavaScript GlossaryThis post is currently under construction; please post any comments below.<br /><br><br /><a name="argument" style="font-weight: bold;">Argument</a> - An <a href="http://en.wikipedia.org/wiki/Dependent_and_independent_variables" target="_blank" class="postlink">independent</a> <a href="http://en.wikipedia.org/wiki/Variable#Computer_programming" target="_blank" class="postlink">variable</a> declared in a <a href="#function">function</a>'s header and defined by the function's caller. An argument (or "arg") is only visible within the declared function's <a href="http://en.wikipedia.org/wiki/Scope_(programming)" target="_blank" class="postlink">scope</a>. If an argument uses the same identifier as another variable in a scope which contains the function, the argument hides the other variable.<div class="code">function getArgument(arg){<br /> alert('Your argument is ' + arg + '.');<br />}<br />getArgument('weak');// alerts "Your argument is weak."</div><br /><br><br /><a name="boolean" style="font-weight: bold;">Boolean</a> - The binary (either true or false) <a href="#datum_type">datum type</a> named after <a href="http://en.wikipedia.org/wiki/George_Boole" target="_blank" class="postlink">George Boole</a>. Boolean values are immutable.<br /><br><br /><a name="class" style="font-weight: bold;">Class</a> - A contrived notion in JavaScript which is nonetheless frequently used for transitioning <a href="http://en.wikipedia.org/wiki/Class-based" target="_blank" class="postlink">class-based</a> programmers into the <a href="http://en.wikipedia.org/wiki/Prototype-based_programming" target="_blank" class="postlink">prototype-based</a> language. Classes are simulated in JavaScript via <a href="#prototype">prototypes</a> of <a href="#constructor">constructors</a>.<br /><br><br /><a name="constructor" style="font-weight: bold;">Constructor</a> - A function called with <span class="icode">new</span>. By convention, constructor names should always be in <a href="http://en.wikipedia.org/wiki/CamelCase" target="_blank">UpperCamelCase</a>. In the body of a constructor, the pseudo-variable <span class="icode">this</span> refers to each individual instance of that constructor that will ever exist.<div class="code">function Foo(){<br /> alert(this.constructor.name);<br />}<br />var foo = new Foo();//alerts "Foo"<br />Foo();//alerts "undefined" because this.constructor (i.e. window.constructor) doesn't exist in this case</div><br /><br><br /><a name="clone" style="font-weight: bold;">Clone</a> - An <a href="#object">object</a> which inherits every current property of its <a href="#constructor">constructor</a>'s <a href="#prototype">prototype</a>.<br /><br><br /><a name="datum_type" style="font-weight: bold;">Datum Type</a> - One of at least 5 types of values: <a href="#boolean">boolean</a>; <a href="#function">function</a>; <a href="#number">number</a>; <a href="#object">object</a>; and <a href="#string">string</a>. The type of the literal <span class="icode">undefined</span> value is <span class="icode">"undefined"</span> but I don't consider that a real type. A value's type is returned by <span class="icode">typeof value</span>. See <a href="http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Operators:Special_Operators:typeof_Operator" target="_blank" class="postlink">http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Operators:Special_Operators:typeof_Operator</a> and <a href="http://en.wikipedia.org/wiki/Data_type" target="_blank" class="postlink">http://en.wikipedia.org/wiki/Data_type</a>.<br /><br><br /><a name="event" style="font-weight: bold;">Event</a> - An <a href="#object">object</a> which represents a change in the browser's state; is passed as an argument to any <a href="#event-handler">event-handler</a> as called by the browser.<br /><br><br /><a name="event-handler" style="font-weight: bold;">Event-handler</a> - A <a href="#function">function</a> called by the browser when a specific type of <a href="#event">event</a> occurs. Event-handlers can also be explicitly called by a script, but this is very uncommon.<div class="code">window.onload = function (){<br /> alert('Do something useful!');<br />};</div><br /><br><br /><a name="function" style="font-weight: bold;">Function</a> - The <a href="#datum_type">datum type</a> which represents sets of instructions to be executed by the browser at the prompting of either scripting or, in the case of <a href="#event-handlers">event-handlers</a>, the browser itself. Being objects, JavaScript functions are <a href="http://en.wikipedia.org/wiki/First-class_function">first-class</a>. Functions are mutable.<br /><br><br /><a name="global" style="font-weight: bold;">Global</a> - Owned by <span class="icode">window</span>. Global variables are accessible from every <a href="http://en.wikipedia.org/wiki/Scope_(programming)" target="_blank" class="postlink">scope</a>.<br /><br><br /><a name="local" style="font-weight: bold;">Local</a> - Declared independently and therefore owned by no particular <a href="#object">object</a>.<br /><br><br /><a name="method" style="font-weight: bold;">Method</a> - A <a href="#function">function</a> which happens to be the property of an object. Methods, like all other <a href="#property">properties</a>, should always have <a href="http://en.wikipedia.org/wiki/CamelCase" target="_blank" class="postlink">lowerCamelCase</a> names (again, by widely accepted convention). In a method, <span class="icode">this</span> refers to the object in whose context the method was called.<br /><br><br /><a name="number" style="font-weight: bold;">Number</a> - The signed, floating-point, numeric <a href="#datum_type">datum type</a>. Numbers may be specified as either decimal, hexadecimal, or octal values. Numbers are immutable.<br /><br><br /><a name="object" style="font-weight: bold;">Object</a> - The catch-all <a href="#datum_type">datum type</a>. If a value is defined but doesn't fit in the boolean, function, number, or string groups (the members of which also being objects), then it's called an object. Object values are mutable.<br /><br><br /><a name="procedure" style="font-weight: bold;">Procedure</a> - A <a href="#method">method</a> of no particular <a href="#object">object</a> (or of <span class="icode">window</span>). A function which is called as a property of no particular object is a <a href="#local">local</a> procedure; a function explicitly assigned to a property of <span class="icode">window</span> is a <a href="#global">global</a> procedure. Like methods', procedures' names should be in <a href="http://en.wikipedia.org/wiki/CamelCase" target="_blank" class="postlink">lowerCamelCase</a>.<br /><br><br /><a name="prototype" style="font-weight: bold;">Prototype</a> - An <a href="#object">object</a> whose properties are inherited by one or more <a href="#clone">clones</a>. At its core, JavaScript is <a href="http://en.wikipedia.org/wiki/Prototype-based_programming" target="_blank" class="postlink">prototype-based</a>.<br /><br><br /><a name="string" style="font-weight: bold;">String</a> - The <a href="#datum_type">datum type</a> of character sequences. Any length of non-newline characters delimited by two single- or double-quotes ( ' or " ) is a string. If a newline is interposed between the quotes, an "Unterminated string constant" error is issued. String values are immutable.Chris "Jesdisciple"http://www.blogger.com/profile/00251874665739661016noreply@blogger.com0tag:blogger.com,1999:blog-4959426721055574010.post-30058628527957303282007-09-14T22:37:00.000-07:002008-05-23T22:28:11.515-07:00HTML Isn't PHP's Only Application.I recently completed an online certification (probably worthless in industry) in PHP; during that course, I accidentally found <a href="http://www.javascriptkit.com/javatutors/externalphp.shtml">this article</a> while searching for something else on the site. As a JavaScript programmer, I found this very intriguing. As I was experimenting with this new twist on the two languages, I found that this also works:<blockquote class="mycode"><script type="text/javascript"><br /><?php<br /> echo " alert('This is dynamically coded JavaScript!');";<br />?><br /></script></blockquote>It works because <?php and ?> aren't HTML code; they're signals to the PHP engine telling it to start and stop parsing PHP code, respectively.<br /><br />Dynamic CSS is another application of PHP. If, for example, you have two (or more) CSS values which are related, you can figure both from one PHP variable:<blockquote class="mycode"><?php<br /> $exampleVar = 5;<br />?><br />p{<br /> width: <?php echo $exampleVar; ?>in;<br /> height: <?php echo $exampleVar * 2; ?>in;<br />}</blockquote>The above code makes all P elements 10 inches high and 5 inches wide. To apply another set of dimensions of the same proportion (height = width * 2), just change $exampleVar. Of course, the variable could be dynamic as well, but I didn't feel like putting that much into an example.<br /><br />In my CSS and JS files with PHP, I use this algorithm to either link (client-side) or include (server-side) the script:<blockquote class="mycode"><?php<br /> if(isset($method)) $included = $method == 'include';<br /> if($included) echo "<style type="\"text/css\"">\n";<br />?><br /><br />//insert code here<br /><br /><?php<br /> if($included) echo "</style>\n";<br />?></blockquote>Note that, to include the file, you must specify "$method = 'include'" first. You could use "$included = true" instead, but the above way leaves the script open to other operations for other values of $method.<br /><br />Any other client-side code could probably benefit from PHP, too, although I haven't tried it. I wonder what enhancements, if any, would be possible in XML (and its many branches), for instance. If the browser doesn't know what language to interpret the file in (i.e., due to <b><a href="http://www.blogger.com/script.xml.php" <span style="color: rgb(255, 255, 255);">mce_href="script.xml.php"</span>>an ambiguous link</a></b>), some problems might arise, although I think the browser should recognize the markup in this case.<br /><br /><span style="font-style: italic;">NOTE (early 2008): I recently noticed that PHP has a solution to this problem. Send a header like this one (for the above example) and the browser will interpret the file correctly.</span> (Apache HTTPD also has a solution in its [httpd.conf / apache.conf] and directory-specific .htaccess files.)<br /><blockquote><?php<br /> header('Content-Type: text/xml');<br />?></blockquote><span style="font-style: italic;">See <a href="http://en.wikipedia.org/wiki/Internet_media_type">Wikipedia: Internet media type</a>.</span><br /><br />As you surely noticed, the above filename ends in .xml.php. I think it's a good idea to use the conventional file extension (i.e., .js, .css) before the .php, if only for your own recollection when you're trying to find that pesky file among all the other .php extensions. Ideally, this kind of compound extension would be recognized by IDEs, etc., but I won't hold my breath.</span>Chris "Jesdisciple"http://www.blogger.com/profile/00251874665739661016noreply@blogger.com0