<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="iBlog 1.4.6" -->

<rss xmlns:itunes="http://www.itunes.com/DTDs/Podcast-1.0.dtd" version="2.0">
  <channel>
    <title><![CDATA[Chris Page’s Weblog of Doom]]></title>
    <link>http://homepage.mac.com/chrispage/iblog</link>
    <description><![CDATA[Read my blog or suffer the consequences.]]></description>
	<docs>http://blogs.law.harvard.edu/tech/rss</docs>
	<language>en</language>
    <webMaster>weblog-of-doom@chris-page.org</webMaster>
    <copyright>© 1995-2006 Chris Page</copyright>
    <lastBuildDate>Sun, 12 Aug 2007 18:47:23 -0700</lastBuildDate>
    <pubDate>Sun, 12 Aug 2007 18:48:18 -0700</pubDate>
    <generator>iBlog 1.4.6</generator>
    
	<!-- iTunes tags in channel -->
	
	<itunes:author>Chris Page</itunes:author>
	<itunes:subtitle>Chris Page’s Weblog of Doom</itunes:subtitle>
	<itunes:summary>Read my blog or suffer the consequences.</itunes:summary>
	<itunes:owner>
		<itunes:name>Chris Page</itunes:name>
		<itunes:email>weblog-of-doom@chris-page.org</itunes:email>
	</itunes:owner>
	<itunes:link rel="image" type="image/png" href="http://homepage.mac.com/chrispage/iblog/podcastImage.png">Chris Page’s Weblog of Doom</itunes:link>
	<category>Arts &amp; Entertainment</category>
	<itunes:category text="Arts &amp; Entertainment"> <itunes:category text="Architecture"/> </itunes:category>
	
	<!-- end of iTunes tags in channel -->
	
    <item>
      <title><![CDATA[Andy Ihnatko is one funny dude—and not Fake Steve ]]></title>
      <link>http://homepage.mac.com/chrispage/iblog/C2139199310/E20070812184703/index.html</link>
      <description><![CDATA[ <br /> <div><font face="Optima-Regular">I actually find it a little tiring to read a <a href="http://www.macworld.com/2007/07/opinion/fakesteve/index.php">whole article</a> of his because of the energy burned up being amused.</font></div> ]]></description>
      <pubDate>Sun, 12 Aug 2007 18:47:03 -0700</pubDate>
	  <guid>http://homepage.mac.com/chrispage/iblog/C2139199310/E20070812184703/index.html</guid>
	  
    </item>

    <item>
      <title><![CDATA[Donuts filled with gelatinous goop instead of jelly: Evil or just bad taste? ]]></title>
      <link>http://homepage.mac.com/chrispage/iblog/C1458150064/E20070408234631/index.html</link>
      <description><![CDATA[ <br /> <div><font face="Optima-Regular">Discuss.</font></div> ]]></description>
      <pubDate>Sun, 08 Apr 2007 23:46:31 -0700</pubDate>
	  <guid>http://homepage.mac.com/chrispage/iblog/C1458150064/E20070408234631/index.html</guid>
	  
    </item>

    <item>
      <title><![CDATA[“Brain the size of a planet, and they want me to run software from the 1950’s.” ]]></title>
      <link>http://homepage.mac.com/chrispage/iblog/C649209254/E20061224040342/index.html</link>
      <description><![CDATA[<div><font face="Optima-Italic"><i>Marvin the Paranoid Android would probably get all sulky if he were a web server.</i></font></div>  <br /> <div><font face="Optima-Regular">Today, while attempting to create an account on a website, I got this not-so-helpful reply:</font><br /><br /><font face="Optima-Regular">“The screen name you requested is too short, too long, or contains illegal characters.</font><font face="LucidaGrande"> </font><font face="Optima-Regular">Screen names must be between 2 and 24 characters long and can contain only letters and numbers (no spaces).”</font><br /><br /><font face="Optima-Regular">Well, don’t keep me guessing, which is it? Too short? Too long? Does it contain spaces or accents that are known to make computers explode in a shower of sparks while repeating “does not compute” in a voice suspiciously similar to that of Lwaxana Troi?</font><br /><br /><font face="Optima-Regular">Clearly, some human wrote code to test for each of these failures individually, so why didn’t they report which specific test (or tests) failed, instead of requiring me to waste time performing the same tests so I can figure out how to change my desired screen name to fit in its puny electronic brain?</font><br /><br /><font face="Optima-Regular">Of course, the larger issue is that these limitations are almost entirely unnecessary. Sure, some finite restrictions on the length make sense; however, twenty four characters is shorter than many real-world names, and both computers and humans are entirely capable of handling multiple words, accents and other letters and symbols from the world of written communication. Not since perhaps the 1970’s have these limitations been widely required by computing systems. These sorts of restrictions are artificial and should be relegated to history before extraterrestrials finally do show up to visit and we have to embarrassingly explain why we need them to spell their names with fewer than twenty four letters from the Roman alphabet.</font><br /><br /><font face="Optima-Regular">I still occasionally come across forms both electronic and paper that force me to truncate my first name, Christopher, to an annoying ten-character “Christophe”. I guess </font><font face="Optima-Italic"><i>Christopher</i></font><font face="Optima-Regular"> is one of those whacky names from the 1960’s that people just don’t use much.</font></div> ]]></description>
      <pubDate>Sun, 24 Dec 2006 04:03:42 -0800</pubDate>
	  <guid>http://homepage.mac.com/chrispage/iblog/C649209254/E20061224040342/index.html</guid>
	  
    </item>

    <item>
      <title><![CDATA[Effective Dylan: 50 Specific Ways Dylan is Easier to Use Than C++ ]]></title>
      <link>http://homepage.mac.com/chrispage/iblog/C42511381/E1695292303/index.html</link>
      <description><![CDATA[<div><font face="Optima-Italic"><i>A point-by-point comparison between Dylan and the fifty items described in Scott Meyers' Effective C++.</i></font></div>  <br /> <div><font face="Optima-Regular">I’ve been meaning to do this for a while. Here I go. The following is a brief† explanation of how Dylan compares against all fifty items listed in Scott Meyers’ </font><font face="Optima-Italic"><i><a href="http://www.amazon.com/exec/obidos/ASIN/0201924889/">Effective C++: 50 Specific Ways to Improve Your Programs and Designs</a></i></font><font face="Optima-Regular">††. Much as I like this book and find it useful for programming in C++, the fact is that a lot of what’s in it (and other books on C++) is about the unnecessarily hard parts of C++. Dylan generally provides a simpler and more productive (and enjoyable!) approach to programming.</font><br /><br /><font face="Optima-Regular">†I wrote that before writing the bulk of this. Since there are, after all, </font><font face="Optima-Italic"><i>fifty</i></font><font face="Optima-Regular"> points, the overall result isn’t very short. However, my response to each item is relatively brief and may leave out a number of details that would be worth expanding on in the future.</font><br /><br /><font face="Optima-Regular">††Note that I used the first edition of Scott’s book, although that link above points at the second edition on Amazon. At some point I’ll go through the second edition and update my comments if necessary.</font><br /><br /><br /><font face="Optima-Bold"><b>Shifting from C to C++</b></font><br /><br /><font face="Optima-Regular">This section is very specific to C vs. C++, so there isn’t a direct comparison in Dylan, but I’ll add some comments anyway.</font><br /><br /><font face="Optima-Regular">1. </font><font face="Optima-Italic"><i>Use const and inline instead of #define.</i></font><font face="Optima-Regular"> Dylan has no preprocessor or #define. It has constants and inline functions.</font><br /><br /><font face="Optima-Regular">2. </font><font face="Optima-Italic"><i>Prefer iostream.h to stdio.h.</i></font><font face="Optima-Regular"> Dylan has stream-based I/O libraries.</font><br /><br /><font face="Optima-Regular">3. </font><font face="Optima-Italic"><i>Use new and delete instead of malloc and free.</i></font><font face="Optima-Regular"> Dylan has automatic memory management. You do not need to call functions to allocate and deallocate memory.</font><br /><br /><font face="Optima-Regular">4. </font><font face="Optima-Italic"><i>Prefer C++-style comments.</i></font><font face="Optima-Regular"> Dylan supports both styles of C++ comments (/* */ and //), and common Dylan programming style agrees with Meyers.</font><br /><br /><br /><font face="Optima-Bold"><b>Memory Management</b></font><br /><br /><font face="Optima-Regular">Most of the items in this section are non-issues in Dylan, which has automatic memory management. There are no new and delete to use incorrectly.</font><br /><br /><font face="Optima-Regular">5. </font><font face="Optima-Italic"><i>Use the same form in corresponding calls to new and delete.</i></font><font face="Optima-Regular"> An impossible error to make in Dylan. If you create a collection object, every object in it will be automatically deallocated as appropriate when the collection is deallocated.</font><br /><br /><font face="Optima-Regular">6. </font><font face="Optima-Italic"><i>Call delete on pointer members in destructors.</i></font><font face="Optima-Regular"> Another detail that’s impossible to overlook in Dylan. All objects are properly deallocated when no longer referenced.</font><br /><br /><font face="Optima-Regular">7. </font><font face="Optima-Italic"><i>Check the return value of new.</i></font><font face="Optima-Regular"> Dylan’s equivalent to new, “make,” signals an exception if object allocation or initialization fails. It is not possible to unintentionally overlook a failure.</font><br /><br /><font face="Optima-Regular">8. </font><font face="Optima-Italic"><i>Adhere to convention when writing new.</i></font><font face="Optima-Regular"> There is no new.</font><br /><br /><font face="Optima-Regular">9. </font><font face="Optima-Italic"><i>Avoid hiding the global new. </i></font><font face="Optima-Regular">There is no global new.</font><br /><br /><font face="Optima-Regular">10. </font><font face="Optima-Italic"><i>Write delete if you write new.</i></font><font face="Optima-Regular"> There is no…rule number six.</font><br /><br /><br /><font face="Optima-Bold"><b>Constructors, Destructors, and Assignment Operators</b></font><br /><br /><font face="Optima-Regular">These issues are dramatically simpler in Dylan. Automatic memory management eliminates the need to define constructors and destructors when the only resource being managed is memory. Initialization is much simpler in Dylan and in most cases can be defined in the class definition without a separate initialization function. There is no assignment operator function, and, in contrast to C++, Dylan doesn’t copy objects implicitly, and explicit copying is rare.</font><br /><br /><font face="Optima-Regular">11. </font><font face="Optima-Italic"><i>Define a copy constructor and an assignment operator for classes with dynamically allocated memory</i></font><font face="Optima-Regular">. Although you can define the equivalent of copy constructors when desired in Dylan, automatic memory management makes it unnecessary to worry about writing copying code merely to properly manage memory. There is no copying assignment operator in Dylan, and no implicit copying of objects, so it is rare that you need to write copying code; you do not need to do so simply to satisfy language semantics as in C++, you only need to do so when you wish to support explicit copying.</font><br /><br /><font face="Optima-Regular">12. </font><font face="Optima-Italic"><i>Prefer initialization to assignment in constructors.</i></font><font face="Optima-Regular"> This actually applies to Dylan, although there’s less of a chance a Dylan programmer will make a mistake here. For most cases, object initialization can be expressed just once, in the class definition, unlike C++ initialization clauses, which cannot be used in as many cases and which have to be diligently written for every constructor. Dylan only requires an explicit initialization function for special cases, e.g., when multiple initial values have interdependencies.</font><br /><br /><font face="Optima-Regular">13. </font><font face="Optima-Italic"><i>List members in an initialization list in the order in which they are declared.</i></font><font face="Optima-Regular"> A non-issue in Dylan, where initial values are given in the definition of each member (called “slots” in Dylan), so there is no way to get the order wrong.</font><br /><br /><font face="Optima-Regular">14. </font><font face="Optima-Italic"><i>Make destructors virtual in base classes.</i></font><font face="Optima-Regular"> A non-issue in Dylan, where all functions are implicitly “virtual” (besides, Dylan does not have destructors in the C++ sense.) Note that this does </font><font face="Optima-Italic"><i>not</i></font><font face="Optima-Regular"> mean all function calls incur dispatching overhead, a cost many C++ programmers are very conscious of. If a given call site doesn’t require dynamic dispatch, it automatically becomes a simple function call, just as with non-virtual C++ member functions, and may even be inlined as appropriate. There is no need (or means) to explicitly declare “virtual” and “non-virtual” functions, and no class definition changes are ever necessary if program requirements later change.</font><br /><br /><font face="Optima-Regular">15. </font><font face="Optima-Italic"><i>Have operator= return a reference to *this.</i></font><font face="Optima-Regular"> There is no assignment operator in Dylan.</font><br /><br /><font face="Optima-Regular">16. </font><font face="Optima-Italic"><i>Assign to all data members in operator=.</i></font><font face="Optima-Regular"> There is still no assignment operator in Dylan.</font><br /><br /><font face="Optima-Regular">17. </font><font face="Optima-Italic"><i>Check for assignment to self in operator=.</i></font><font face="Optima-Regular"> Well, there was one, but the cat’s eaten it.</font><br /><br /><font face="Optima-Regular">(Someone asked me for further clarification: There is an “assignment operator” in Dylan, of course. It looks just like Pascal’s “:=”. However, it is not a function. It is not equivalent to C++’s operator=, which performs copying, and there is no need to implement one for your classes as in C++ simply to avoid problems with C++’s pervasive implicit copying.)</font><br /><br /><br /><font face="Optima-Bold"><b>Classes and Functions: Design and Declaration</b></font><br /><br /><font face="Optima-Regular">Meyers’ has some good things to say about class and function design that, broadly speaking, apply as much to Dylan as they do to any other language. However, a lot of these items are rendered simpler—or in some cases, trivial—to deal with in Dylan.</font><br /><br /><font face="Optima-Regular">18. </font><font face="Optima-Italic"><i>Strive for class interfaces that are complete and minimal.</i></font><font face="Optima-Regular"> Okay, Scott, will do. In fact, in Dylan, class definitions are usually much simpler than in C++, only including definitions of slots (“data members”) and (implicitly) their accessors—an approach <a href="http://www.cuj.com/documents/s=8042/cuj0002meyers/">Scott recommends for C++</a>, but which is made more difficult to adhere to than in Dylan because of the limitations of non-member functions.</font><br /><br /><font face="Optima-Regular">19. </font><font face="Optima-Italic"><i>Differentiate among member functions, global functions, and friend functions.</i></font><font face="Optima-Regular"> Dylan has a simpler, more orthogonal programming model in which there is essentially only one kind of function (called a “generic function”), which is polymorphic, similar to a C++ virtual member function. Generic functions do not “belong” to classes, and there is no real distinction between “member” and “non-member”, or “friend” functions, making it simpler to evolve programs with fewer and more localized source changes. You use explicit modules (aka “namespaces”) to control access and encapsulation instead of implicit class namespaces and public, private, protected, and friend declarations.</font><br /><br /><font face="Optima-Regular">20. </font><font face="Optima-Italic"><i>Avoid data members in the public interface.</i></font><font face="Optima-Regular"> In Dylan, accessor functions are automatically defined for all slots. In fact, there is no way to explicitly access a slot “directly” as in C++. All slot access is via accessor functions (calls to which are often optimized away in practice). In C++, you have to explicitly write your own accessors, complicating the code and increasing the likelihood that someone will avoid that work and make a data member public when they shouldn’t, and thereby make the code harder to maintain and evolve.</font><br /><br /><font face="Optima-Regular">21. </font><font face="Optima-Italic"><i>Use const whenever possible.</i></font><font face="Optima-Regular"> Dylan doesn’t have const, which isn’t as clearly necessary as in C++. One reason for this is that, just as functions can accept multiple arguments, in Dylan they can also return multiple values, so you never need to design functions that take “output” pointer/reference arguments, and so there’s less need to differentiate them from “input” arguments. Dylan functions also tend to be functional rather than mutating (ie., they are implicitly const). Although Dylan explicitly supports imperative programming, most standard library functions do not alter their arguments, and so const-like declarations would often be redundant. (This is not to say there would be no value in having something like </font><font face="Optima-Italic"><i>const</i></font><font face="Optima-Regular"> in Dylan, but it isn’t as much of a clear win as in C++.)</font><br /><br /><font face="Optima-Regular">22. </font><font face="Optima-Italic"><i>Pass and return objects by reference instead of by value.</i></font><font face="Optima-Regular"> Dylan always uses reference semantics. There is no direct way to pass by value, although you can explicitly copy an object then pass the copy along.</font><br /><br /><font face="Optima-Regular">23. </font><font face="Optima-Italic"><i>Don’t try to return a reference when you must return an object.</i></font><font face="Optima-Regular"> See #22. This simply isn’t an issue in Dylan.</font><br /><br /><font face="Optima-Regular">24. </font><font face="Optima-Italic"><i>Choose carefully between function overloading and parameter defaulting.</i></font><font face="Optima-Regular"> This applies only indirectly to Dylan. First, it’s important to note that Dylan does not have function overloading in the same sense as C++. Second, Meyers recommends overloading when there is no reasonable default value for an argument, but in Dylan it is always possible to define a default value (using type-unions, which I won’t go into here), and furthermore, it is possible to tell whether an optional argument was passed to a Dylan function, obviating the need for a default value if avoiding one is desired.</font><br /><br /><font face="Optima-Regular">25. </font><font face="Optima-Italic"><i>Avoid overloading on a pointer and a numerical type.</i></font><font face="Optima-Regular"> In Dylan there are no raw pointers and therefore no null pointer, but more to the point, Dylan is more type-safe than C++ and there is no way to confuse a zero with a null pointer, or in fact any number with any value that is not a number. In stark contrast to C++, Dylan’s false, zero, and null character ('\0') are of distinct types, and there is no implicit casting between them as in C++.</font><br /><br /><font face="Optima-Regular">26. </font><font face="Optima-Italic"><i>Guard against potential ambiguity.</i></font><font face="Optima-Regular"> There is no implicit casting and no ambiguity between construction and conversion; you have to explicitly invoke the desired function. Generic functions do not “belong” to classes in the same sense that C++ member functions belong to their classes, and so the potential ambiguity between two inherited member functions with the same name doesn’t have a direct analogue in Dylan. The closest match is name collisions in modules (again, aka “namespaces”); similar to C++, you do need to resolve any collisions that occur during importing, by excluding or renaming one or more of the offending names.</font><br /><br /><font face="Optima-Regular">27. </font><font face="Optima-Italic"><i>Explicitly disallow use of implicitly generated member functions you don’t want.</i></font><font face="Optima-Regular"> The example Meyers uses is the default assignment operator. Dylan has no assignment operator, so that specifically is a non-issue. More generally, Dylan doesn’t automatically define any functions on your behalf that you would need to suppress (any undesirable behaviors are up to you to implement yourself).</font><br /><br /><font face="Optima-Regular">28. </font><font face="Optima-Italic"><i>Use structs to partition the global namespace.</i></font><font face="Optima-Regular"> Here Meyers is suggesting a short-term workaround for the lack of namespaces in C++. Now that modern C++ compilers support namespaces, this is unnecessary. As mentioned above, Dylan has namespaces (called “modules”).</font><br /><br /><br /><font face="Optima-Bold"><b>Classes and Functions: Implementation</b></font><br /><br /><font face="Optima-Regular">Some of these points discuss design issues of a general nature that tend to apply across languages, but others highlight where C++ is more complex than one might desire, where Dylan provides a simpler and more enjoyable programming experience in contrast. In particular, Dylan has no header files and instead relies upon whole-program analysis, where the compiler can see all the source code for a program or library and isn’t constrained by a monolithic, compilation-order-dependent mechanism like C++’s translation unit.</font><br /><br /><font face="Optima-Regular">29. </font><font face="Optima-Italic"><i>Avoid returning “handles” to internal data from const member functions.</i></font><font face="Optima-Regular"> As a general point, this applies to Dylan, and I’d modify this to the more broad, “avoid exposing implementation information through interfaces.” Note, however, that Dylan has no raw pointers, and that all slots are implicitly accessed via functions, so less raw data is exposed by default.</font><br /><br /><font face="Optima-Regular">30. </font><font face="Optima-Italic"><i>Avoid member functions that return pointers or references to members less accessible than themselves.</i></font><font face="Optima-Regular"> This applies to Dylan in the same general way that #29 does, though, again, there is no way to return a raw pointer or reference to a member, making this (at least slightly) less of an issue.</font><br /><br /><font face="Optima-Regular">31. </font><font face="Optima-Italic"><i>Never return a reference to a local object or a dereferenced pointer initialized by new within the function.</i></font><font face="Optima-Regular"> You can blatantly ignore this in Dylan, where it’s perfectly safe to return any object, since you’re always using heap semantics (ie., there is no way to return a reference a stack object). Note that I said heap </font><font face="Optima-Italic"><i>semantics</i></font><font face="Optima-Regular">. Dylan programs are written as though objects are always allocated on the heap, but objects may be allocated on the stack if there are no external references to them. Dylan treats the location of an object as an implementation detail, and allocating on the stack is an optimization. Automatic memory management eliminates the problems seen in C++ due to incorrect references or omitted deletion.</font><br /><br /><font face="Optima-Regular">32. </font><font face="Optima-Italic"><i>Use enums for integral class constants.</i></font><font face="Optima-Regular"> The opposite is true in Dylan: Go ahead and use constants, that’s what they’re for. The Dylan compilation model doesn’t use headers. Instead, the compiler simply looks at the definition of a constant regardless of where it is in the sources to find its value. So, Dylan doesn’t have the same scoping and compilation order problems that C++ does.</font><br /><br /><font face="Optima-Regular">33. </font><font face="Optima-Italic"><i>Use inlining judiciously.</i></font><font face="Optima-Regular"> [Curly voice] Why, soitenly. In fact, Dylan compilers make judicious use of inlining on your behalf in many cases, and, again, Dylan doesn’t use headers, so you don’t have to place function bodies in headers to get them inlined. The compiler can inline any function in your program as appropriate, making inlining easier to manage with fewer changes to source code. Dylan compilers are also expected to perform certain kinds of inlining and partial inlining that you might not expect of a C++ compiler (or that might not be possible due to the language semantics and compilation model).</font><br /><br /><font face="Optima-Regular">34. </font><font face="Optima-Italic"><i>Minimize compilation dependencies between files.</i></font><font face="Optima-Regular"> Of course, reducing dependencies is a good thing, but again, since there are no headers, the task is made much simpler in Dylan. No implementation details are explicitly exposed in header files. Only those dependencies that actually occur in your programs need cause recompiles, and only the affected functions need to be processed, rather than recompiling everything in a translation unit that directly or indirectly may depend upon a header file, as in C++.</font><br /><br /><br /><font face="Optima-Bold"><b>Inheritance and Object-Oriented Design</b></font><br /><br /><font face="Optima-Regular">Some of these items are general and apply to Dylan, but others are, again, non-issues in Dylan, or in fact the opposite of common Dylan practice. C++ imposes some design constraints that Dylan programs are not subject to.</font><br /><br /><font face="Optima-Regular">35. </font><font face="Optima-Italic"><i>Make sure public inheritance models “isa.”</i></font><font face="Optima-Regular"> Dylan doesn’t have private inheritance, so you can ignore some of what Meyers has to say here, but the general point about inheritance modeling “isa” still basically applies to Dylan (and in fact, to all OO languages).</font><br /><br /><font face="Optima-Regular">36. </font><font face="Optima-Italic"><i>Differentiate between inheritance of interface and inheritance of implementation.</i></font><font face="Optima-Regular"> A good idea in Dylan, too. Meyers goes on at length on this topic, and the summary is that Dylan is a bit simpler here because there are no non-virtual member functions, nor pure virtual member functions. To define an abstract class in Dylan, you do so explicitly with the adjective “abstract” in the class definition; there is no need to define a pure virtual member function merely to implicitly make a class uninstantiable.</font><br /><br /><font face="Optima-Regular">37. </font><font face="Optima-Italic"><i>Never redefine an inherited nonvirtual function.</i></font><font face="Optima-Regular"> An impossibility in Dylan, as all functions use “virtual” semantics. This makes it simpler to modify and maintain Dylan programs without breaking client code.</font><br /><br /><font face="Optima-Regular">38. </font><font face="Optima-Italic"><i>Never redefine an inherited default parameter value.</i></font><font face="Optima-Regular"> In Dylan it is perfectly fine to do so, whereas C++ semantics make this problematic. Subclasses can impose further restrictions and therefore it is desirable to alter default initialization values, and Dylan semantics make this trivial to do.</font><br /><br /><font face="Optima-Regular">39. </font><font face="Optima-Italic"><i>Avoid casts down the inheritance hierarchy.</i></font><font face="Optima-Regular"> Because it is a dynamic language, Dylan does not have or need up- or down-casting. Furthermore, it does not have raw pointers or non-virtual functions, eliminating most of the issues raised by Meyers here. As he suggests, though, you should avoid relying upon the exact type of an object and instead provide one or more polymorphic functions that provide the desired tests for object attributes (in this case, the example is testing an object’s class, but this rule can be applied more generally).</font><br /><br /><font face="Optima-Regular">40. </font><font face="Optima-Italic"><i>Model “has-a” or “is-implemented-in-terms-of” through layering.</i></font><font face="Optima-Regular"> Generally applicable to Dylan, too.</font><br /><br /><font face="Optima-Regular">41. </font><font face="Optima-Italic"><i>Use private inheritance judiciously.</i></font><font face="Optima-Regular"> There is no private inheritance in Dylan, so this is a non-issue. More specifically, Meyers points out some cases where C++ requires using private inheritance instead of the more desirable layering approach. In Dylan, these cases simply do not occur, and layering is always applicable.</font><br /><br /><font face="Optima-Regular">42. </font><font face="Optima-Italic"><i>Differentiate between inheritance and templates.</i></font><font face="Optima-Regular"> Dylan directly supports generic programming without the use of a specialized syntax like C++ templates, and it is considered good form to make the difference transparent. Most Dylan programming is generic programming to at least some degree, making it easier to reuse code. Dylan also supports homogenous and heterogeneous containers. In fact, unlike in C++, neither of these features requires generating duplicate code (although this can be done as an optimization, as a form of inlining).</font><br /><br /><font face="Optima-Regular">43. </font><font face="Optima-Italic"><i>Use multiple inheritance judiciously.</i></font><font face="Optima-Regular"> Taking the topic title literally, it also applies to Dylan. However, MI in C++ has a number of complications that MI in Dylan simply doesn’t suffer from, making MI use easier and more common. Mixin inheritance is a common idiom in Dylan.</font><br /><br /><font face="Optima-Regular">44. </font><font face="Optima-Italic"><i>Say what you mean; understand what you’re saying.</i></font><font face="Optima-Regular"> This is sort of a summary of some of Meyers’ previous points. I won’t bother going into detail. If you read his book and my comments, it should be straightforward to see how his points apply to Dylan.</font><br /><br /><br /><font face="Optima-Bold"><b>Miscellany</b></font><br /><br /><font face="Optima-Regular">These are general points, for the most part, and apply to Dylan, although the details differ.</font><br /><br /><font face="Optima-Regular">45. </font><font face="Optima-Italic"><i>Know what functions C++ silently writes and calls.</i></font><font face="Optima-Regular"> Speaking very, </font><font face="Optima-Italic"><i>very</i></font><font face="Optima-Regular"> broadly, this is good advice for Dylan, too. However, in stark contrast to C++, Dylan writes and calls very little code implicitly, and any implicit code does the right thing (whereas, for example, in C++, if you have any pointer data members the default destructor will not call delete on them). In fact, Dylan really only generates accessor functions for slots, and they’re trivial. Default methods on make() and initialize(), which create and initialize objects, do the right thing by default. There is no copying assignment operator, copy constructor, or address-of operators as generated in C++.</font><br /><br /><font face="Optima-Regular">46. </font><font face="Optima-Italic"><i>Prefer compile-time and link-time errors to runtime errors.</i></font><font face="Optima-Regular"> The same is true of Dylan, although unlike C++ you are guaranteed to get runtime errors (exceptions) instead of silent failures for things that can’t be checked at compile- or link-time.</font><br /><br /><font face="Optima-Regular">47. </font><font face="Optima-Italic"><i>Ensure that global objects are initialized before they’re used.</i></font><font face="Optima-Regular"> This is guaranteed in Dylan. All globals (and locals, too) must have an explicit initial value. There is no way to forget to initialize one. Furthermore, Dylan makes it easier to specify initial values, and it guarantees that globals with dependencies will be initialized in the correct order.</font><br /><br /><font face="Optima-Regular">48. </font><font face="Optima-Italic"><i>Pay attention to compiler warnings.</i></font><font face="Optima-Regular"> A good idea no matter what language you’re using.</font><br /><br /><font face="Optima-Regular">49. </font><font face="Optima-Italic"><i>Plan for coming language features.</i></font><font face="Optima-Regular"> Most of Meyers’ points here are very specific to C++. I’ll just point out that one of Dylan’s greatest strengths is that it makes it easier to change things.</font><br /><br /><font face="Optima-Regular">50. </font><font face="Optima-Italic"><i>Read the ARM.</i></font><font face="Optima-Regular"> Read the <a href="http://www.gwydiondylan.org/books/drm/index.html">Dylan Reference Manual</a>. It’s shorter and simpler than the ARM. To be fair, a lot of the “motivation” discussion in the ARM won’t be found in the DRM. Instead, look to other sources, such as <a href="http://www.ai.mit.edu/~gregs/info-dylan.html">info-dylan</a> email and <a href="http://groups.google.com/groups?q=comp.lang.dylan">comp.lang.dylan</a> Usenet archives, as well as <a href="http://www.gwydiondylan.org/books/dpg/index.html">Dylan Programming</a>.</font></div> ]]></description>
      <pubDate>Sun, 11 Apr 2004 06:41:58 -0700</pubDate>
	  <guid>http://homepage.mac.com/chrispage/iblog/C42511381/E1695292303/index.html</guid>
	  
    </item>

    <item>
      <title><![CDATA[The Libration of the Earth’s Moon ]]></title>
      <link>http://homepage.mac.com/chrispage/iblog/C709029074/E20060917132112/index.html</link>
      <description><![CDATA[ <br /> <div><font face="Optima-Regular">Wikipedia describes <a href="http://en.wikipedia.org/wiki/Libration">libration</a> and includes a fascinating (simulated) animation of the moon as seen from the Earth over a one-month period. The surprising thing to me is how much the visibility of the moon’s surface varies over a month. Due to actual movements of the moon and changes in the angle of observation, 59% of the moon’s surface can be seen from Earth, not merely a strict “side”.</font><br /><br /><font face="Optima-Regular">I find the observed movement of the moon in the animation almost disturbingly wobbly for such a large body (though it doesn’t actually move quite that much.)</font></div> ]]></description>
      <pubDate>Sun, 17 Sep 2006 13:21:12 -0700</pubDate>
	  <guid>http://homepage.mac.com/chrispage/iblog/C709029074/E20060917132112/index.html</guid>
	  
    </item>

    <item>
      <title><![CDATA[A Handy CSS Debugging Snippet ]]></title>
      <link>http://homepage.mac.com/chrispage/iblog/C42511381/E20060806095030/index.html</link>
      <description><![CDATA[ <br /> <div><font face="Optima-Regular">I use the following bit of CSS to help visualize the structure of an XHTML (or HTML) document by putting a colored outline around the border of every element. At each level in the hierarchy the color changes so you can see when “depth” changes.</font><br /><br /><tt><font face="Monaco">  * { outline: 2px dotted red }</font></tt><br /><tt><font face="Monaco">  * * { outline: 2px dotted green }</font></tt><br /><tt><font face="Monaco">  * * * { outline: 2px dotted orange }</font></tt><br /><tt><font face="Monaco">  * * * * { outline: 2px dotted blue }</font></tt><br /><tt><font face="Monaco">  * * * * * { outline: 1px solid red }</font></tt><br /><tt><font face="Monaco">  * * * * * * { outline: 1px solid green }</font></tt><br /><tt><font face="Monaco">  * * * * * * * { outline: 1px solid orange }</font></tt><br /><tt><font face="Monaco">  * * * * * * * * { outline: 1px solid blue }</font></tt><br /><br /><font face="Optima-Regular">I usually keep this block of rules at the top of a stylesheet, commented out with /*…*/, which I remove when I want to see the structure.</font></div> ]]></description>
      <pubDate>Sun, 06 Aug 2006 09:50:30 -0700</pubDate>
	  <guid>http://homepage.mac.com/chrispage/iblog/C42511381/E20060806095030/index.html</guid>
	  
    </item>

    <item>
      <title><![CDATA[The origin of “chortle” ]]></title>
      <link>http://homepage.mac.com/chrispage/iblog/C709029074/E20060805123700/index.html</link>
      <description><![CDATA[ <br /> <div><font face="Optima-Regular">The word “chortle” was coined by Lewis Carroll in </font><font face="Optima-Italic"><i><a href="http://en.wikipedia.org/wiki/Jabberwocky">Jabberwocky</a></i></font><font face="Optima-Regular">.</font></div> ]]></description>
      <pubDate>Sat, 05 Aug 2006 12:37:00 -0700</pubDate>
	  <guid>http://homepage.mac.com/chrispage/iblog/C709029074/E20060805123700/index.html</guid>
	  
    </item>

    <item>
      <title><![CDATA[Generic Programming is Simpler in Dylan vs. C++ ]]></title>
      <link>http://homepage.mac.com/chrispage/iblog/C42511381/E743986222/index.html</link>
      <description><![CDATA[<div><font face="Optima-Italic"><i>Dylan programs are usually clearer and easier to understand than their C++ equivalents, especially when writing generic code.</i></font></div>  <br /> <div><font face="Optima-Regular">The following C++ examples are from <a href="http://home.themel.com/weblog/archives/permalinks/2004-12-29T16_11_58.html">Thomas Themel’s blog</a>. He has some interesting things to say about programming languages there, but I'll let you read what he has to say. I’m just using his code as a starting point for some of my own ramblings.</font><br /><br /><font face="Optima-Regular">The original C++ example:</font><br /><br /><tt><font face="Monaco" color="#333333">  void exchange(map&lt;string, int&gt;&amp; ref, int id1, int id2)</font></tt><br /><tt><font face="Monaco" color="#333333">  {</font></tt><br /><tt><font face="Monaco" color="#333333">      if (ref.find(id1) != ref.end() &amp;&amp;</font></tt><br /><tt><font face="Monaco" color="#333333">          ref.find(id2) != ref.end())</font></tt><br /><tt><font face="Monaco" color="#333333">      {</font></tt><br /><tt><font face="Monaco" color="#333333">          string tmp = map[id1];</font></tt><br /><tt><font face="Monaco" color="#333333">          map[id1] = map[id2];</font></tt><br /><tt><font face="Monaco" color="#333333">          map[id2] = tmp;</font></tt><br /><tt><font face="Monaco" color="#333333">      }</font></tt><br /><tt><font face="Monaco" color="#333333">  }</font></tt><br /><br /><font face="Optima-Regular">The C++ template version, which is more general:</font><br /><br /><tt><font face="Monaco" color="#333333">  template &lt;typename _id_t, typename _mem_t&gt; </font></tt><br /><tt><font face="Monaco" color="#333333">  void exchange(map&lt;_id_t, _mem_t&gt;&amp; ref, const _id_t&amp; id1, const _id_t&amp; id2)</font></tt><br /><tt><font face="Monaco" color="#333333">  {</font></tt><br /><tt><font face="Monaco" color="#333333">      typename map&lt;_id_t, _mem_t&gt;::iterator it1 = ref.find(id1);</font></tt><br /><tt><font face="Monaco" color="#333333">      typename map&lt;_id_t, _mem_t&gt;::iterator end = ref.end();</font></tt><br /><tt><font face="Monaco" color="#333333">  </font></tt><br /><tt><font face="Monaco" color="#333333">      if (it1 != end)</font></tt><br /><tt><font face="Monaco" color="#333333">      {</font></tt><br /><tt><font face="Monaco" color="#333333">          typename map&lt;_id_t, _mem_t&gt;::iterator it2 = ref.find(id1);</font></tt><br /><tt><font face="Monaco" color="#333333">          if (it2 != end)</font></tt><br /><tt><font face="Monaco" color="#333333">          {</font></tt><br /><tt><font face="Monaco" color="#333333">              _mem_t tmp = it2-&gt;second;</font></tt><br /><tt><font face="Monaco" color="#333333">              it2-&gt;second = it1-&gt;second;</font></tt><br /><tt><font face="Monaco" color="#333333">              it1-&gt;second = tmp;</font></tt><br /><tt><font face="Monaco" color="#333333">          }</font></tt><br /><tt><font face="Monaco" color="#333333">      }</font></tt><br /><tt><font face="Monaco" color="#333333">  }</font></tt><br /><br /><font face="Optima-Regular">One of the problems with C++ is that if you want to write general, flexible code, it can get pretty hairy, making it more difficult to understand—or to write the code correctly in the first place. Similar Dylan code is usually much clearer and succinct.</font><br /><br /><font face="Optima-Regular">A simple Dylan rendition:</font><br /><br /><tt><font face="Monaco" color="#333333">  define method exchange (c :: &lt;collection&gt;, key1, key2) =&gt; ()</font></tt><br /><tt><font face="Monaco" color="#333333">    let temp1 = c[key1];</font></tt><br /><tt><font face="Monaco" color="#333333">    let temp2 = c[key2];</font></tt><br /><tt><font face="Monaco" color="#333333">    c[key1] := temp2;</font></tt><br /><tt><font face="Monaco" color="#333333">    c[key2] := temp1;</font></tt><br /><tt><font face="Monaco" color="#333333">  end method exchange;</font></tt><br /><br /><font face="Optima-Regular">Perhaps the most important thing to note here is that this Dylan rendition is equivalent to the template version, because it can work with arguments of several different types, yet, like the original, non-template C++ code, it remains clear and easy to read, where C++ template syntax can get quite verbose and obscure.</font><br /><br /><font face="Optima-Regular">In fact, it is more general than the template version, because it works with any collection, not just maps. If you wanted to limit it to “maps”, you would just change “</font><tt><font face="Monaco" color="#333333">&lt;collection&gt;</font></tt><font face="Optima-Regular">” to “</font><tt><font face="Monaco" color="#333333">&lt;table&gt;</font></tt><font face="Optima-Regular">”, the Dylan hash-table class.</font><br /><br /><font face="Optima-Regular">Similarly, because we didn’t restrict the types of key1 and key2, they can be any type at all. So this function can work with arrays, hash-tables, linked-lists—any collection type that can be accessed with the “</font><tt><font face="Monaco" color="#333333">[]</font></tt><font face="Optima-Regular">” operator—and they can contain elements of any type, without the consequent verboseness you’re likely to find in an equivalent C++ template.</font><br /><br /><font face="Optima-Regular">Now, you may have noticed that this isn’t exactly a direct translation from the original: Unlike the C++ code, this signals an error (“throws an exception”) if key1 or key2 aren’t found. I don’t understand why the original version silently ignores invalid arguments. Seems like a bad idea to me. But, this is a good opportunity to discuss how to handle invalid keys in Dylan.</font><br /><br /><font face="Optima-Regular">First, here’s a more direct translation of the original. It only accepts hash-tables, and it checks whether the keys are valid before using them, so invalid keys are silently ignored:</font><br /><br /><tt><font face="Monaco" color="#333333">  define method exchange (t :: &lt;table&gt;, key1, key2) =&gt; ()</font></tt><br /><tt><font face="Monaco" color="#333333">    if (key-exists?(t, key1) &amp; key-exists?(t, key2))</font></tt><br /><tt><font face="Monaco" color="#333333">      let temp = t[key1];</font></tt><br /><tt><font face="Monaco" color="#333333">      t[key1] := t[key2];</font></tt><br /><tt><font face="Monaco" color="#333333">      t[key2] := temp;</font></tt><br /><tt><font face="Monaco" color="#333333">    end if;</font></tt><br /><tt><font face="Monaco" color="#333333">  end method exchange;</font></tt><br /><br /><font face="Optima-Regular">Again, this is just as general as the C++ template function, but without the complicated syntax. In Dylan, all code is effectively template code, it’s just a matter of degree. The more tightly you define the types used in your programs, the less generic—and the less template-like—your programs are. In that vein, for the rest of this discussion I’ll go back to using </font><tt><font face="Monaco" color="#333333">&lt;collection&gt;</font></tt><font face="Optima-Regular"> instead of </font><tt><font face="Monaco" color="#333333">&lt;table&gt;</font></tt><font face="Optima-Regular">.</font><br /><br /><font face="Optima-Regular">Explicitly checking whether the keys are valid could be a waste of effort if the keys are valid most of the time. When we attempt to access the collection the keys will be tested, anyway. Instead, we can just try to use the keys and establish an exception handler that does nothing if one or both are invalid:</font><br /><br /><tt><font face="Monaco" color="#333333">  define method exchange (c :: &lt;collection&gt;, key1, key2) =&gt; ()</font></tt><br /><tt><font face="Monaco" color="#333333">    block ()</font></tt><br /><tt><font face="Monaco" color="#333333">      let temp1 = c[key1];</font></tt><br /><tt><font face="Monaco" color="#333333">      let temp2 = c[key2];</font></tt><br /><tt><font face="Monaco" color="#333333">      c[key1] := temp2;</font></tt><br /><tt><font face="Monaco" color="#333333">      c[key2] := temp1;</font></tt><br /><tt><font face="Monaco" color="#333333">    exception e</font></tt><br /><tt><font face="Monaco" color="#333333">    end block;</font></tt><br /><tt><font face="Monaco" color="#333333">  end method exchange;</font></tt><br /><br /><font face="Optima-Regular">(“</font><tt><font face="Monaco" color="#333333">block</font></tt><font face="Optima-Regular">…</font><tt><font face="Monaco" color="#333333">exception</font></tt><font face="Optima-Regular">” is like C++’s “</font><tt><font face="Monaco" color="#333333">try</font></tt><font face="Optima-Regular">…</font><tt><font face="Monaco" color="#333333">catch</font></tt><font face="Optima-Regular">”. In fact, the C++ code could have used a similar approach.)</font><br /><br /><font face="Optima-Regular">Now, Dylan actually has a more efficient, direct way to look up collection elements without the cost of testing the keys or handling an exception. Just as in C++, when you use the array access operator “</font><tt><font face="Monaco" color="#333333">[]</font></tt><font face="Optima-Regular">”, you’re actually calling a function (“</font><tt><font face="Monaco" color="#333333">operator[]</font></tt><font face="Optima-Regular">” in C++), and you can explicitly call that function instead of using the “</font><tt><font face="Monaco" color="#333333">x[i]</font></tt><font face="Optima-Regular">” syntax. In Dylan, that function is named “</font><tt><font face="Monaco" color="#333333">element</font></tt><font face="Optima-Regular">”, and when you call it explicitly you can give it additional arguments.</font><br /><br /><tt><font face="Monaco" color="#333333">element</font></tt><font face="Optima-Regular"> accepts an optional keyword argument called “</font><tt><font face="Monaco" color="#333333">default:</font></tt><font face="Optima-Regular">”, and if the key is invalid, it returns the default value instead of signaling an error. This means that the key is only tested for validity once, in </font><tt><font face="Monaco" color="#333333">element</font></tt><font face="Optima-Regular">, and an invalid key produces an identifiable result instead of imposing the cost of signaling and handling an error. This is more efficient in cases where you expect invalid keys to occur often:</font><br /><br /><tt><font face="Monaco" color="#333333">  define method exchange (c :: &lt;collection&gt;, key1, key2) =&gt; ()</font></tt><br /><tt><font face="Monaco" color="#333333">    let tmp1 = element(c, key1, default: #f);</font></tt><br /><tt><font face="Monaco" color="#333333">    let tmp2 = element(c, key2, default: #f);</font></tt><br /><tt><font face="Monaco" color="#333333">    if (tmp1 &amp; tmp2)</font></tt><br /><tt><font face="Monaco" color="#333333">      c[key1] := tmp2;</font></tt><br /><tt><font face="Monaco" color="#333333">      c[key2] := tmp1;</font></tt><br /><tt><font face="Monaco" color="#333333">    end if;</font></tt><br /><tt><font face="Monaco" color="#333333">  end method exchange;</font></tt><br /><br /><font face="Optima-Regular">Here, we’ve used “</font><tt><font face="Monaco" color="#333333">#f</font></tt><font face="Optima-Regular">”, the literal for boolean false, as the default value. It’s quite common in Dylan code to use false to mean “none of the above” or “no value”, since it’s convenient to test for. Because Dylan is a type-safe language, false will never be confused with any other value, such as zero (or the empty list, as in Lisp). Dylan does not have a </font><tt><font face="Monaco" color="#333333">NULL</font></tt><font face="Optima-Regular"> or </font><tt><font face="Monaco" color="#333333">Nil</font></tt><font face="Optima-Regular">, which are not type-safe. (In C++, you are also encouraged to use specific, type-safe values instead of </font><tt><font face="Monaco" color="#333333">NULL</font></tt><font face="Optima-Regular"> or </font><tt><font face="Monaco" color="#333333">0</font></tt><font face="Optima-Regular">. In fact, “</font><tt><font face="Monaco" color="#333333">NULL</font></tt><font face="Optima-Regular">” is explicitly not an official part of C++, though many programmers still use it.)</font><br /><br /><font face="Optima-Regular">Although it’s common to use false as a default value for </font><tt><font face="Monaco" color="#333333">element()</font></tt><font face="Optima-Regular">, using it means that the above code isn’t appropriate if we want to allow the collection to contain false as a value. To make sure we can distinguish between “the element is #f” and “there is no element with that key”, we can construct a unique object that will never be stored in the collection:</font><br /><br /><tt><font face="Monaco" color="#333333">  define constant $unfound = make(&lt;pair&gt;);</font></tt><br /><br /><font face="Optima-Regular">(The exact class doesn’t matter much, but a </font><tt><font face="Monaco" color="#333333">&lt;pair&gt;</font></tt><font face="Optima-Regular"> is probably the simplest built-in class in Dylan. It’s used to build linked lists and other data structures.)</font><br /><br /><font face="Optima-Regular">Now, we can use it as the default value for </font><tt><font face="Monaco" color="#333333">element</font></tt><font face="Optima-Regular">:</font><br /><br /><tt><font face="Monaco" color="#333333">  define method exchange (c :: &lt;collection&gt;, key1, key2) =&gt; ()</font></tt><br /><tt><font face="Monaco" color="#333333">    let tmp1 = element(c, key1, default: $unfound);</font></tt><br /><tt><font face="Monaco" color="#333333">    let tmp2 = element(c, key2, default: $unfound);</font></tt><br /><tt><font face="Monaco" color="#333333">    if (tmp1 ~== $unfound &amp; tmp2 ~== $unfound)</font></tt><br /><tt><font face="Monaco" color="#333333">      c[key1] := tmp2;</font></tt><br /><tt><font face="Monaco" color="#333333">      c[key2] := tmp1;</font></tt><br /><tt><font face="Monaco" color="#333333">    end if;</font></tt><br /><tt><font face="Monaco" color="#333333">  end method exchange;</font></tt><br /><br /><font face="Optima-Regular">(</font><tt><font face="Monaco" color="#333333">~==</font></tt><font face="Optima-Regular"> is the “not the same object as” comparison operator. We’re testing whether the result of </font><tt><font face="Monaco" color="#333333">element()</font></tt><font face="Optima-Regular"> is the object stored in </font><tt><font face="Monaco" color="#333333">$unfound</font></tt><font face="Optima-Regular">, not just whether it is equal to the object’s value.)</font><br /><br /><font face="Optima-Regular">In fact, although this isn’t part of the language defined in the <a href="http://www.gwydiondylan.org/books/drm/">Dylan Reference Manual</a>, </font><tt><font face="Monaco" color="#333333">$unfound</font></tt><font face="Optima-Regular"> is defined in a common set of extensions to the standard library, allowing us to omit the “</font><tt><font face="Monaco" color="#333333">define constant</font></tt><font face="Optima-Regular">” above.</font><br /><br /><font face="Optima-Regular">I’ve taken this opportunity to discuss several different points about Dylan and about programming in general, but I hope the take-away for you is that Dylan code can be generic while still being clear and easy to understand, where achieving the same thing in C++ may not always be possible.</font><br /><br /><font face="Optima-Regular">(Disclaimer: I didn't compile any of the example code, but I believe it’s all correct.)</font><br /><font face="Optima-Regular">[Later, I noticed and fixed some minor typos.]</font><br /><font face="Optima-Regular">[Later later, I changed </font><tt><font face="Monaco" color="#333333">~=</font></tt><font face="Optima-Regular"> to </font><tt><font face="Monaco" color="#333333">~==</font></tt><font face="Optima-Regular"> and added the note that explains the operator.]</font></div> ]]></description>
      <pubDate>Mon, 06 Jun 2005 04:41:42 -0700</pubDate>
	  <guid>http://homepage.mac.com/chrispage/iblog/C42511381/E743986222/index.html</guid>
	  
    </item>

    <item>
      <title><![CDATA[FedEx is like freakin’ elves ]]></title>
      <link>http://homepage.mac.com/chrispage/iblog/C1458150064/E1498189831/index.html</link>
      <description><![CDATA[<div><font face="Optima-Italic"><i>I swear they’re like elves that come in the night to make shoes or something; they come and go without you seeing them.</i></font></div>  <br /> <div><font face="Optima-Regular">FedEx is like a bunch of little elves or sumthin’. I checked on a package I’m expecting and the tracking site said it had been loaded onto the delivery vehicle at 8:00 AM yesterday. At first, I figure I’m not reading it right. It must be due tomorrow, because I didn’t see FedEx show up today. So, I decide just now to go check the front door, and sure enough there’s a little “we missed you” sticker on the door.</font><br /><br /><font face="Optima-Regular">I left the house a few minutes after the time on the notice. I’ll be generous and assume it’s due to clock inaccuracies (mine, theirs, or both o’arn), but I swear they’re like elves that come in the night to make shoes or something; they come and go without you seeing them.</font><br /><br /><font face="Optima-Regular">“We missed you.” Well, FedEx, I missed you, too.</font></div> ]]></description>
      <pubDate>Sat, 05 Mar 2005 01:00:52 -0800</pubDate>
	  <guid>http://homepage.mac.com/chrispage/iblog/C1458150064/E1498189831/index.html</guid>
	  
    </item>

    <item>
      <title><![CDATA[53a50n’5 Gr33+1ng5, right back atcha ]]></title>
      <link>http://homepage.mac.com/chrispage/iblog/C42511381/E1652831533/index.html</link>
      <description><![CDATA[<div><font face="Optima-Italic"><i>Because programmers can’t do anything in the usual way.</i></font></div>  <br /> <div><font face="Optima-Regular">Scott Knaster wrote a bit of <a href="http://foodisworse.typepad.com/this/2004/12/53a50n5_gr331ng.html">holiday code</a> in his blog. Because true geek humor also demands a (half-)serious response, here’s my rendition, “translated” into Dylan for comparison:</font><br /><br /><tt><font face="Monaco" color="#333333">let seasons-greetings =</font></tt><br /><tt><font face="Monaco" color="#333333">  if (you.do-christmas?)</font></tt><br /><tt><font face="Monaco" color="#333333">      #"merry-christmas"</font></tt><br /><tt><font face="Monaco" color="#333333">    else</font></tt><br /><tt><font face="Monaco" color="#333333">      #"happy-holidays"</font></tt><br /><tt><font face="Monaco" color="#333333">  end;</font></tt><br /><br /><tt><font face="Monaco">let </font><font face="Monaco" color="#333333">also = make( &lt;happy-birthday&gt;,</font></tt><br /><tt><font face="Monaco" color="#333333">                 to: scott-knaster,</font></tt><br /><tt><font face="Monaco" color="#333333">                 date: 26,</font></tt><br /><tt><font face="Monaco" color="#333333">                 month: $december );</font></tt></div> ]]></description>
      <pubDate>Sat, 25 Dec 2004 23:40:24 -0800</pubDate>
	  <guid>http://homepage.mac.com/chrispage/iblog/C42511381/E1652831533/index.html</guid>
	  
    </item>

    <item>
      <title><![CDATA[Characters: How abstract should they be? ]]></title>
      <link>http://homepage.mac.com/chrispage/iblog/C42511381/E697487987/index.html</link>
      <description><![CDATA[<div><font face="Optima-Italic"><i>Some thoughts on whether to model characters as abstract characters or as characters in a particular character set or encoding.</i></font></div>  <br /> <div><font face="Optima-Regular">Recently in the <a href="irc://irc.freenode.net/#dylan">#dylan</a> IRC channel on <a href="http://freenode.net/">freenode.net</a> there was a discussion about how to implement characters in computer programming languages as abstract characters—characters that exist outside of any particular encoding or character set, which you can map to and from character values in particular character sets and encodings—with the goal of representing all character data as abstract characters by default. Here are some of my thoughts from that discussion, lightly edited:</font><br /><br /><font face="Optima-Regular">Every time this discussion comes up, a sticking point for me is that you have to use </font><font face="Optima-Italic"><i>something</i></font><font face="Optima-Regular"> as a “handle” to get to an abstract character, and that usually involves an unacceptable amount of storage overhead. The popular suggestion is to use a unique string or “symbol”, sometimes known as an “interned” or “uniqued” string.</font><br /><br /><font face="Optima-Regular">I’ve always preferred approaches where you don’t have abstract characters. Every character is in some character set and you can map between them, and you either pick some relatively comprehensive intermediate encoding like Unicode for performing those mappings or you require pairs of mappings to be defined for combinations of character sets. In this model, character instances occupy at most a single machine word, just like an integer, and there is little or no auxiliary information about characters stored elsewhere. (By the way, mappings don’t have to be defined for every possible combination; you can chain them together to save space.)</font><br /><br /><font face="Optima-Regular">The interface to characters is still somewhat abstract in this approach, but if there’s an intermediate encoding for mapping, you can get a speed boost by converting your character data to that encoding and using it to do most of your text processing.</font><br /><br /><font face="Optima-Regular">At least, ten years ago it would have been unacceptable to have a symbol for every assigned Unicode code point stored on disk or in memory. Today, I am still reticent to impose an overhead of hundreds of kilobytes or potentially megabytes just to do something as common as work with text in a way that doesn’t require higher-level facilities like spelling checkers and hyphenation.</font><br /><br /><font face="Optima-Regular">For any abstract character proposal, I want to see hard performance, size, and deliverable size numbers, as well as a comprehensive description of the target users. Making this a part of the core of a programming language means it would affect </font><font face="Optima-Italic"><i>every</i></font><font face="Optima-Regular"> program.</font><br /><br /><font face="Optima-Regular">I think the overriding question to ask is, what’s the value of having truly abstract characters? Do we really need them, or is it just a conceptually pure model that has an aesthetic appeal? I don’t see much you can do with them besides test for equality and convert them to/from other character sets (you can’t compare them for sorting, you can’t convert them to/from integers, and you can’t (directly) convert digit characters to numerical values, for example).</font><br /><br /><font face="Optima-Regular">I think we can provide a protocol that’s “abstract enough”, but uses a more concrete representation.</font><br /><br /><font face="Optima-Regular">An issue for me is that I think characters should be more like integers in that they have very few properties that the core language has to support directly. We don’t talk about storing numerical properties for integers. Even if we support Unicode source code, character and string literals, and some Unicode character properties, we don’t necessarily need to support </font><font face="Optima-Italic"><i>all</i></font><font face="Optima-Regular"> of Unicode or any other non-trivial character system. Leave that to additional libraries that applications can pick and choose from.</font><br /><br /><font face="Optima-Regular">You might say I prefer characters that are abstract in that they have little or no implementation overhead (speed or space), only the minimum of functionality necessary to support simple text processing, and that relegate most higher-level functionality to (optional) libraries. I realize that we may only be discussing where to draw that line.</font><br /><br /><font face="Optima-Regular">It also just occurred to me that I think trying to model abstract characters is the same as trying to model abstract numbers. That’s a very high-level thing to try to do that’s probably best left to optional libraries. The size and speed efficiency of integers and floats that are close to the hardware is hard to ignore, and it’s highly desirable for characters to have the same efficiency advantages.</font></div> ]]></description>
      <pubDate>Tue, 07 Dec 2004 04:43:51 -0800</pubDate>
	  <guid>http://homepage.mac.com/chrispage/iblog/C42511381/E697487987/index.html</guid>
	  
    </item>

    <item>
      <title><![CDATA[Dylan Object Copying (or lack thereof) ]]></title>
      <link>http://homepage.mac.com/chrispage/iblog/C42511381/E1006212671/index.html</link>
      <description><![CDATA[<div><font face="Optima-Italic"><i>Answering the question “How do you copy objects in Dylan?” often begins with “You don’t.”</i></font></div>  <br /> <div><font face="Optima-Italic"><i>[Update: <a href="http://www.pete.gontier.org/">Pete Gontier</a> pointed out that I used the term “bitwise copying” when describing what C++ does to copy objects by default, but in fact the correct description is “member-wise copying”. This is a common terminology mistake, and the difference is important; C++ invokes a copy-constructor to copy each member and its members, recursively. Of course, when there are no explicit copy constructors to invoke, a C++ compiler could optimize it into a bitwise copy when appropriate. I've revised the text below to use “member-wise”.]</i></font><br /><br /><font face="Optima-Regular">Recently there was a discussion in the #dylan IRC channel on <a href="http://freenode.net/">freenode.net</a> about copying objects in Dylan. Someone asked how to copy objects as in C++, where assignment with ‘</font><tt><font face="Monaco">=</font></tt><font face="Optima-Regular">’ is a copying operation and when the destination is a class (or struct) instance the compiler can automatically generate a simple member-wise copy of its data members.</font><br /><br /><font face="Optima-Regular">In short: Dylan programs copy objects much less often than typical C++ code, assignment does not copy objects, objects are only copied explicitly, and simple member-wise copying is often inappropriate.</font><br /><br /><font face="Optima-Regular">There are four (no, three, Sir!) points to observe:</font><br /><br /><font face="Optima-Regular">1. In Dylan, assignment to a binding (a global or local variable, or a function parameter) does not copy or construct an object, it merely makes that binding refer to the source object. Compared to C++, it is as if every variable were a pointer to a heap-allocated object, so assignment merely copies the pointer.</font><br /><br /><tt><font face="Monaco">  let obj1 = make( &lt;my-class&gt; );</font></tt><br /><tt><font face="Monaco">  let obj2 = obj1;</font></tt><br /><br /><font face="Optima-Regular">Here, both </font><tt><font face="Monaco">obj1</font></tt><font face="Optima-Regular"> and </font><tt><font face="Monaco">obj2</font></tt><font face="Optima-Regular"> refer to the same object. The ‘==’ operator tests whether two values are the same object, and returns true (</font><tt><font face="Monaco">#t</font></tt><font face="Optima-Regular">) in this case:</font><br /><br /><tt><font face="Monaco">  obj1 == obj2;</font></tt><br /><tt><font face="Monaco">  </font></tt><font face="Osaka">⇒</font><tt><font face="Monaco"> #t</font></tt><br /><br /><font face="Optima-Regular">If we change any slots of </font><tt><font face="Monaco">obj1</font></tt><font face="Optima-Regular"> or </font><tt><font face="Monaco">obj2</font></tt><font face="Optima-Regular">, both bindings will see the same values:</font><br /><br /><tt><font face="Monaco">  obj1.my-slot := 42;</font></tt><br /><tt><font face="Monaco">  obj2.my-slot;</font></tt><br /><tt><font face="Monaco">  </font></tt><font face="Osaka">⇒</font><tt><font face="Monaco"> 42</font></tt><br /><br /><font face="Optima-Regular">This is analogous to the C++ code:</font><br /><br /><tt><font face="Monaco">  my_class* obj1 = new my_class;</font></tt><br /><tt><font face="Monaco">  my_class* obj2 = obj1;</font></tt><br /><tt><font face="Monaco">  obj1-&gt;my_slot = 42;</font></tt><br /><tt><font face="Monaco">  obj2-&gt;my_slot;</font></tt><br /><tt><font face="Monaco">  </font></tt><font face="Osaka">⇒</font><tt><font face="Monaco"> 42</font></tt><br /><br /><font face="Optima-Regular">2. Since Dylan always uses reference semantics (every binding is like a pointer to an object), there is no implicit copying of objects as there is in C++. For example, C++ copies objects to create temporaries while evaluating an expression, and when passing values in and out of functions. In contrast, objects are only copied explicitly in Dylan, and copying is performed much more rarely than in C++.</font><br /><br /><tt><font face="Monaco">  my_class obj1;</font></tt><br /><tt><font face="Monaco">  my_class result = some_function( obj1 );</font></tt><br /><br /><font face="Optima-Regular">In the above C++ example, </font><tt><font face="Monaco">obj1</font></tt><font face="Optima-Regular"> is copied when passed to </font><tt><font face="Monaco">some_function()</font></tt><font face="Optima-Regular"> and the result of that function is copied to </font><tt><font face="Monaco">result</font></tt><font face="Optima-Regular">, because C++ is using pass-by-value semantics here. In the Dylan version, no copying occurs:</font><br /><br /><tt><font face="Monaco">  let obj1 = make( &lt;my-class&gt; );</font></tt><br /><tt><font face="Monaco">  let result = some-function( obj1 );</font></tt><br /><br /><font face="Optima-Regular">The equivalent C++ code is:</font><br /><br /><tt><font face="Monaco">  my_class *obj1 = new my_class;</font></tt><br /><tt><font face="Monaco">  my_class *result = some_function( obj1 );</font></tt><br /><br /><font face="Optima-Regular">3. Copying is generally accomplished either by calling </font><tt><font face="Monaco">shallow-copy()</font></tt><font face="Optima-Regular">, which is roughly like a C++ copy constructor, or by simply creating a new object with </font><tt><font face="Monaco">make()</font></tt><font face="Optima-Regular"> and passing in initial values taken from a source object, which is like a more general C++ constructor that takes additional parameters.</font><br /><br /><tt><font face="Monaco">  let obj2 = shallow-copy( obj1 );</font></tt><br /><tt><font face="Monaco">  let obj3 = make( &lt;my-class&gt;, foo: obj2.foo, bar: obj2.bar );</font></tt><br /><br /><font face="Optima-Regular">Here, we pass the </font><tt><font face="Monaco">foo</font></tt><font face="Optima-Regular"> and </font><tt><font face="Monaco">bar</font></tt><font face="Optima-Regular"> slots of </font><tt><font face="Monaco">obj2</font></tt><font face="Optima-Regular"> to </font><tt><font face="Monaco">make()</font></tt><font face="Optima-Regular"> using keyword arguments to indicate which slots these values should be used to initialize. You could also define a custom keyword called (for example) </font><tt><font face="Monaco">copy-from:</font></tt><font face="Optima-Regular"> that just takes a source object instead of individual slot values:</font><br /><br /><tt><font face="Monaco">  let obj4 = make( &lt;my-class&gt;, copy-from: obj3 );</font></tt><br /><br /><font face="Optima-Regular">(Example implementations are at the end of this entry.)</font><br /><br /><font face="Optima-Regular">4. By default, </font><tt><font face="Monaco">shallow-copy()</font></tt><font face="Optima-Regular"> is defined only for collections, such as lists, vectors, strings, and arrays. In order to use it with other classes, you must define a method yourself. There is no automatic way to copy the slots of a user-defined object. A justification for this is that copying is not usually as simple as just copying the bits of every slot, so there is no reasonable default copying implementation. Copying some slots requires copying the objects they refer to, and yet other slots shouldn’t be copied at all. The same is actually true of C++, where most non-trivial classes require user-defined copy constructors or </font><tt><font face="Monaco">operator=</font></tt><font face="Optima-Regular"> member functions to handle copying correctly.</font><br /><br /><font face="Optima-Regular">Prompted by this discussion, I did a survey of all the Dylan code in the Gwydion Dylan CVS repository in ./fundev, ./libraries, and ./src for definitions and uses of </font><tt><font face="Monaco">shallow-copy()</font></tt><font face="Optima-Regular">:</font><br /><br /><font face="Optima-Regular">  &lt;<a href="http://www.gwydiondylan.org/cgi-bin/viewcvs.cgi/">http://www.gwydiondylan.org/cgi-bin/viewcvs.cgi/</a>&gt;</font><br /><br /><font face="Optima-Regular">As expected, there are relatively few occurrences of </font><tt><font face="Monaco">shallow-copy()</font></tt><font face="Optima-Regular">. Also important to note is that only two or three </font><tt><font face="Monaco">shallow-copy()</font></tt><font face="Optima-Regular"> methods are effectively trivial slot copying. Furthermore, it turns out I wrote one of them (back in 1997) and looking at the code now I realize it may not even have been necessary or desirable.</font><br /><br /><font face="Optima-Regular">So the answer to the original question is that Dylan assignment does not copy, you must explicitly copy objects using functions you provide implementations for, and in any case you’re not going to have to do that very often.</font><br /><br /><br /><font face="Optima-Italic"><i>Example Implementations of Copying</i></font><br /><br /><font face="Optima-Regular">Although I had originally intended to end this blog entry here, I’ve decided to provide some details that may help make some of this discussion a little more concrete for those unfamiliar with </font><tt><font face="Monaco">make()</font></tt><font face="Optima-Regular"> and </font><tt><font face="Monaco">shallow-copy()</font></tt><font face="Optima-Regular">. Given the class definition:</font><br /><br /><tt><font face="Monaco">  define class &lt;my-class&gt; (&lt;object&gt;)</font></tt><br /><tt><font face="Monaco">    slot foo, init-keyword: foo:;</font></tt><br /><tt><font face="Monaco">    slot bar, init-keyword: bar:;</font></tt><br /><tt><font face="Monaco">  end;</font></tt><br /><br /><font face="Optima-Regular">we can now simply call </font><tt><font face="Monaco">make()</font></tt><font face="Optima-Regular"> with keywords </font><tt><font face="Monaco">foo:</font></tt><font face="Optima-Regular"> and </font><tt><font face="Monaco">bar:</font></tt><font face="Optima-Regular"> to copy slots from another instance as mentioned above:</font><br /><br /><tt><font face="Monaco">  make( &lt;my-class&gt;, foo: obj1.foo, bar: obj1.bar )</font></tt><br /><br /><font face="Optima-Regular">This is very explicit, and simple to implement, but perhaps a bit verbose if we need to do this a lot. We can shorten this a bit by defining an </font><tt><font face="Monaco">initialize()</font></tt><font face="Optima-Regular"> method that implements a single </font><tt><font face="Monaco">copy-from:</font></tt><font face="Optima-Regular"> keyword that takes an object from which to copy the slots:</font><br /><br /><tt><font face="Monaco">  define method initialize (obj :: &lt;my-class&gt;, #key copy-from)</font></tt><br /><tt><font face="Monaco">    next-method(); // first, perform inherited initialization</font></tt><br /><tt><font face="Monaco">    if (copy-from) // if supplied, copy the source object's slots</font></tt><br /><tt><font face="Monaco">      obj.foo := copy-from.foo;</font></tt><br /><tt><font face="Monaco">      obj.bar := copy-from.bar;</font></tt><br /><tt><font face="Monaco">    end;</font></tt><br /><tt><font face="Monaco">  end method;</font></tt><br /><br /><font face="Optima-Regular">Now we have the additional option of writing:</font><br /><br /><tt><font face="Monaco">  make( &lt;my-class&gt;, copy-from: obj1 );</font></tt><br /><br /><font face="Optima-Regular">Another approach is to implement a </font><tt><font face="Monaco">shallow-copy()</font></tt><font face="Optima-Regular"> method, like so:</font><br /><br /><tt><font face="Monaco">  define method shallow-copy (obj :: &lt;my-class&gt;)</font></tt><br /><tt><font face="Monaco">    make( &lt;my-class&gt;, foo: obj.foo, bar: obj.bar )</font></tt><br /><tt><font face="Monaco">  end method;</font></tt><br /><br /><font face="Optima-Regular">(Also note we could both implement </font><tt><font face="Monaco">copy-from:</font></tt><font face="Optima-Regular"> and use it to implement </font><tt><font face="Monaco">shallow-copy()</font></tt><font face="Optima-Regular">, if desired.)</font><br /><br /><font face="Optima-Regular">Notice that all we’ve done is wrap up the verbose call to </font><tt><font face="Monaco">make()</font></tt><font face="Optima-Regular"> in </font><tt><font face="Monaco">shallow-copy()</font></tt><font face="Optima-Regular">. The behavior is the same whichever you call. This points out that for some cases, writing a </font><tt><font face="Monaco">shallow-copy()</font></tt><font face="Optima-Regular"> method may be unnecessary. Implementing </font><tt><font face="Monaco">shallow-copy()</font></tt><font face="Optima-Regular"> helps wrap your copying code up in a well-known copying protocol that can be used to copy objects without knowing exactly how to copy them, but sometimes that generality isn’t strictly necessary. It depends on the code in question and where the abstraction boundaries are.</font><br /><br /><font face="Optima-Regular">Finally, notice that it’s just as easy for you to define your own copying function if </font><tt><font face="Monaco">shallow-copy()</font></tt><font face="Optima-Regular"> isn’t appropriate. For example, if you want to perform copying that is deeper, but only for certain slots:</font><br /><br /><tt><font face="Monaco">  define method copy-in-my-own-special-way (obj :: &lt;my-class&gt;)</font></tt><br /><tt><font face="Monaco">    make( &lt;my-class&gt;, foo: shallow-copy( obj.foo ), bar: obj.bar );</font></tt><br /><tt><font face="Monaco">  end method;</font></tt><br /><br /><font face="Optima-Regular">This custom copying function copies part of the object a little more deeply, by shallow copying the </font><tt><font face="Monaco">obj.foo</font></tt><font face="Optima-Regular"> value. Remember, Dylan never copies implicitly, so </font><tt><font face="Monaco">obj.bar</font></tt><font face="Optima-Regular"> is not copied; instead, the new object’s </font><tt><font face="Monaco">bar</font></tt><font face="Optima-Regular"> slot is bound to the same object as the source object’s </font><tt><font face="Monaco">bar</font></tt><font face="Optima-Regular">. In contrast, by calling </font><tt><font face="Monaco">shallow-copy()</font></tt><font face="Optima-Regular"> with </font><tt><font face="Monaco">obj.foo</font></tt><font face="Optima-Regular">, we make a (shallow) copy of its value, so that </font><tt><font face="Monaco">foo</font></tt><font face="Optima-Regular"> in the new object is distinct from </font><tt><font face="Monaco">foo</font></tt><font face="Optima-Regular"> in the original object.</font></div> ]]></description>
      <pubDate>Sun, 20 Jun 2004 09:08:25 -0700</pubDate>
	  <guid>http://homepage.mac.com/chrispage/iblog/C42511381/E1006212671/index.html</guid>
	  
    </item>

    <item>
      <title><![CDATA[A Round of Applause for OmniGraffle ]]></title>
      <link>http://homepage.mac.com/chrispage/iblog/C42511381/E2101941149/index.html</link>
      <description><![CDATA[<div><font face="Optima-Italic"><i>A plug for OmniGraffle, the greatest graphics tool since sliced vectors.</i></font></div>  <br /> <div><font face="Optima-Regular">Recently, in my work on the online <a href="http://www.gwydiondylan.org/books/drm/">Dylan Reference Manual</a>, I needed to recreate some <a href="http://www.gwydiondylan.org/books/drm/drm_93.html">class hierarchy diagrams</a> and other figures that are a part of the printed DRM, but which were never provided with the HTML version.</font><br /><br /><font face="Optima-Regular">They tend to be structured diagrams with boxes and arrows and descriptive text, the kind of stuff that is tedious to draw by hand, but which should be a breeze with a capable piece of software that knows how to arrange and draw these patterned designs.</font><br /><br /><font face="Optima-Regular">As it turns out, there is a wonderful tool for doing these kinds of graphics, which made my life a lot easier: </font><font face="Optima-Italic"><i>OmniGraffle</i></font><font face="Optima-Regular"> by <a href="http://www.omnigroup.com/">The Omni Group</a>.</font><br /><br /><font face="Optima-Regular">It occurred to me that I should give them a plug in my blog for all the help they gave me:</font><br /><br /><font face="Optima-Regular">Plug, plug, plug.</font><br /><br /><font face="Optima-Regular">So, there you go.</font></div> ]]></description>
      <pubDate>Thu, 11 Nov 2004 03:57:51 -0800</pubDate>
	  <guid>http://homepage.mac.com/chrispage/iblog/C42511381/E2101941149/index.html</guid>
	  
    </item>

    <item>
      <title><![CDATA[How to Spot Nerds From Quite a Long Way Away ]]></title>
      <link>http://homepage.mac.com/chrispage/iblog/C1458150064/E2012867934/index.html</link>
      <description><![CDATA[<div><font face="Optima-Italic"><i>In which our hero has a revealing moment of self-observation involving a container of pudding.</i></font></div>  <br /> <div><font face="Optima-Regular">I was preparing to eat some chocolate pudding when I started thinking about how, once opened, it always develops pools of liquid (water, presumably) on top when left in the fridge, which I find a little gross, and I always scoop that top part off when I continue eating it later. I wondered why there was no liquid to start with.</font><br /><br /><font face="Optima-Regular">Today, as I was opening this fresh container of pudding, I realized that it has a plastic seal that touches the surface of the pudding, so I guess it keeps the water at bay. Once removed, the water has room to move to the surface, or perhaps it’s the exposure to air that draws the water out.</font><br /><br /><font face="Optima-Regular">Then I started thinking, “I guess pudding is a suspension, where the liquid and the solids aren't entirely ‘fused’ and the water can seep to the surface,” which then led me to ask (silently, to myself), “is pudding a liquid, a solid, a suspension, or what?”</font><br /><br /><font face="Optima-Regular">Finally, I went “meta” and realized that was how I could tell I was a geek: I was wondering about what kind of state of matter chocolate pudding is†.</font><br /><br /><font face="Optima-Regular">And, of course, writing “I went ‘meta’” is probably a dead giveaway, too.</font><br /><br /><font face="Optima-Regular">†Bad grammar, no biscuit! (But I like the way it flows, or, rather, the way it completely fails to do so.)</font></div> ]]></description>
      <pubDate>Tue, 09 Nov 2004 16:36:12 -0800</pubDate>
	  <guid>http://homepage.mac.com/chrispage/iblog/C1458150064/E2012867934/index.html</guid>
	  
    </item>

    <item>
      <title><![CDATA[Online Dylan Reference Manual Redesign ]]></title>
      <link>http://homepage.mac.com/chrispage/iblog/C42511381/E414703007/index.html</link>
      <description><![CDATA[<div><font face="Optima-Italic"><i>I've completely redesigned the online Dylan Reference Manual, making it easier to read and to use as a convenient reference for the Dylan programming language.</i></font></div>  <br /> <div><font face="Optima-Regular">It's been a while since my last Dylan-related blog entry, and partly it's because I've been spending most of my Dylan-related time for the past few weeks on heavily editing the online <a href="http://www.gwydiondylan.org/books/drm/">Dylan Reference Manual</a>. My desire is to make sure the online DRM is an excellent reference for the Dylan language, and I think this update has made a lot of improvements (unfortunately, there are some real problems with the quality of the machine-generated HTML that make it less readable, but I've fixed a lot of them and I hope to address them all eventually).</font><br /><br /><font face="Optima-Regular">If you're curious about the Dylan language, or you've taken a look at the online DRM before and found it lacking as a tool for learning about the language, please take a look at the new version.</font><br /><br /><font face="Optima-Regular">Here's a copy of my commit message with the details of the changes:</font><br /><br /><font face="Optima-Regular">Complete redesign of the online DRM, including a new navigation bar on the left, which features convenient access to interior links to items on each page (this was previously relegated to the bottom of the page, and is particularly useful for navigating longer, more complex pages).</font><br /><br /><font face="Optima-Regular">I also used CSS to make the printed rendition of the HTML more reasonable. All the navigation items are hidden, and links are printed in plain text, without underlines or blue coloring.</font><br /><br /><font face="Optima-Regular">While I put CSS to good use, I also tried to make the HTML produce a more reasonable, usable rendition than before, when CSS isn't supported or stylesheets are disabled.</font><br /><br /><font face="Optima-Regular">Overall, the layout and typography is now much closer to the printed DRM, and I've reconstructed some content that was apparently lost during the automatic translation to HTML.</font><br /><br /><font face="Optima-Regular">I made use of CSS to hide some information not in the printed DRM or that was just cluttering things up, while leaving it in the HTML in case we want to make use of it in the future. (e.g., in the navigation links, it includes tags like "[Open Generic Function]", which are no longer displayed.)</font><br /><br /><font face="Optima-Regular">I consolidated all the HTML pages of Appendix B, Exported Names, into one page. There was no reason for it to be split up and it just made it harder to navigate.</font><br /><br /><font face="Optima-Regular">I added "disabled" renditions of each navigation button image, so the set of buttons doesn't change on pages where one or more buttons don't apply.</font><br /><br /><font face="Optima-Regular">Too many fixes and adjustments to tagging to mention, but this includes fixing the tagging of all the function signatures (though not all the G.F. method signatures).</font><br /><br /><font face="Optima-Regular">In fact, this work began as merely an attempt to fix the signature tagging, but once you start making global changes to over a hundred HTML files in dire need of cleanup, it's hard to find a good stopping point. Or maybe that's just me.</font></div> ]]></description>
      <pubDate>Mon, 08 Nov 2004 23:21:18 -0800</pubDate>
	  <guid>http://homepage.mac.com/chrispage/iblog/C42511381/E414703007/index.html</guid>
	  
    </item>
  
  </channel>
</rss>
