Introduction to Thoughtful Programming and the Forth Philosophy



Michael Misamore

Copyright 2002

This document may be freely distributed so long as it is reproduced in its entirety without modificatons.

To the reader: constructive criticism and commentary is welcome!

Introduction to Thoughtful Programming

What is "good programming practice"? Why do most modern developers look to object orientation, polymorphism, scripting technologies, ultra-high level languages, component architectures, and libraries for "good" programming solutions? Are they good in the sense of end user speed? Certainly not. The modern programmer is more likely to sacrifice significant amounts of runtime processing power for a shorter development cycle. Are they good in the sense of complexity? Also obviously not; these new technologies are among the most complex solutions to seemingly simple problems ever created. Is abstraction a good thing? Computer science teachers would certainly say yes: they help the programmer get his or her work done faster by effectively providing snap-together components and a layer of glue called the "programming language". So some major trends in modern software development come to the forefront almost immediately: the tendency to sacrifice end user speed and complexity for ease and speed of development, and the increasing tendency to use abstraction to avoid the details of actual problem solving. In fact it seems that all one needs is a "general idea" of how to start solving a problem before one sits down to code. This is certainly the view of most computer science students.

This is also the view of businesses in the increasingly information-driven economy of the United States. They believe that software should be developed and shipped as quickly as possible to make it to the market on time. If this involves cutting corners in terms of runtime speed, code complexity, size, system requirements, or bug testing, it is considered a sacrifice which can be remedied after the product ships. After all, the business has a bottom line, and if the code works, marketing is perfectly willing to sell it to people.

Now, it is doubtful that many programmers, perhaps after some hard thought, would consider this kind of software beautiful. It is certainly suboptimal in many aspects already mentioned, there are certainly sections of code which could be rewritten or done away with, perhaps it was written in a scripting language when it should have been written in a lower level language, etc. And let's not forget the hundreds or thousands of bugs that still lie in the code because the deadline was hit. This is not the kind of code that a programmer would be proud to admit to writing.

Perhaps there are some things to be proud of in the technologies used in the product itself. "I designed a new class hierarchy which makes much more sense than the previous one" or "our new reusable component architecture makes communicating over the net a snap!" or other similar responses are probably common. But are these architectures actually necessary? What has the programmer actually accomplished besides creating new layers of complexity atop the previous layers? Certainly it is possible to accomplish these tasks without abstract architectures and garbage collectors and network layers and applications programming interfaces and maybe even operating systems? What victory, then, may be claimed here? A victory over complexity? No, since this new technology just adds complexity to the machine. More likely this was a victory for ease of programming. This was a victory for the programmer rather than the end user. This was a case of the programmer being a little greedy, wasting the time of thousands or millions so that he can waste a little less time of his own.

So in fact there is very little to be aesthetically proud of in the development of commercial software as it is currently developed, besides the fact that it gets the job done, or, at least gets the job done sometimes, in some circumstances. Programming aesthetics take a back seat to the industry's demands, and this has usually resulted in software of poorer quality than is necessary. The philosophy taught to the mainstream of computer science students emphasizes these industry goals, and asserts that these are good and "right" for use in software engineering. However, there is another school of thought, one which has been around as long as computer hackers and enthusiasts have been around, which emphasizes a very different style of programming. If taken seriously, this older set of aesthetics leads to an entirely different philosophy: the philosophy of Thoughtful Programming. More on this later. First lets discuss the problems of the more modern industry philosophy.

For years now, the computer industry, largely in marketing efforts, has given the average consumer the impression that computing technology is abundant and ubiquitous [4]. Neither is really the case. Comparatively very few people in the world even own a personal computer and those who do mostly live in only the richest countries in the world. To the average person an Apple IIe or Commodore is a dream machine. This trend in marketing tends to encourage wastefulness both in the industry and at the personal level. In the latter case, good hardware and software is simply abandoned or destroyed. Computers clocked at 75 megahertz are considered so slow as to be unusable (this is due to increasingly slow software). This is of course the end result of the tendency for the industry to produce slower software (which wastes more clock cycles by definition) since the hardware is also improving at break-neck speed and, of course, old computers are considered to be disposable.

Indeed, a number of new technologies have arisen to fill all of these new clock cycles, and more often than not they benefit the programmers and executives more than the public in general. These new bundling trends and technologies include object orientation and rapid application development products, both of which have no positive impact on the end user (besides, perhaps, less bugs). One only needs to look to computer boot times to see how software has actually regressed in some sense over the past twenty years [4]. Observe the old Apple computers booting in only a few seconds versus a modern Pentium class machine taking almost a minute just to bring up the simulated graphical environment. One might object at this point that the latter environment is more sophisticated and hence will naturally take more time to load, but exactly what is gained from this increased sophistication is hard to tell.

It is also important to note that these new technologies which waste the resources of modern machines are also sources of lots of new problems and bugs. As every programmer probably knows, the complexity of the problems one has to deal with often increases exponentially with the size of the program being written [7]. Even in a component based architecture, unexpected interactions between the underlying components and misdocumentation of functionality lead to many headaches. Add to this the problem that the increasing complexity of computer hardware and software increases the job security of the average programmer, and hence gives the programmer an incentive to raise the amount of abstraction and abstruse methodologies to stratospheric heights [6].

Due to current programming methodologies, the average programmer has certain expectations for the types of programming tasks put to him or her. Often a programmer may be asked to effectively "glue" existing components together to implement a new application using largely already-existing code. This leads to more or less drone-like programming since writing code to combine existing pieces of code together into a larger whole usually presents no special challenges or difficulties. This leads one to wonder whether this is a result of the redundancies built into the workforce. As Chuck Moore has put it: "You can't replace the smart people, but you can replace the dumb people" [7].

The language that the programmer uses usually has a syntax which is designed to prevent the programmer from making mistakes (or otherwise the syntax seems to be thrown in more or less arbitrarily for no reason other than to stay consistent with a traditional language like C or Java). Thus on both these accounts the programmer is encouraged to think as little as possible in the actual process of programming and the task resembles more of a "gluing together" experience rather than a "building from scratch" experience.

Going back to complexity and job security, the average programmer expects whichever language is employed to take months or years to learn and master. This expectation is also largely a result of the bundling technologies which were originally supposed to simplify programming. Techniques such as late-binding are used to correct problems in these existing methodologies, adding yet another layer of complexity and decreasing actual runtime performance [9]. The average programmer expects lack of communication with the hardware designer, because the predominant viewpoint is that software and hardware should be orthogonal. This is essentially the "write once, run anywhere" philosophy. Compilers are expected to write machine code for the target architecture, and almost invariably do a worse job than a good human programmer could do (the only exception being when the hardware is so phenomenally complicated that no single human could possibly take into consideration every possible optimization). Finally, the average programmer expects a huge set of "standard" libraries which simplify the task of programming, at least to the programmer. Modern high level languages, despite various sets of language features, resemble little more than glorified "wrappers" for these existing libraries [9].

All of these phenomena may be traced back to a central theme: Chuck Moore has referred to it as the User Illusion. This is the illusion that computers themselves are actually the abstractions which they implement [4]. It is the idea that computers consist of desktops, windows, files and their filesystems, operating systems, and so on. This is the paradigm Apple has taken with their Macintosh and later Microsoft with their Windows operating system. The goal of such an effort appears to be to mask the increasingly complex underlying technology with a layer of abstraction which is intended to give the user the impression that the machine is less complex than it actually is. This is believed to promote a more "user friendly" experience, where the user has an easier time operating the machine. However, as the massive amounts of technical support and user frustration seem to suggest, this may not be the case. Often support problems arise because the user has no understanding at all of how the hardware actually works and what it is designed to do, or because the complex layers of software on the machine are too hard for the lay user to understand the underlying problem. Hence it might just as easily be argued that the increasing complexity of hardware and software have resulted in more difficulty in operations of a personal computer, not less [4].

The User Illusion also has implications for how the computer is programmed, as mentioned above. Tendencies in the design of modern software may lead the programmer to believe that the only way to accomplish the task at hand requires some complex methodology, perhaps because the programmer is attempting to anticipate problems in the general design of the software. Sometimes it is the case that the software has become so complex that these problems are in fact internal to the software design itself, and have nothing at all to do with the actual problem to be solved. These are referred to by Thoughtful Programming practitioners as the "non-problems" which are to be avoided in the design [3]. The industry programmer finds these "non-problems" to be barriers to problem solving because of the orthodox methodologies he or she attempts to employ.

Another set of problems has arisen because of the non-thoughtful practice of believing that the program that a programmer is working on is going to be the only program running on the machine of the end-user. If the average programmer pauses to think about it, one probably focuses all of one's attention on the aspects of the program's own runtime behaviors, and completely foregoes, even in the design of the program, the concept that perhaps this will not be the only process running on the machine. If this is the paradigm that every programmer follows in the design and implementation of new software, it is no wonder that programs are not designed to have minimal impact on system resources; after all, the programmer implicitly assumes that all system resources belong to him or her. All of this refers to the more common preemptive style multitasking in modern operating systems. Perhaps in a cooperative multitasking system the User Illusion has a less negative impact along this axis.

The User Illusion is also somewhat responsible for the belief that hardware and software must be very complex in order to accomplish useful tasks. History shows us that this is not the case, and indeed most of the extra complexity arises from the aforementioned industry philosophy of patching continually instead of redesigning existing hardware and code [1]. Marketing to consumers has convinced the average customer that faster always equals better; this is largely the result of software becoming progressively slower, leading to a vicious circle.

It is also (very mistakenly) believed by many that abstractions used in programming must have some actual presence in the object code which is produced. Tables of virtual methods from C++ and late binding/polymorphism again come to mind as manifestations of this development philosophy. Instead of developing the software in a way which conveniently processes abstractions at edit time in a metaprogramming framework, current software instead implements abstractions directly into the final object code, leading to slower runtime performance and larger memory footprints. This line of thinking tends to encourage pushing design time tasks to edit time, edit time tasks to compile time, and compile time tasks into runtime. That is, programmers tend to want to sit down and start coding immediately, making many mistakes which could have been avoided with a thorough design and redesign phase [3]. While programmers code, they don't tend to think when they are editing the code and hence wait for the compiler to spew out a list of errors at them, wasting additional time as the programmer switches out of the editor, gives the correct command for compilation, tries to interpret the error messages, and goes back to the editor again. It is important to note that throughout this time very little actual work is being accomplished. As mentioned before the final step is to use libraries and abstraction technologies to push what work should be done at compile time into the actual runtime of the program itself. This process obviously tends to make the program more complex than is needed and results in programs with sub-par performance.

Now that considerable thought has been given to the problems in the larger school of programming philosophy, the paradigm of Thoughtful Programming arises as one possible alternative. The fundamental difference between the philosophy of the larger computer industry and that of Thoughtful Programming is that the latter school has as its goal "minimizing overall complexity" [7]. This has required efforts, on both the hardware and software fronts, by individuals such as Chuck Moore and Jeff Fox, among undoubtedly many others. Their main principles are to create faster, simpler hardware and software solutions than those which are currently available, and in fact to produce them at competitive prices. This requires a dramatic shift in the methodology used to develop new hardware and software. In the former paradigm, focus is placed on which features to put into the new design, whereas in Thoughtful Programming the emphasis is on what can possibly be removed to make the proposed solution simpler in the sense of overall complexity [4]. The latter methodology encourages development of entire solutions, not simply new software upon inadequate hardware. The hardware must be general enough to apply to a wide variety of possible applications, and yet simple enough that the average programmer can understand every important aspect of the machine's behavior. This type of deep understanding of the machine shatters the User Illusion, and is an approach which is nearly unheard of in mainstream software development for personal computers.

