Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Tools

Pick-a-Number Interfaces


FEB90: PICK-A-NUMBER INTERFACES

Bob designed the first 5-MHz CPU card for the S-100 bus (TEI 1978). He also designed the TEI System 48, the Maxicom DL, and authored the shareware program Onbase. He may be reached c/o Blackbelt Software, P.O. Box 31075, Houston, TX 77035.


In this age of "user friendly" interfaces with pop-up windows, pulldown menus, and a plethora of moving bars in almost every program, you may question why I would write an article about old-fashioned, pick-a-number menus. The answer to that puzzle is that the pick-a-number menu has some powerful subtleties that make it difficult to replace in certain computer applications. Pick-a-number interfaces are the easiest interface for a programmer to write into a program, and they consume the least amount of computer resources. If pick-a-number interfaces are properly coded, people who have no computer experience can use them easily. In addition, these interfaces allow touch typists to work without moving their eyes away from the screen.

I recently had the misfortune to enter a large amount of data into a mailing list program that has all of the modern interface fads -- exploding windows, function keys, moving-bar menus, sound effects, and Yes/No confirmations (which, amusingly, used function keys, instead of the Y or N keys). The programmer obviously had devoted a great deal of time and effort to the interface portion of the program. The reason that I said "misfortune" earlier is that in any programming project to which a given amount of effort is made, the effort expended in glitter and gloss comes at the expense of substance and functionality. With the program in question, the missing functionality was the lack of a means to handle the possibility of a power failure. If a power failure occurred while you were adding data to the mailing list, all of the data in the mailing list would be lost. In addition, if you exited the program without manually closing the database, all of the data that was ever entered into the program would be lost. The only way to back up the data was to use the user manual to close the file, and then copy the data file to a different file name.

Now I'm not about to claim that the addition of a pick-a-number interface to this program would have solved the program's problems. My earlier comment about the trade-offs that can be made when the level of effort is fixed is true, but it is also true that all too often, the level of effort is not fixed. Given an easier interface to write, the programmer simply lowers the level of effort that is devoted to the program. Nevertheless, programmers who change to a simpler user interface gain more time to at least consider what they are doing with the rest of the program.

Programmers write complicated user interfaces for a number of reasons. For one thing, a fancier interface is more challenging to write, so many programmers find it more interesting to code. A three-ring-circus-style interface is useful for impressing compu-boobs, and may, in some cases, sell lots of programs. Most programmers don't understand what user friendly means, so they assume that it means something that dazzles the eye. Finally, a trendy, faddish program interface makes the software look modern and up-to-date.

Pick-a-number interfaces are appropriate in the following circumstances: 1. You are writing a custom program for a business, and the program will be used by people who are interested in the program's utility, not in how flashy the program appears; 2. The code will be used by many people who may not be sophisticated computer users; 3. The amount of time needed to build the finished program is important; 4. Computer resources are limited; 5. Speed and error prevention are important in the program.

Pick-a-number interfaces are not appropriate in the following cases: 1. The program is intended for use by management personnel who fancy themselves as "computer literati" and who request other interfaces; 2. The program is game software, where glitter and gloss is the whole purpose; 3. You are trying to impress someone with your programming skill; 4. Your program really doesn't do much, so it is necessary to cover up this fact; 5. You are developing a program for commercial distribution, and the marketing people insist upon a different interface.

The 80/20 Percent Rule

Granted, it is possible to write a clumsy user interface in any technology. Despite the fact that the interface of the mailing list program mentioned earlier offered all of the leading-edge ways of doing things, the interface was awkward and slow to use. I generally had to step through three levels of moving bars in order to do what I wanted to do -- just enter data and print mailing lists. Of course, this awkwardness is also true of most pick-a-number interfaces. Generally, programmers require users to wade through pages of menus before the users are allowed to do what they want to do. The reason for this phenomenon is that it is just as difficult to write code that is rarely used in the program as it is to write code that will be used often. As a result, programmers give equal importance in the user interface to both often-used and rarely used options.

