- To call forth a concept, a word is needed; to portray a phenomenon, a concept is needed.
- Programming computers can be crazy making.
- Programmers design, build, and repair the stuff of imagination, ghostly mechanisms that escape the senses.
- Our work takes place not in RAM, not in an editor, but within our own minds.
- Forth is a language, an operating system, a set of tools, and a philosophy.
- Assembly-language programming is characterized by a one-for-one correspondence between each command that the programmer types and each command that the processor performs.
- High-level languages are clearly more “powerful” than assembly languages in the sense that each instruction might compile dozens of machine instructions. But more significantly, high-level languages eliminate the linear corresponding between source code and the resulting machines instructions.
- Decisions about the algorithms and associated data structures should be made in parallel.
- Simplicity is the primary measurement recommended for evaluating alternative designs relative to reduced debugging and modification time.
- By dividing a problem into simple modules, programs were expected to be easier to write, easier to change, and easier to understand.
- The safest kind of coupling is the passing of local variables as parameters from one module to another.
- The smallest atom of a Forth program is not a module or a subroutine or a procedure, but a “word”.
- Everything in Forth is a word.
- Calls are implicit.
- Data passing is implicit.
- Because Forth uses a stack for passing data, words can nest within words.
- Forth eliminates from our programmes the details of how words are invoked and how data are passed.
- Because Forth is interactive, the programmer can type and test the primitive commands.
- Forth programming consists of extending the root language toward the application, providing new commands that can be used to describe the problem at hand.
- Forth is a programming environment for creating application-oriented languages.
- The purpose of hiding information is simply to minimize the effects of a possible design-change by localizing things that might change within each component.
- Forth conveniently seperates “things” from “actions” by allowing addresses of data structures to be passed on the stack and providing the “fetch” and “store” commands.
- Forth pays little attention to whether something is a data structure or an algorithm. This indifference allows us programmers incredible freedom in creating the parts of speech we need to describe our applications.
- Forth is a design language.
- Unfortunately, human foresight is limited even under the best conditions. Too much planning becomes counterproductive.
- Constructing a prototype is a more refined way to plan, just as breadboarding is in electronic design.
- Experimentation proves more reliable in arriving at the truth than the guesswork of planning.
- Overall, Forth outdoes all other high-level languages in speed, capability, and compactness.
- Although Forth is an interpretive language, it executes compiled code.
- Forth’s use of a data stack greatly reduces the performance cost of passing arguments from word to word.
- Forth can do anything any other language can do--usually easier.
- Forth can be written to run on top of any operating system or, for those who prefer it, Forth can be written as a self-sufficient operating system including its own terminal drivers and disk drivers.
- Start simple. Get it running. Learn what you’re trying to do. Add complexity gradually, as needed to fit the requirements and constraints. Don’t be afraid to restart from scratch.
- Testing and prototyping are the best ways to discover what is really needed.
- For newcomers to Forth: Keep the analysis phase to a minimum.
- For Forth addicts: Hold off on coding as long as you possibly can.
- Plan for change (by designing components that can be changed).
- Prototype.
- The first step is to determine what the application should do.
- A conceptual model is an imaginary solution to the problem. It is a view of how the system appears to work.
- A design begins to describe how the system really works.
- Strive to build a solid conceptual model before beginning the design.
- First, and most importantly, the conceptual model should describe the system’s interfaces.
- Decide on error- and exception-handling early as part of defining the interface.
- Develop the conceptual model by imagining the data traveling through and being acted upon by the parts of the model.
- Forth encourages you to think in terms of the conceptual model, and Forth’s implicit use of a data stack makes the passing of data among modules so simple it can usually be taken for granted. This is because Forth, used properly, approaches a functional language.
- Most of your efforts at defining a problem will center on describing the interface.
- Visualization of ideas helps in understanding problems, particularly those problems that are too complex to perceive in a linear way.
- You don’t understand a problem until you can simplify it.
- Keep it simple.
- Given two solutions to a problem, the correct one is the simpler.
- Generality usually involves complexity. Don’t generalize your solution any more than will be required; instead, keep it changeable.
- Go back to what the problem was before the customer tried to solve it. Exploit the “don’t cares”.
- To simplify, quantize.
- To simplify, keep the user out of trouble.
- To simplify, take advantage of what’s available.
- Careful planning is essential, because things always take longer than you expect.
- The mean time for making a “two-hour” addition to an application is approximately 12 hours.
- Conventional wisdom reveres complexity.
- Always give your client some options. Clients like options.
- Everything takes longer than you think, including thinking.
- To see the relationship between two things, put them close together. To remind yourself of the relationship, keep them together.
- The goal of preliminary design is to determine what components are necessary to accomplish the requirements.
- Within each component, implement only the commands needed for the current iteration. (But don’t preclude future additions.)
- Definitions are invoked by being named.
- The purpose of an interface component is to implement, and hide information about, the data interface between two or more other components.
- Both data structures and the commands involved in the communication of data between modules should be localized in an interface component.
- We must distinguish between data structures that are validly used only within a single component and those that may be shared by more than one component.
- Express in objective units any data to be shared by components.
- One of Forth’s rules is that a word must already have been defined to be invoked or referred to.
- Most of us are guilty of over-emphasizing the difference between “high-level” and “low-level”. This notion is an arbitrary one. It limits our ability to think clearly about software problems.
- An object is a portion of code that can be invoked by a single name, but that can perform more than one function. To select a particular function you have to invoke the object and pass it a parameter or a group of parameters.
- Don’t bury your tools.
- A component is simply a set of commands that together transform data structures and algorithms into useful functions. These functions can be used without knowledge of the structures and/or algorithms within.
- By thinking about the ways in which we solve problems, apart from the problems themselves, we enrich our subconscious storehouse of techniques.
- Determine your goal.
- Picture the problem as a whole.
- Develop a plan.
- Set a course for action and avoid the trap of fumbling about aimlessly.
- Think of an analogous problem.
- Work forward.
- Work backward.
- Belief is a necessary ingredient for successfully working backward.
- Recognize the auxiliary problem.
- Step back from the problem.
- It’s easy to get so emotionally attached to one particular solution that we forget to keep an open mind.
- Use whole-brain thinking.
- When a problem has you stumped and you seem to be getting nowhere, relax, stop worrying about it, perhaps even forget about it for a while.
- Creative people have always noted that their best ideas seem to come out of the blue, in bed or in the shower.
- Evaluate your solutions. Look for other solutions.
- Don’t invest too much effort in your first solution without asking yourself for a second opinion.
- The human mind works exceptionally well with analogies.
- Each definition should perform a simple, well-defined task.
- In designing a component, the goal is to create a lexicon that will make your later code readable and easy to maintain.
- Let numbers precede names.
- Let text follow names.
- Let definitions consume their arguments.
- Use zero-relative numbering.
- Since computers are numeric processors, software becomes easier to write when we use zero-relative numbering.
- Let addresses precede counts.
- Let sources precede destinations.
- Avoid expectations (in the input stream).
- Let commands perform themselves.
- Don’t write your own interpreter/compiler when you can use Forth’s.
- A simple solution is one that does not obscure the problem with irrelevancies.
- An algorithm is a procedure, described as a finite number of rules, for accomplishing a certain task. The rules must be unambiguous and guaranteed to terminate after a finite number of applications.
- A data structure is an arrangement of data or locations for data, organized especially to match the problem.
- We’ve stated before that the best solution to a problem is the simplest adequate one; for any problem we should strive for the simplest approach.
- In choosing which approach to apply towards solving a problem, give preference in the following order: calculation, data structures, logic.
- In devising an algorithm, consider exceptions last. In writing code, handle exceptions first.
- In Forth we try to minimize our dependent on logic.
- If you have trouble thinking about a conceptual model, visualize it--or draw it--as a mechanical device.
- Good organization has three aspects: decomposition, composition, disk partitioning.
- Composition is the putting together of pieces to create a whole. Good composition requires as much artistry as good decomposition.
- Structure your application listing like a book: hierarchically.
- Modularity of the source code is one of the reasons for Forth’s quick turnaround time for editing, loading, and testing (necessary for the iterative approach).
- Begin all definitions at the left edge of the screen, and define only one word per line.
- Spacing and indentation are essential for readability.
- Every colon or code definition that consumes and/or returns any arguments on the stack must include a stack-effect comment.
- The purpose of commenting is to allow a reader of your code to easily determine what’s going on.
- Design your application so that the code, not the comments, conveys the meaning.
- The most-accurate, least-expensive documentation is self-documenting code.
- Choose names according to “what”, not “how”.
- Find the most expressive word.
- Spell names in full.
- Favor short words.
- Hyphenated names may be a sign of bad factoring.
- Don’t bundle numbers into names.
- Use prefixes and suffixes to differentiate between like words rather than to cram details of meaning into the name itself.
- Maintainability requires readability.
- Factoring means organizing code into useful fragments.
- Don’t pass control flags downward.
- If a series of definitions contains identical functions, with variation only in data, use a defining word.
- Keep definitions short.
- A word should be a line long. That’s the target.
- Factor at the point where you feel unsure about your code (where complexity approaches the conscious limit).
- Factor at the point where a comment seems necessary.
- Limit repetition of code.
- When factoring out duplicate code, make sure the factored code serves a single purpose.
- Look for repetition of patterns.
- Be sure you can name what you factor.
- If you have a concept that you can’t assign a single name to, not a hyphenated name, but a name, it’s not a well-formed concept. The ability to assign a name is a necessary part of decomposition.
- Simplify the command interface by reducing the number of commands.
- For maximum maintainability, limit redundancy even at compile time.
- Work on only one aspect of a problem at a time.
- By concentrating on one dimension of the problem at a time, you can solve each dimension more efficiently.
- Don’t change too much at once.
- Don’t try to anticipate ways to factor too early.
- Building levels of abstraction is a dynamic process, not one you can predict.
- Today, make it work. Tomorrow, optimize it.
- A good programmer continually tries to balance the expense of building-in changeability against the expense of changing things later if necessary.
- Anticipate things-that-may-change by organizing information, not by adding complexity. Add complexity only as necessary to make the current iteration work.
- Forth handles data in one of two ways: either on the stack or in data structures.
- The simplest way for Forth words to pass arguments to each other is via the stack.
- Simplify code by using the stack. But don’t stack too deeply within any single definition. Redesign, or, as a last resort, use a named variable.
- Generally, three elements on the stack is the most you can manage within a single definition.
- Especially in the design phase, keep on the stack only the arguments you’re using immediately. Create local variables for any others. (If necessary, eliminate the variables during the optimization phase.)
- When determining which arguments to handle via data structures rather than via the stack, chose the arguments that are the more permanent or that represent a current state.
- Make sure that stack effects balance out under all possible control flows.
- When doing two things with the same number, perform the function that will go underneath first.
- Where possible, keep the number of return arguments the same in all possible cases.
- Keep return stack operators symmetrical.
- Unless it involves cluttering up the stack to the point of unreadability, try to pass arguments via the stack rather than pulling them out of variables.
- Most of the modularity of Forth comes from designing and treating Forth words as “functions” in the mathematical sense.
- The return stack is a component of the Forth system designed to hold return addresses, and thereby serve as an indication of where you’ve been and where you’re going.
- When the application requires handling a group of conditions simultaneously, use a state table, not seperate variables.
- A CONSTANT’s value should never be changed once the application is compiled.
- Using the stack is preferable for testing and reusability, but too many values manipulated on the stack by a single definition hurts readability and writability.
- Control structures aren’t as important in Forth as they are in other languages.
- The use of conditional structures adds complexity to your code.
- The more complex your code is, the harder it will be for you to read and to maintain.
- Give each function its own definition.
- The Forth dictionary is a giant string case statement. The match and execute functions are hidden within the Forth system.
- Don’t test for something that has already been excluded.
- When multiple conditions have dissimilar weights (in likelihood or calculation time) nest conditionals with the term that is least likely to be true or easiest to calculate on the outside.
- The most elegant code is that which most closely matches the problem. Choose the control structure that most closely matches the control-flow problem.
- Don’t decide, calculate.
- Many times conditional control structures are applied mistakenly to situations in which the difference in outcome results from a difference in numbers.
- A trick is simply taking advantage of certain properties of operation.
- The use of tricks becomes dangerous when a trick depends on something likely to change, or when the thing it depends on is not protected by information hiding.
- Use decision tables.
- A decision table is clearly a better choice than a conditional structure when the problem has multiple dimensions.
- One change at the bottom can save ten decisions at the top.
- Don’t test for something that can’t possible happen.
- Reexamine the algorithm.
- A lot of conditionals arise from fuzzy thinking about the problem.
- Avoid the need for special handling.
- Use the structured exit.
- Fooling with the return stack is like playing with fire. You can get burned.
- Take the action when you know you need to, not later.
- Don’t put off till run time what you can compile today.
- Any time you can make a decision prior to compiling an application, do.
- The use of logic and conditionals as a significant structural element in programming leads to overly-complicated, difficult-to-maintain, and inefficient code.
- Most people go out and attack problems with complicated tools. But simpler tools are available and more useful.
- Forth is expressed in words (and numbers) and is separated by spaces.
- All words, whether included with the system or user-defined, exist in the “dictionary”, a linked list.
- Writing a Forth application consists of building increasingly powerful definitions in terms of previously defined ones.
20190406
Thinking Forth by Leo Brodie
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment