home

about

license

support

K/Base

Indy
HomeContactsSite Map


Source Code Standards

  1. No assembly - Assembly language is prohibited because it will act differently in different platforms. Assembly language is also more prone to errors than Pascal. There are few exceptions but those are done after much discussion, ONLY for specific reasons, and only if they do not compromise cross-platform compatibility.
  2. No Goto Statements - Goto statements are prohibited because they often render code unreadable and encourage spaghetti code. Goto is basically a hold over from GWBASIC and the original basic authors had depreciated that feature because it encouraged sloppy programming.
  3. Always use begin..end - All "if", "while", "for" blocks must include a "begin...end" even if there was only one line of code in the condition. This is required because we often might have to add something else to conditional execution later on. In addition, compound lines (if condition then exit) can cause unexpected jumps during tracing.
  4. Uses in interface section - Unless there is something in a unit's interface which depends on another unit, the unit should be moved to the implementation uses clause. This increases efficiency in the compiler.
  5. Comments of quirks - If there is an odd quirk or bug in an API that an Indy developer is working around, this should be noted in a comment above the relevant code. This is important in case the developer later forgets or someone else has to work on the unit and may not know about the quirk. Remember that people involved with Indy can come and go. This can also be helpful if the reason for the work-around no-longer exists (a bug was fixed in a patch or years later, it is no longer relevant because support for that API was dropped).
  6. Compiler warnings and hints - There should never be any compiler warnings or hints. This is important because some things could have unintended consequences such as operands being widened, code optimized out by the compiler even if the code was doing something necessary, and some people might assume there was some sloppiness and get a bad impression.
  7. Use of ancestor code - If code is used in more than one place, it should be placed in an ancestor class. For example, TIdQuotD and TIdDayTime simply connect to the server and retrieve data until the connection closes. Thus, the TIdTCPClient has a method called ConnectAndGetAll which does this. Thus, the main difference between TIdQuotD and TIdDayTime is simply a name of function and a different default port. This reduces errors and helps optimize code as well as fixing a bug in several places.
  8. No private sections - Nothing in Indy is ever placed in the component's private section. Some things which are not used outside of the component are placed in the protected section so they can be used by descendant classes. In addition, most methods should be virtual so descendant classes can override them if necessary.
  9. Low Level Code - Low level functionality code (such as calling socket function) should not be used directly by high-level classes. They should be accessed through intermediate classes such as TIdSocketHandle. The reason is so that any changes we need at a low level would only require adjustments to the intermediate class's code.
  10. Variable prefixes - Arguments are prefixed with A, unless they are var arguments which are prefixed by V. Member variables are prefixed by F, global variables (not constants) by G, Local variables are prefixed by L, except for general purpose integers (i, j, k, ...) and general purpose strings (s, t, u, ...)
  11. IFDEFs - IFDEFs are normally not permitted in any unit except for System units like IdGlobal. This means that all platform specific code should exist in IdGlobal and IdStack... units only. However, most units do include IdCompilerDefines.inc, which defines a large set of useful DEFINEs, and as Indy grows more complex, IFDEFs in non-System units is sometimes needed.
  12. FreeAndNil - FreeAndNil should always be used, except when it cannot be used. Such cases where it cannot be used are in a with statement that uses a constructor as its object. (with tlist.create do try.... finally Free; end).
  13. Alphabetization - Units in uses clauses are alphabetized (by first letter only). Variables, properties and methods are also alphabetized in the interface and var sections. Methods need not be alphabetized in the implementation section.
  14. TIdBaseComponent - All Indy components descend from TIdBaseComponent or a descendant of TIdBaseComponent. This class does not directly link to any stack functionality so it can be used with components that do not require stack functionality. This removes unnecessary functionality if the user was only using Indy components that do not use stack functionality.
  15. TIdComponent - All Indy components that use socket functionality such as clients and server descend from TIdComponent or a descendant of TIdComponent. This is an ancestor of TIdBaseComponent which links to the stack units and classes.
  16. EIdException - All exceptions must be of type EIdException or a descendant of EIdException. By descending from EIdException, a developer can determine if an exception is related to Indy.
  17. TStream instead of TextFile - In Indy, we use TStreams for most I/O access such as Loading and Saving instead of using things such as TextFile or File types. We do this because the TStream has more options than a typical text file giving the developer the utmost flexibility. By using TStreams as parameters, a user can use the function with data that is already in memory, do things such as compress data, and access files. We also know that there are more TStream descendant classes available which can add even more capability to programs such as buffered input and output. Most routines that access files in Indy directly simply are wrappers for functions that use TStreams.
  18. CLX / VCL Forms in property editors - Starting with Indy 9.0, all property editors use dynamically created forms and controls along with IFDEF's for CLX on Kylix.  This prevents us from having to make a single change in both .DFM and XFM files, prevents some maintenance problems that occur in the Delphi 6 IDE, and provide consistency with older Delphi and C++Builder versions. Example code.
  19. Design time property editors - Starting with Indy 9.0, design-time property editor forms are separate from the component and design-time editors classes and are in separate units.  This permits us to embed the property editor form in a test harness program so we can debug them without design-time unit problems.
  20. Replace AnsiXXX functions - Delphi 8.0 has marked a number of functions prefixed with Ansi as deprecated. Portable replacements have consequently been defined in IdGlobal. Indy 10 code should replace (a) AnsiSameText with TextIsSame, (b) AnsiLowerCase with IndyLowerCase, (c) AnsiUpperCase with IndyUpperCase, (d) AnsiCompareStr with IndyCompareStr, and (e) AnsiPos with IndyPos.
  21. Sets have changed - Delphi 8.0 has changed the way sets are treated; so to avoid warnings, in Indy 10 replace constructs like "if not(Data[i] in ValidChars) then" with "if not CharIsInSet(Data, i, ValidChars) then".
  22. Constants for Seek() offsets have changed - Starting with Delphi 8.0, soBeginning, soCurrent, soEnd now replace soFromBeginning, soFromCurrent, and soFromEnd. These are used in functions such as Seek(). In general, replace Seek() with Position, e.g. replace "TheStream.Seek(0, soFromEnd);" with "TheStream.Position := TheStream.Size" (though there may be a small performance penalty that could be an issue in tightly-coded loops). If you really have to use those constants in Indy 10, replace them with the portable constants IdFromBeginning, IdFromCurrent and IdFromEnd defined in IdGlobal.


Corporate Sponsors

Atozed







home

about

license

support

K/Base

site map

links

Copyright © 1993 - 2008 Chad Z. Hower (Kudzu) and the Indy Pit Crew.          Website design by RuInternet.ru