In trying to design a solution to a programming problem, the Thoughtful Programmer starts with "a clean sheet of paper", as Chuck Moore puts it, and starts to think about the simplest possible solution to the problem at hand [7]. A very important aspect of this process is to identify the "non-problems": those assumptions about the necessary existing software technologies or methodologies needed to produce a satisfactory solution. Due to the much more direct assault on the problem the Thoughtful Programmer takes, it will be unlikely that any of these technologies are optimal for the specific problem at hand. At this point, the Thoughtful Programmer becomes a creative artist, and attempts to produce a solution which avoids solving all the non-problems standing in the way [3]. Representing the proposed solution in the least complex manner possible then becomes the priority, and for this the Thoughtful Programmer will write code, test it, try to break it, rewrite it to make it simpler and more elegant, and test it again. This cycle will repeat until the Thoughtful Programmer is aesthetically satisfied with the result [3]. In order to facilitate this process, it is useful to have a programming language which enables the programmer to design and test new ideas as rapidly as possible, ideally in an environment which allows new functionality to be tested as soon as it is written. Also, it is important for the programming language to be extensible so that it may easily be molded to suit the problem at hand. And by all means the language must be as flexible as possible; the programmer cannot be hindered by any inherent limitations in the expressive capability of the language itself.

Now lets observe how a Thoughtful Programmer goes through the stages of Designing, Editing, Compiling, and Running new computing solutions. Design of the solution should take the most time to complete of any of the steps, and it is the one which must be repeated most often. Each new solution should be critically examined for possible algorithmic or structural improvements, and these improvements must be integrated and tested thoroughly to make sure that the solution is indeed optimal. Remember that the biggest algorithmic improvements come not from employing the obvious and straightforward industry methods, but instead from creatively producing solutions which uniquely fit the problem at hand. Also remember that the truly optimal solution may come through the design or use of new or different hardware. Do not be afraid to consider radically different technologies as possible options for problem solving [3].

Once a satisfying solution has been arrived at, the editing phase begins, and this is the first step in the actual coding of the software. Ideally the development software will allow for the design and testing of as many ideas as possible in a short time frame. It is also at this stage that the Thoughtful Programmer must concentrate efforts on eliminating compile time and runtime overhead through the philosophy of Early Binding. From a conventional industry standpoint, Early Binding is a bad idea because it makes the final software components more inflexible and wastes compile time because modifications need to be made to each object which requires change. These objections are moot to the Thoughtful Programmer for two reasons: first, the Thoughtful Programmer does not worry about flexibility at this stage because any such changes will usually require sacrifices in complexity and runtime performance; and second, the software that the Thoughtful Programmer tends to write is of such minimal complexity that it is easy to identify and fix any code which needs to be changed. After all, the Thoughtful Programmer is generally NOT interested in software reuse; the more immediate and important concern is that the software solution being developed right now is optimal. New and better editing technologies may help alleviate any perceived problems with Early Binding as well; Early Binding need not make actual code more difficult to read or write. Various metaframeworks may be possible which might bind code early and eliminate redundancies, all while preserving the programmer's desired level of abstraction and control over the final code produced. More work should be done in this direction.

To the Thoughtful Programmer, editing is about representing the desired solution in as simple and effective manner as possible. Hence a similar process to the Design stage should be implemented, where the fat is trimmed from the representation as much as possible [1]. This methodology also stresses the importance of willingness to redesign: if the code being edited is suboptimal as a result in a flaw in the design, the programmer should be willing to start from scratch with a new design to fix the problem. This should not be that big of a problem if the Design has been well thought out in the first place, since the programmer is already well familiar with the problem and should be aware of how to recode the small amount of code necessary to implement the new design (and this code will almost always be relatively small if an efficient representation is used). The final coded solution should be as "brutally simple" as possible, and should try to do as much work in representation as possible so that less work needs to be done at compile and runtime [1].

If the Thoughtful Programmer has done his or her job right, Compile time should be a snap. The key is to code the solution so as to compile as little as possible and to interpret as much as possible before the user actually has to run the code. If the language is simple, the compilation will be fast, and this is obviously a desirable feature to have. Numerical constants should be computed at this time, not at runtime. If there are bugs, the language should allow the programmer to quickly isolate and fix them. If a bug arises which necessitates a change in the Design, it will be necessary to go back and redesign. Again, it is desirable to redesign: a good programmer will be proud to make the code better if possible. This is what distinguishes coding as an art from coding as an industry. If the steps have been correctly followed up to this point, the code will be a solution of minimal complexity necessary to solve the problem at hand. In all likelihood, runtime performance will probably be through the roof compared to competition.

Forth: A Language for Thoughtful Programming

The programming language Forth sticks out for representing many of the desired features of a language which would be useful for Thoughtful Programming. Forth was invented by Charles Moore in the early 1970s and has since become popular among Thoughtful Programmers for its emphasis on simple syntax, speed, ability to function at both low and high levels of abstraction, portability, extensibility, and general ease of use in development. One of the things that makes Forth exceptionally pleasant to newcomers is the fact that the language is very easy to learn [7]. In contrast with programming languages in the larger industry arena which take months or even years to learn adequately, learning most of how to use Forth only takes about a half an hour. The syntax is brutally simple, consisting of only words and whitespace, removing barriers that in other languages tend to hinder any remaining creative spirit programmers might have [1]. Hence the language as written has as its focus semantics rather than the peculiar syntactics of other languages [2]. This also makes the language particularly flexible and extensible since the syntactical rules do not restrict, and in fact promote, the employment of entirely new languages and rules within the existing system to express solutions.

As a result of the simplicity of the language itself, Forth is extremely easy to compile compared to other languages, and it is easier for the programmer to express exactly what he or she wants the machine to do. The language is ideal for programming in unison with a given machine's hardware, yet it has such a simple implementation on the machine itself that it can really be thought of as a high level version of assembly language [9]. Forth is very capable of low level programming tasks in particular because of its complete lack of restrictions on fundamental data types; in fact, there are none besides the standard "cells" and "double cells" which are basically units of raw memory. Hence the programmer is free to implement his or her own data types as freely as the machine may allow, in a syntax which is more powerful and convenient than assembly, and yet just as capable of direct communications with the hardware. Forth is so hardware friendly, in fact, that the primitives of the language itself may be implemented in micro-chips which are 1000 times less complex (in terms of transistor counts) than competitors, bridging the gap in simplicity between software and hardware. This is the Thoughtful Programmer's dream: to have hardware simple enough that it can be completely understood by a single human being, so that any software written for it can truly result in computing solutions of minimal complexity.

The fact that the primitives of the Forth language may be implemented in hardware does not mean, however, that it is not an effective high level language as well. In fact, the flexibility of the language allows a Thoughtful Programmer to implement whatever layers of abstraction are necessary to solve the problem at hand [9]. Since the possible data types are unlimited, the capabilities to effectively handle problems in packet mangling, databases, filesystems, and so on are effectively infinite, and the extensibility of the syntax of the language itself allows for the most convenient representations of these structures that are possible.

A Forth system as implemented in software is effectively a virtual machine. It has all the power of the Java virtual machine and more, thanks to its complete freedom of data types and lack of additional structure like objects and arrays which are provided even if the Java programmer does not really need them. Unlike Java, the Thoughtful Programmer has complete freedom in how to implement a Forth solution on the target platform, and has an inherent ability which comes from the foundations of the language itself to interact directly with the hardware. The Java virtual machine may be based on similar technology to Forth virtual machines, but the Java philosophy of implementing complex solutions on a virtual machine so that the programmer does not have to reimplement the solution for different platforms is completely against the style of Thoughtful Programming.

This is not the only way in which Forth dramatically differs from Java and other modern programming languages. Forth has traditionally taken the role of the user/programmer operating environment of the machine being developed upon, and hence has built into it a notion of direct programmer interaction in the software design process. The Thoughtful Programmer demands that software ideas be able to be written and tested quickly, and that new functionality may be tested immediately for its utility in a given programming situation. No other language could be better suited for this purpose. Forth is completely interactive with the programmer, giving direct access to the compiler and interpreter, including the compiler's own behavior. The Thoughtful Programmer has to freedom to tell a Forth system when to begin compilation, how to proceed with it, and when to pause or end it. As soon as new "words" are created, their functionality may be tested immediately without switching into a different environment. Effects on arbitrary inputs may be checked as often as desired without leaving the programming environment, making debugging a snap.

The freedom of Forth's syntax is sometimes criticized as allowing for code which is harder to read or maintain than in more traditional languages [9]. This criticism may be argued against for a number of reasons. First of all, as mentioned above, one of the advantages of Forth in software design is the inherent flexibility in the syntax. Such flexibility tends to lead to much simpler solutions to software problems due to the extensible nature of the language itself, and, if done right, might actually result in programs which are easier to read than their C++ and Java counterparts. This results from the unique ability of Forth to describe in words what it is doing as it does it. As for maintenance, Forth programmers tend to be Thoughtful Programmers and hence tend to write solutions which are as simple as possible using representations which are as efficient as possible. If a change needs to be made, it therefore should not be that arduous of a task, and if the change is large then the programmer should think about rewriting the system anyway.

In addition, Forth, like any other programming language, may have the misfortune of having particularly bad programmers write and promote bad coding solutions. It is easy to write equally horrendous code in just about any language that one might choose; Forth does not stand alone in this department [9]. The moral to take from this is that one bad coding solution in Forth is one bad coding solution in Forth; such examples rarely serve as good indicators of the readability of the language, which itself is a highly subjective property anyway. To help combat readability problems, good Forth programmers employ "factorization": the practice of breaking a program into very small bits of code which may be coded and tested individually [7]. The idea is that new word definitions can be one or two lines long, which is much more readable than, say, a sequence of 50 consecutive words. Forth uses a stack to pass inputs and outputs between words (remember that data structure from computer science?), so all arguments are implicitly passed, making the language both easier to read and faster at runtime (than say, languages like C which must set up new stack frames for each function). And of course, there is always a need for good documentation for software, and Forth systems are no different. Each word should be individually documented for its effects on inputs and outputs, and it is good practice to keep the words simple enough that stack diagrams (comments on the structure of the stack as different words act) are not needed. Remember that simplicity in representation is one of the core aspects of the Thoughtful Programming paradigm.

Another reason that Forth's simple syntax is an advantage to the Thoughtful Programmer is that doing so pushes the complexity from compile and runtime back to edit time. This is exactly the type of "pushing work backwards in time" which is advocated by Thoughtful Programmers [7]. The point is that the language itself need not be complicated to accomplish useful work. Often times the editing environment knows a lot more about the overall structure of the project, and hence it makes sense that as much important preprocessing as possible be done at the time the code is edited.

One reported problem that many programmers may initially have with the Forth language is its used of reverse polish notation for arithmetic [9]. This means that the operators on arithmetic expressions appear after the operands, not between or before them, and it is the mode commonly used to evaluate arithmetic expressions on HP calculators. This type of computation is inherent to Forth because of the central role the stack plays in the language. Such expressions may appear confusing at first, but like many technologies employed for Thoughtful Programming, the purpose is to simplify operations and dispel the User Illusion. Simplification of arithmetic expressions in RPL occurs because of the lack of need to parenthesize expressions as they are written. Expressions which might normally be mathematically expressed in terms of many parentheses are instead reduced to the natural order in which a computer would actually evaluate the expression, and thus gives the programmer an upper hand by having full control over the exact order of computation. This can be especially handy when managing things like significant digits. And even if the curious industry programmer cannot get the hang of RPL notation, the Forth language provides the flexibility to implement his or her own personal arithmetic syntax, which could be infix, prefix, or any more elaborate scheme.

There are doubtless many other objections from programmers who are skeptical of the Thoughtful Programming paradigm and the Forth programming language. It would be informative to the casual reader to discuss what they are here. One popular and quite general objection to these methods is that layers of abstraction are necessary because the hardware which one must implement software for is too complicated [4]. The way a good Thoughtful Programmer would probably react to this objection is to simply state that the hardware should be made simpler. After all, if the hardware is made less complicated, the programmer will have an easier time programming directly to the machine, there will not be a need to worry about pipelines, caching, and out of order execution. All said technologies are just extra layers of complexity which are added to the already tremendously complex CISC and RISC style microprocessors.

Despite all objections to the contrary, the Thoughtful Programmer will probably assert that even RISC chips are much too complicated to work with; after all, it is claimed even by good programmers that C compilers for RISC code will outdo even good RISC assembly programmers. This is not at all a desirable situation for the Thoughtful Programmer: the goal is to have a machine which is simple enough for a human to understand, and RISC is not simple enough for these purposes. Custom Minimal Instruction Set Computers known as MISC microprocessors have been designed by Forth and other stack computing enthusiasts as viable candidates for truly simple computing. One of the key ideas in such designs has been to implement Forth as the machine language of the processor, and to use Forth's radically extensible nature to implement any of the more complicated operations which are necessary. The processor is the high level language and the implementation is far easier to produce than that of more complicated languages like Java.

Another very common and general objection from people who may or may not understand how Thoughtful Programming works is "I would like to use method X, but Forth makes it very difficult to implement" [4]. This type of objection would probably come from someone who has been trained in the object oriented or functional programming languages before coming to consider Forth. There are a couple of points for the objector to consider. First, one has to consider whether this method is actually necessary to implement the solution. Chances are it will not be absolutely necessary, and in fact may get in the programmer's way if the programmer continues to do it "the hard way". In Forth, implementations of more advanced methods are often more difficult because Forth is closely tied to the machine and hence reflects the actual complexity that the machine will be working with. This has the positive effect of encouraging the programmer to simplify his or her solutions so that an actual machine could be efficient in implementing them.

The second point is, if the programmer is interested in using, say, the object oriented approach, then the programmer is free to implement it however he or she wants [9]. The utility of good factorization in writing code should not be underrated. Breaking the problem into smaller pieces which may be individually developed and tested allows for even complex solutions to be implemented with a minimal amount of fuss. Writing any project can seem overwhelming if the programmer does not take the time to write a design which breaks things down into parts. This is abstraction put to good use: not for code reuse or isolation, but for testing the implementation piece by piece as it is built.

Future Directions in Thoughtful Programming and Forth

Over the past 30 years, Forth has been evolving, largely due to the continuing work of its inventor, Charles Moore. While many programmers have attempted to standardize Forth as it was practiced 20 or 30 years ago to crystallize the language to outsiders, Chuck has continued to develop new and exciting ideas in Thoughtful Programming. His new colorForth language and development environment is a reflection of his ongoing search for a more convenient coding environment for the Thoughtful Programmer. An expert Forth programmer by the name of Jeff Fox has also made new and exciting contributions to the Thoughtful Programming paradigm, especially through the design of his new aha Forth system. Some of the ideas that these individuals have been working on are quite revolutionary, and show that cutting edge Forth is smaller, cleaner, and faster than ever. Indeed, over time the language itself has had the tendency to become simpler!

One new idea being tried is to completely avoid the storage of object code, and instead to compile source on the fly. This provides an obvious portability advantage in Moore's colorForth. Such an advantage is made possible through the simplicity of the implementation of the language: compilation takes no perceptible time to complete [8]. This is a result of a recent key innovation in Forth designs: to store the source code in an unconventional format. Recently these innovators have realized that Forth source code is about words, not about characters, and hence that Forth source is not ideally expressed or handled in plain ASCII format [8]. Instead, alternative representations of source based on "tokens", roughly word references with additional information appended for editing or compilation purposes, are used. This preparsed source allows for dictionary searching to be eliminated from compile time, so the laborious process of searching for ASCII strings in a word dictionary is completely eliminated from the compilation process. Compilation speedups due to this new technology have been dramatic [5].

Another recent innovation in Forth systems is due to Chuck Moore, who realized that in the simplification of source code, color could be used as a meaningful way of communication information about the behavior of the various words being displayed. By placing special information in the whitespace of the source code, Mr. Moore has been able to express his source in a simpler and easier to read format. The various colors have also been used to give words individual behaviors, eliminating much ambiguity in the behavior of how the source listings would function when compiled [8]. While Moore's colorForth was not initially designed for a wide audience, he has recently made some efforts to make it run on a wider range of personal computers than just his own systems. The outstanding efforts of Sean Pringle to bring colorForth to the masses through the Enth and Flux projects will provide a ripe test-bed for new ideas. Developments along these lines have tended to stress simplicity, avoiding the massive operating systems and BIOS systems in modern personal computers as much as possible [5].

As Forth source code has taken on completely new representations in the recent systems, more sophisticated editors have become necessary. User interfaces for these new editors are still highly experimental and under constant development. The general consensus among Thoughtful Programming enthusiasts has been to push things backwards in time in the traditional Thoughtful Programming style, performing source code compression and optimization at edit time rather than at compile time [5]. As these systems continue to develop, one might expect to see better error detection at edit time, debates about when and how to pack the source code, new optimization techniques, and a variety of different scripting technologies or different means of representing source code. Whatever the future holds, Thoughtful Programmers, likely using Forth and its descendents, will be finding new and innovative methods for minimizing complexity in computing solutions for years to come.





References

[1] Fox, Jeff. "Low Fat Computing". December 6, 1998. Online, Internet.

Available http://www.ultratechnology.com/lowfat.htm

[2] Fox, Jeff. "Forth - the LEGO of Programming Languages".

November 24, 2000. Online, Internet.

Available http://www.ultratechnology.com/4thlego.htm

[3] Fox, Jeff. "The Forth Methodology of Charles Moore by Jeff Fox".

December 9, 2001. Online, Internet. Available

http://www.ultratechnology.com/method.htm

[4] Fox, Jeff. "Thoughtful Programming and Forth". Online, Internet.

Available http://www.ultratechnology.com/forth.htm

[5] Fox, Jeff and Sean Pringle. "ENTH Flux aha Color Forth". Online,

Internet. Available http://www.ultratechnology.com/enthflux.htm

[6] Moore, Charles. "1x Forth". April 13, 1999.

Transcript courtesy of Jeff Fox. Online, Internet.

Available http://www.ultratechnology.com/1xforth.htm

[7] Moore, Charles. "Moore Forth -- Chuck Moore's Comments on Forth".

January 25, 2001. Transcript courtesy of Jeff Fox. Online,

Internet. Available http://www.ultratechnology.com/moore4th.htm

[8] Moore, Charles. "Philosophy". July 20, 2001. Online, Internet.

Available http://www.colorforth.com/phil.htm

[9] Various Authors. Comments from the slashdot.org story "Chuck Moore

Holds Forth". September 14, 2001. Online, Internet. Available

http://slashdot.org/article.pl?sid=01/09/11/139249