When the term "user friendly" is applied to a program, it means that the program usually does just what the user wants it to do with a minimum amount of fuss and bother on the user's part. The application of the "80/20 percent rule" to menu design is an important part of creating a user-friendly program. You should determine what will be done with the program 80 percent of the time, and then devote menu options that accomplish exactly these functions to the 20 percent of the code that will perform them. Then place the most-used options at the front of the menu The menu shown in Example 1 illustrates this approach. (The code that generates this menu is shown in Listing One , page 100.) Most of the time, the user will pick either option 1 or option 2, which handle the primary functions of the mailing list program.

Example 1: In pick-a-number interfaces, the most commonly used options should be available early in the menu

            Mailing List Menu
   (Press Esc key to leave program)

  1. Enter new mail list data
  2. Print a Zip code sorted mail list
  3. Change existing data
  4. Delete a single address from the list
  5. Browse through the existing data
  6. Backup data
  7. Print a mail list not sorted by Zip
  8. Perform other functions

  Enter the number of your selection and
  press Enter key:

This 80/20 design rule leads to a program that users usually enjoy working with because it usually does just what they want to do with a minimum amount of bother. Also, following this rule results in a program that requires a minimum amount of training for the people who use it. I have found it far easier to teach people how to use a program designed in this fashion, than to show them how to use a bell-and-whistle-style interface. Virtually anyone who can read can learn how to use a program that is designed according to the 80/20 rules. I maintain that successfully learning how to use a program that is driven by a moving bar or by function keys requires a bit more computer experience.

One interesting aspect of the menu in Example 1 is the requirement that the user must press the Enter key after a menu selection is entered. When I first began coding menus into programs, I designed the programs so that the requested function was performed without requiring the user to press the Enter key. This approach limited the size of the menu to only ten functions (0..9). In addition, the users were uncertain about whether or not the computer was active.

The issue of consistency in data input is also related to this Enter key issue. I have found it vital to always require that input into a data field be followed by a press of the Enter key. If you allow a user to skip automatically to the next field when a field fills up, but you require the user to press the Enter key only if the field is not filled, then the preprocess of data entry requires constant, conscious checking on the part of the person who enters the data. Additionally, the cursor can be placed in the wrong data field if the user tries to enter more data than a field can hold.

Data entry can never become a subconscious, automatic task because the speed of data entry is limited. Subconscious tasks are executed much more quickly by the user than are conscious tasks, and the limited data entry speed places a higher level of stress on the data entry personnel. Imagine the stress that would occur during the process of driving if stopping the car sometimes required you to press the brake pedal, and other times (if, for example, the car in front of you weighed more than 3,800 pounds) you had to twist the rearview mirror without pressing the brake pedal. It may appear wasteful to always require the user to press the Enter key after data entry in each field is finished, but the technique both substantially speeds up the data entry process and increases the program's ease of use.

Pick-A-Number Code

I am basically a lazy programmer who wants the computer to do as much of the grunt work as possible, so I wrote code that automates the process of centering and dividing menu data into columns, and provides error rejection during user input. (As Robert Heinlein said, "Progress is not made by early risers, it is made by lazy people looking for an easier way of doing something.") The code that implements these functions is written in Modula-2 and has been tested with the Logitech Modula-2 compiler (Version 3.0). The process of converting this code so that it can run with other Modula compilers will probably be straightforward.

The procedure Grab in the module READA (Listings Two and Three, page 100) is a general-purpose data-field entry routine that requires a press of the Enter key after a data field is filled. An alarm sounds if an attempt to overflow the field is made. The procedure Menu in the module MENU ( Listings Four and Five, pages 101 and 102) implements pick-a-number interfaces for menus that contain up to 60 entries. This procedure centers the menu items on the screen, and divides the menu entries so that they occupy from one to four columns for display.

_PICK-A-NUMBER INTERFACES_ by Bob Canup

[LISTING ONE]

<a name="0061_0008">

MODULE Mtest ;
FROM MENU IMPORT MenuType,Menu ;
FROM InOut IMPORT WriteString, WriteLn ;
PROCEDURE CLS ;
BEGIN
   WriteString(CHR(12)) ;
END CLS ;

PROCEDURE Header ;
BEGIN
   WriteLn ;
   WriteLn ;
   WriteLn ;
   WriteLn ;
   WriteString('                     M A I L I N G   L I S T   M E N U') ;
   WriteLn ;
   WriteString('                      (Press Esc key to leave progam)') ;
END Header ;

PROCEDURE EnterData ;
END EnterData ;
PROCEDURE PrintZip ;
END PrintZip ;
PROCEDURE Modify ;
END Modify ;
PROCEDURE DelData ;
END DelData ;
PROCEDURE Browse ;
END Browse ;
PROCEDURE Backup ;
END Backup ;
PROCEDURE PrintNZip ;
END PrintNZip ;
PROCEDURE Setup ;
END Setup ;
PROCEDURE test ;
VAR
   test   : MenuType ;
   i   : CARDINAL ;
BEGIN
   LOOP
      CLS ;
      Header ;
      test[0] := '1. Enter new mail list data.' ;
      test[1] := '2. Print a Zip code sorted mail list.' ;
      test[2] := '3. Change existing data.' ;
      test[3] := '4. Delete a single address from the list.' ;
      test[4] := '5. Browse through the existing data.' ;
      test[5] := '6. Backup data.' ;
      test[6] := '7. Print a mail list not sorted by ZIP.' ;
      test[7] := '8. Perform other functions.' ;
      i := Menu(test,8) ;
      CASE i OF
         0 : EXIT      |
         1 : EnterData |
         2 : PrintZip  |
         3 : Modify    |
         4 : DelData   |
         5 : Browse    |
         6 : Backup    |
         7 : PrintNZip |
         8 : Setup
      END ; (* CASE *)
   END ; (* LOOP *)
END test ;
BEGIN
   test ;
END Mtest.




<a name="0061_0009"><a name="0061_0009">
<a name="0061_000a">
[LISTING TWO]
<a name="0061_000a">

DEFINITION MODULE READA;
(* EscType determines whether an esc will exit a field. The values are:
   Esc   which allows an escape to exit a field.
   NoEsc which prevents exit from a field on an escape char entry.
*)
FROM SYSTEM IMPORT AX,BX,CX,DX,BP,CODE,SETREG ;
FROM Terminal IMPORT Write ;
FROM InOut IMPORT EOL ;
   EXPORT QUALIFIED Grab, ClearField, gotoxy, EscType ;
TYPE
     EscType = (Esc,NoEsc) ;
     PROCEDURE Grab(VAR String : ARRAY OF CHAR ; EscFlag :EscType) ;
     PROCEDURE ClearField(VAR String : ARRAY OF CHAR ; Column,Row : CARDINAL);
     PROCEDURE gotoxy(x,y : CARDINAL ) ;
END READA.




<a name="0061_000b"><a name="0061_000b">
<a name="0061_000c">
[LISTING THREE]
<a name="0061_000c">

(***************************************************************************
    Name: READA
   Purpose: Usefull String routines
      ClearField wipes out a data entry field on screen
      Grab accepts characters up to length of length of string array
      then refuses to accept any more chars until Enter is pressed.
      gotoxy positions the cursor.
   Entry: ClearField(VAR String: ARRAY OF CHAR ; Column,Row : CARDINAL)
          Grab(VAR String:ARRAY OF CHAR ; EscFlag : EscType)
          gotoxy(x,y : CARDINAL) x = column y = row.
   Exit: ClearField - String is zeroed, cursor left at position Column,Row
         Grab - String is filled in with user entered characters.
   Global Variables used: Passed String array.
   Revision number:
   1.2   10/3/88   Escape type added to Grab.
   1.1   11/30/87  Escape key exit for String 0.
   1.0   11/8/87
****************************************************************************)

IMPLEMENTATION MODULE READA ;
FROM SYSTEM IMPORT AX,BX,CX,DX,BP,CODE,SETREG ;
FROM Terminal IMPORT Write, Read ;
FROM InOut IMPORT EOL ;
VAR
   Index   : CARDINAL ;
   Ch   : CHAR ;
PROCEDURE gotoxy(x,y : CARDINAL ) ;
VAR
   a : CARDINAL ;
BEGIN
   IF ( x >= 0) AND ( x <= 79) AND ( y >=0) AND ( y <=24) THEN
      IF ( x # 79) OR (y # 24 )
      THEN
      CODE( 55H) ;      (* PUSH BP *)
      a := 200H ;
      SETREG ( AX ,a ) ;
      CODE( 50H ) ;      (* PUSH AX *)
      a := 0H ;
      SETREG( BX , a) ;
      CODE( 53H) ;      (* PUSH BX *)
      SETREG( DX,x + 256 * y) ;
      CODE( 5BH ) ;      (* POP BX *)
      CODE( 58H ) ;      (* POP AX *)
      CODE( 0CDH,10H) ;   (* INT 10H *)
      CODE( 5DH ) ;      (* POP BP *)
      END ;
   END ;
END gotoxy ;

PROCEDURE ClearField(VAR String : ARRAY OF CHAR ; Column,Row : CARDINAL) ;
(* This procedure wipes the appropriate field on the screen out *)
BEGIN
   gotoxy(Column,Row) ;   (* Position Cursor *)
   FOR Index := 0 TO HIGH(String) DO
      Write(' ') ;
   END ;   (* FOR *)
   gotoxy(Column,Row) ;   (* Reposition Cursor *)
END ClearField ;

PROCEDURE Grab(VAR String : ARRAY OF CHAR ; EscFlag : EscType ) ;

(* This procedure assumes that the cursor has already been moved to a position
either by a direct gotoxy call or by a call to ClearField *)

BEGIN
   FOR Index := 0 TO HIGH(String) DO
      String[Index] := CHR(0) ;
   END ; (* FOR *)
   Index := 0 ;
   LOOP
      Read(Ch) ;
      IF Ch = EOL THEN EXIT END ;
      IF EscFlag = Esc THEN
         IF Ch = CHR(27) THEN
            String[0] := Ch ;
            EXIT ;
         END ;
      END ;
      IF Ch = CHR(8) THEN
         IF Index = 0 THEN
            Write(CHR(7)) ;   (* Honk at Barney *)
         ELSE
            Write(CHR(8)) ;   (* BackSpace *)
            Write(CHR(32)) ;   (* Space *)
            Write(CHR(8)) ;   (* BackSpace *)
            Index := Index - 1 ;
            String[Index] := CHR(0) ;
         END ; (* IF *)
      ELSIF Ch < CHR(32) THEN
         Write(CHR(7)) ;   (* Honk at Barney *)
      ELSE
         IF Index = (HIGH(String) +1) THEN
            Write(CHR(7)) ;
         ELSE
            String[Index] := Ch ;
            Write(Ch) ;
            Index := Index + 1 ;
         END ; (* IF *)
      END ; (* IF *)
   END ; (* LOOP *)
END Grab ;
END READA .




<a name="0061_000d"><a name="0061_000d">
<a name="0061_000e">
[LISTING FOUR]
<a name="0061_000e">

DEFINITION MODULE MENU ;
  EXPORT QUALIFIED MenuType,Menu ;
  TYPE MenuType = ARRAY[0..59],[0..79] OF CHAR ;
  PROCEDURE Menu(VAR A : MenuType ; NumberOfMenuEntries : CARDINAL) :CARDINAL ;
END MENU.




<a name="0061_000f"><a name="0061_000f">
<a name="0061_0010">
[LISTING FIVE]
<a name="0061_0010">

(**************************************************************************
Name: MENU
Purpose: Automatic screen layout, and response error checking for
   Pick-a-number menus.
Entry: Menu(VAR A : MenuType ; NumberOfMenuEntries : CARDINAL): CARDINAL ;
Exit: Qualified acceptance of menu item or escape key.
Revision Number:
1.1   10/3/88 Escape key output changed to = 0
1.0   9/26/88
***************************************************************************)

IMPLEMENTATION MODULE MENU ;
FROM READA IMPORT gotoxy, Grab,EscType ;
FROM Strings IMPORT Length ;
FROM NumberConversion IMPORT StringToCard ;
FROM InOut IMPORT WriteString ;

PROCEDURE OneColumn(VAR A : MenuType ; i : CARDINAL) ;
VAR
   j,k,l,m : CARDINAL ;
BEGIN
   i := i - 1 ; (* Convert from one base to zero based *)
   (* First we center the strings to be displayed vertically *)
   j := (5 + ((15 - i) DIV 2)) ;
   (* Now we center the strings horizontally *)
   l := 0 ;
   FOR m := 0  TO i DO
      k := Length(A[m]) ;
      IF (k > l) THEN l := k END ; (* get longest string length *)
   END ; (* FOR *)
   k := (40 -(l DIV 2)) ;

   (* Now print the menu *)
   FOR m := 0 TO i DO
      gotoxy(k,(j+m)) ; (* Position cursor to string position *)
      WriteString(A[m]) ;
   END ; (* FOR *)
END OneColumn ;

PROCEDURE TwoColumns(VAR A : MenuType ; i : CARDINAL) ;
VAR
   j,k,l,m,n,o,p : CARDINAL ;
BEGIN
   (* First we center the strings to be displayed vertically *)
   i := i - 1 ;    (* Convert from one base to zero based *)
   n := i DIV 2 ;
   j := (5 + ((15 - n) DIV 2)) ;
   (* Now we center the strings horizontally *)
   l := 0 ;
   FOR m := 0  TO n-1 DO
      k := Length(A[m]) ;
      IF (k > l) THEN l := k END ; (* get longest string length *)
   END ; (* FOR *)
   k := (20 -(l DIV 2)) ;
(* Now set up the second column centered on position 60 *)
   o := 0 ;
   FOR m := n   TO i DO
      p := Length(A[m]) ;
      IF (p > o) THEN o := p END ; (* get longest string length *)
   END ; (* FOR *)
   p := (60 -(o DIV 2)) ;

   (* Now print the menu *)
   FOR m := 0 TO n-1 DO
      gotoxy(k,(j+m)) ; (* Position cursor to string position *)
      WriteString(A[m]) ;
   END ; (* FOR *)
   FOR m := n TO i DO
      gotoxy(p,(j+m-(n))) ; (* Position cursor to string position *)
      WriteString(A[m]) ;
   END ; (* FOR *)

END TwoColumns ;

PROCEDURE ThreeColumns(VAR A : MenuType ; i : CARDINAL) ;
VAR
   j,k,l,m,n,o,p,q,r : CARDINAL ;
BEGIN
   (* First we center the strings to be displayed vertically *)
   i := i - 1 ;    (* Convert from one base to zero based *)
   n := i DIV 3 ;
   j := i MOD 3 ;
   IF j = 2 THEN INC(n) END ;
   j := (5 + ((15 - n) DIV 2)) ;
   (* Now we center the strings horizontally *)
   l := 0 ;
   FOR m := 0  TO n-1 DO
      k := Length(A[m]) ;
      IF (k > l) THEN l := k END ; (* get longest string length *)
   END ; (* FOR *)
   k := (20 -(l DIV 2)) ;
(* Now set up the second column centered on position 40 *)
   o := 0 ;
   FOR m := n  TO (2*n)-1 DO
      p := Length(A[m]) ;
      IF (p > o) THEN o := p END ; (* get longest string length *)
   END ; (* FOR *)
   p := (40 -(o DIV 2)) ;
(* Now set up the third column centered on position 60 *)
   q := 0 ;
   FOR m := 2*n   TO i DO
      r := Length(A[m]) ;
      IF (r > q) THEN q := r END ; (* get longest string length *)
   END ; (* FOR *)
   r := (60 -(q DIV 2)) ;

   (* Now print the menu *)
   FOR m := 0 TO n-1 DO
      gotoxy(k,(j+m)) ; (* Position cursor to string position *)
      WriteString(A[m]) ;
   END ; (* FOR *)
   FOR m := n TO 2*n-1 DO
      gotoxy(p,(j+m-n)) ; (* Position cursor to string position *)
      WriteString(A[m]) ;
   END ; (* FOR *)
   FOR m := 2*n TO i DO
      gotoxy(r,(j+m-2*n)) ; (* Position cursor to string position *)
      WriteString(A[m]) ;
   END ; (* FOR *)
END ThreeColumns ;

PROCEDURE FourColumns(VAR A : MenuType ; i : CARDINAL) ;
VAR
   j,k,l,m,n,o,p,q,r,s,t : CARDINAL ;
BEGIN
   (* First we center the strings to be displayed vertically *)
   i := i - 1 ;    (* Convert from one base to zero based *)
   n := i DIV 4 ;
   j := i MOD 4 ;
   IF j = 3 THEN INC(n) END ;
   j := (5 + ((15 - n) DIV 2)) ;
   (* Now we center the strings horizontally *)
   l := 0 ;
   FOR m := 0  TO n-1 DO
      k := Length(A[m]) ;
      IF (k > l) THEN l := k END ; (* get longest string length *)
   END ; (* FOR *)
   k := (16 -(l DIV 2)) ;
(* Now set up the second column centered on position 40 *)
   o := 0 ;
   FOR m := n   TO 2*n-1 DO
      p := Length(A[m]) ;
      IF (p > o) THEN o := p END ; (* get longest string length *)
   END ; (* FOR *)
   p := (32 -(o DIV 2)) ;
(* Now set up the third column centered on position 60 *)
   q := 0 ;
   FOR m := 2*n   TO 3*n-1 DO
      r := Length(A[m]) ;
      IF (r > q) THEN q := r END ; (* get longest string length *)
   END ; (* FOR *)
   r := (48 -(q DIV 2)) ;
   s := 0 ;
   FOR m := 3*n   TO i DO
      t := Length(A[m]) ;
      IF (t > s) THEN s := t END ; (* get longest string length *)
   END ; (* FOR *)
   t := (64 -(s DIV 2)) ;

   (* Now print the menu *)
   FOR m := 0 TO n-1 DO
      gotoxy(k,(j+m)) ; (* Position cursor to string position *)
      WriteString(A[m]) ;
   END ; (* FOR *)
   FOR m := n TO 2*n-1 DO
      gotoxy(p,(j+m-(n))) ; (* Position cursor to string position *)
      WriteString(A[m]) ;
   END ; (* FOR *)
   FOR m := 2*n TO 3*n-1 DO
      gotoxy(r,(j+m-(2*n))) ; (* Position cursor to string position *)
      WriteString(A[m]) ;
   END ; (* FOR *)
   FOR m := 3*n TO i DO
      gotoxy(t,(j+m-(3*n))) ; (* Position cursor to string position *)
      WriteString(A[m]) ;
   END ; (* FOR *)
END FourColumns ;

PROCEDURE Menu(VAR A : MenuType ; NumberOfMenuEntries : CARDINAL): CARDINAL ;
VAR
   i,j,k,l   : CARDINAL ;
   input   : ARRAY[0..1] OF CHAR ;
   done   : BOOLEAN ;
BEGIN
(* 'A' is actually an array of character strings ( an array of array of char)
Menu displays 'A' and waits for up to a two character response with a trailing
carriage return. Menu returns 100 if escape is pressed, otherwise returns
number entered by user as menu response.(0..60).
*)
   i := NumberOfMenuEntries ;
   IF (i <= 15 ) THEN OneColumn(A,i) END ;
   IF ((i > 15) AND (i <= 30)) THEN TwoColumns(A,i) END ;
   IF ((i > 30) AND (i <= 45 )) THEN ThreeColumns(A,i) END ;
   IF (i > 45) THEN FourColumns(A,i) END ;
   (* Allow a maximum of 15 items per column on displayed menu.*)
  LOOP
    gotoxy(5,24) ;
    WriteString('Enter the number of your selection and press Enter key:   ') ;
    WriteString(CHR(08)) ;
    WriteString(CHR(08)) ;
    Grab(input,Esc) ;
(* If Esc is pressed instead of a number exit with an impossible  value *)
      IF (input[0] = CHR(27)) THEN RETURN 0 END ;
      StringToCard(input,j,done) ;
(* Return only legal values of input *)
      IF done THEN
         IF (j > 0) AND ( j <=i) THEN RETURN j END ;
      END ; (* IF *)
   END ; (* LOOP *)
END Menu ;
END MENU .










Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.