Recent from talks
All channels
Be the first to start a discussion here.
Be the first to start a discussion here.
Be the first to start a discussion here.
Be the first to start a discussion here.
Welcome to the community hub built to collect knowledge and have discussions related to Clipper (programming language).
Nothing was collected or created yet.
Clipper (programming language)
View on Wikipediafrom Wikipedia
Not found
Clipper (programming language)
View on Grokipediafrom Grokipedia
Clipper is a procedural, imperative programming language and compiler belonging to the xBase family, primarily designed for creating database-driven business applications.[1] Originally developed by Nantucket Corporation and released in 1985 as a tool to compile code from the dBase III database management system into fast, standalone executables, it extended dBase's capabilities with improved performance and additional programming constructs.[2]
The language originated from Nantucket's efforts to address the demand for a native compiler for dBase, with its first version, Clipper Winter '84, shipping on May 25, 1985.[3] Early seasonal releases, such as Summer '85 and Summer '87, quickly gained market share by offering enhanced flexibility, including the ability to link with C code and support for larger applications, running on DOS systems with at least 256 KB of RAM.[3] In 1990, Clipper 5.0 introduced rudimentary object-oriented features, though it faced criticism for bugs; subsequent patches and versions like 5.2 (1993) and 5.3 (1995) from Computer Associates—following their 1992 acquisition of Nantucket—added refinements such as better database utilities and linker support.[2][3]
Key features of Clipper include a runtime library (RTL) for database operations, an interactive fullscreen debugger, and utilities for tasks like report generation, SQL query processing, and file browsing, making it suitable for corporate data management and screen-based interfaces.[1] Later versions incorporated mouse support, query optimization for efficient data filtration, and compatibility with graphical elements, though it remained oriented toward character-mode DOS environments.[1] While Clipper's development ended with patch 5.3b in 1997, its influence persists through open-source successors like Harbour, which modernize the xBase syntax for contemporary platforms.[1]
This grows the array by one element each time, inserting the specified value (or NIL if omitted) at the end.[23]
Codeblocks provide a mechanism for creating anonymous, executable code snippets akin to closures, enabling dynamic behavior in loops, callbacks, or evaluations. The syntax encloses parameters after a pipe symbol within curly braces, followed by the expression, as in
This allows passing custom logic to functions like AEval() for array processing without defining full procedures.[24][13]
TO command builds an index file based on a key expression, such as INDEX ON upper(custname) TO custndx, ordering records alphabetically by customer name. Clipper supports up to 99 tags in a compound index file (CDX), with the controlling index set via SET INDEX TO.[28][29][30]
For relational operations, Clipper employs SET RELATION to link parent and child work areas, automatically skipping to matching records in the child file as the parent moves. For example, after opening orders in work area 1 and details in work area 2, SET RELATION TO orders->orderid INTO details connects them by order ID, enabling master-detail navigation without explicit joins in code. The JOIN command merges two files into a new DBF based on a FOR condition, as in USE customers; USE invoices; JOIN WITH invoices TO purchases FOR custid = customers->custid, creating a Purchases.dbf with combined fields for reporting. This approach simulates relational joins programmatically.[31][32]
File input/output extends beyond DBF to sequential and random access for text (TXT) and printer (PRN) files using low-level functions. FOPEN(, ) opens a file handle for reading (mode 1) or writing (mode 2), followed by FREAD(, @, ) to read data into a buffer or FWRITE for output. For example, to read a TXT file: nHandle := FOPEN("data.txt", 1); cData := space(1024); nRead := FREAD(nHandle, @cData, 1024); FCLOSE(nHandle). The COPY TO [DELIMITED|SDF] command exports DBF data to TXT with customizable delimiters, while PRN support directs output to printers via SET PRINTER TO.[33][34]
Multi-user environments rely on locking mechanisms to prevent data conflicts: FLOCK() attempts a file-level lock, returning true if successful, while LOCK attempts a record lock on the current record. In network setups, operations like APPEND BLANK or REPLACE trigger automatic locks, with UNLOCK releasing them; failure to lock prompts retries or errors. This ensures data integrity in shared DBF files.[13]
Clipper provides SQL-like querying through DBF functions rather than a full SQL engine, using LOCATE FOR to search records and CONTINUE to find subsequent matches. For example, LOCATE FOR amount > 1000 scans the current index or natural order, positioning the pointer on the first match. More complex filters use SET FILTER TO, applying conditions across work areas. Full SQL support arrived only in later versions via replaceable database drivers (RDDs), but core Clipper emphasizes procedural navigation over declarative queries.
Error handling in file operations uses the ERRORBLOCK() function to set a code block that intercepts runtime errors, such as file-not-found (error 1001) or lock failures (error 32). For instance, a handler might check the Error object's arguments: IF oError:genCode() == 32; ALERT("Record locked"); ENDIF, allowing recovery like retrying the operation or closing files with CLOSE ALL. This prevents abrupt termination during I/O failures.[35][36]
... [ELSEIF ...] [ELSE ...] ENDIF, where control passes to the first true condition or the ELSE block if none match, then proceeds after ENDIF. This construct supports nesting and is semantically equivalent to DO CASE...ENDCASE for simple binary decisions. For multi-way branching, DO CASE...ENDCASE evaluates successive CASE conditions until one is true, executing its statements until the next CASE or ENDCASE; an optional OTHERWISE clause handles unmatched cases. Syntax: DO CASE CASE ... [CASE ...] [OTHERWISE ...] ENDCASE, allowing unlimited cases without performance penalties from nesting multiple IFs.[37][38]
Looping constructs facilitate repetition: DO WHILE...ENDDO executes a block while a condition remains true, checking the condition before each iteration and supporting EXIT to terminate early or LOOP to skip to the next check. Syntax: [DO] WHILE ... [EXIT] [LOOP] ENDDO, commonly used for indefinite iterations like processing until a file ends. FOR...NEXT provides counter-controlled loops, incrementing (or decrementing with STEP) a counter from start to end values. Syntax: FOR := TO [STEP ] ... [EXIT] [LOOP] NEXT, ideal for fixed iterations such as array traversal, with the counter reevaluated each time. A representative example for database record processing is: DO WHILE !EOF()
User-defined functions and procedures modularize code, with FUNCTION declaring a return-value subprogram and PROCEDURE a void one. FUNCTION syntax: [STATIC] FUNCTION [()] [LOCAL/STATIC/MEMVAR declarations] RETURN , where parameters are passed by value (or reference with @), locals are scoped to the function, and RETURN mandates a value of any type. Procedures use similar syntax: [STATIC] PROCEDURE [()] [declarations] [RETURN], returning NIL implicitly and invoked via DO or () syntax. Both support recursion, parameter skipping (checked via NIL or PCOUNT()), and static scoping for file-local visibility; parameters are formal locals receiving arguments. For instance, a simple FUNCTION might compute: FUNCTION Add(nA, nB) RETURN nA + nB, called as Add(3, 4).[17][18]
Error handling employs BEGIN SEQUENCE...END for structured exception management, akin to try-catch, capturing runtime errors or explicit BREAKs. Syntax: BEGIN SEQUENCE ... [BREAK []] [RECOVER [USING ]] ... END SEQUENCE, where an error or BREAK branches to RECOVER (optionally assigning the error object to via USING), allowing recovery code like logging or retrying with LOOP; unhandled cases proceed to END. This integrates with the global ERRORBLOCK() for custom handlers but provides local control without halting execution.[41]
Clipper programs are structured as .prg source files containing these constructs within a main procedure or called subroutines, compiled via CLIPPER.EXE to intermediate .obj files embedding runtime code and library references, then linked (e.g., with BLINKER) into executables; early versions lacked native modules, relying on explicit linking for multi-file projects.[42]
Overview
Origins and Relation to dBase
Clipper was developed in 1985 by Nantucket Corporation, a company founded by Barry ReBell and Brian Russell, specifically as a compiler for dBase III, Ashton-Tate's popular database management system.[4] The idea originated from discussions between ReBell, a consultant, and Russell, an Ashton-Tate employee, who recognized the limitations of dBase III's interpreted execution and the need for a tool to compile its code into more efficient standalone applications.[4] Nantucket's first version, known as Clipper Winter '84, shipped on May 25, 1985, targeting MS-DOS systems and enabling developers to transform dBase scripts into executable programs without runtime dependencies on the dBase interpreter.[5] This compilation capability addressed key shortcomings in dBase III, which relied on interpretive processing that limited performance in demanding business environments, such as inventory management and accounting software.[6] By generating native code executables, Clipper significantly improved runtime speed and allowed for larger, more robust database-driven applications, making it a vital extension for professional developers working in the xBase ecosystem.[6] Nantucket marketed early versions, including the Summer '87 release in December 1987, as fully compatible dBase III compilers, emphasizing their role in streamlining the creation of deployable business programs.[5] At its core, Clipper implemented a superset of dBase III syntax, preserving the original's database commands and logic while introducing procedural programming elements that were absent in the base system, such as user-defined functions, arrays, and enhanced control structures.[7] This extension aligned with Nantucket's philosophy of empowering developers with unrestricted tools, allowing seamless migration of dBase code while adding capabilities for modular and efficient application development.[6]Core Design Principles
Clipper is fundamentally a procedural and imperative programming language, designed to provide high-level abstractions tailored for database-centric applications. It emphasizes structured programming through constructs such as user-defined functions, procedures, and control structures like DO WHILE loops, FOR...NEXT iterations, IF...ENDIF conditionals, and DO CASE...ENDCASE cases, enabling developers to build modular, sequential logic without low-level system management. This paradigm prioritizes ease of use for business application development, where database operations form the core workflow, allowing programmers to focus on data manipulation rather than underlying hardware details.[6] A primary design goal of Clipper was to maintain compatibility with dBase syntax and semantics while introducing compilation capabilities to enhance efficiency and portability across DOS platforms. By emulating dBase III PLUS commands and file formats, such as DBF databases and NDX/NTX indexes, Clipper allows seamless migration of existing dBase scripts into compiled executables, but it verifies and optimizes code during compilation to produce standalone .EXE files that run faster than interpreted dBase sessions. This compilation process targets MS-DOS 2.0 or later systems (with 3.1+ for networks), requiring minimal resources like 256K RAM, and supports cross-platform deployment through standardized DOS calls and configurable runtime environments, ensuring applications function consistently without platform-specific adjustments.[6] Central to Clipper's architecture is the use of bundled runtime libraries to create self-contained applications that do not rely on the dBase runtime environment. Libraries such as CLIPPER.LIB for core functions, EXTEND.LIB for advanced database and UI features (e.g., screen handling with @...SAY...GET and printing utilities), and OVERLAY.LIB for memory management enable developers to link all necessary components into a single executable, supporting up to 255 open files and features like error handling via ERRORSYS.PRG.[6] This approach eliminates external dependencies, allows royalty-free distribution, and facilitates robust, standalone deployment for database-driven tasks. While the core language remains function-based, relying on global variables and a rich set of built-in functions for operations like file locking (FLOCK(), RLOCK()) and data processing (SEEK(), EOF()), Clipper 5.0 introduced rudimentary object-oriented features, including support for classes and methods, while the Extend System enabled integration with C and assembly code for modular extensions.[8][9]Development and Version History
Nantucket Corporation Era
Nantucket Corporation was founded in 1984 by Barry ReBell and Brian Russell with the goal of creating a compiler for Ashton-Tate's dBase III database management system, addressing its limitations in speed and functionality for application development.[10] The company's inaugural product, Clipper, debuted as the Winter '84 version on May 25, 1985, functioning as a native code compiler that transformed dBase III scripts into efficient, standalone executables for DOS environments.[5] Early Clipper releases adhered to a distinctive seasonal naming scheme, reflecting the company's California roots. These included Summer '85, Winter '85 (released January 29, 1986), Autumn '86 (October 31, 1986), and culminated in Summer '87 (December 21, 1987), which introduced version numbering starting at 5.0 and switched to a more efficient C compiler for improved performance.[5] Subsequent updates under Nantucket, such as 5.01 (April 15, 1991), continued to refine the toolset while maintaining compatibility with dBase standards. Key innovations during this period enhanced Clipper's capabilities beyond basic dBase compilation. The Autumn '86 release added network support and expanded file handling, including DBF files for structured data and DBT files for memo fields, enabling better integration with multi-user environments.[5] Clipper 5.0 (1990) introduced local variables for scoped data management within procedures and functions, reducing global namespace pollution, alongside multi-module compilation via dynamic overlays in the RTlink system, allowing larger applications to be built from multiple source files without exceeding memory limits.[5] Nantucket's independent development of Clipper concluded in June 1992, when the corporation was acquired by Computer Associates International for approximately $190 million, shifting control and future enhancements to the larger entity.[11]Computer Associates Acquisition and Evolution
In June 1992, Computer Associates International Inc. acquired Nantucket Corporation, the original developer of the Clipper compiler, to bolster its position in the xBase software market and integrate Clipper with its existing database tools like CA-dBFast.[12] The acquisition, valued for Nantucket's expertise in database development environments, led to the rebranding of the product as CA-Clipper and a shift from Nantucket's seasonal naming convention (e.g., Summer '87) to a numbered versioning system starting with CA-Clipper 5.01a later that year.[12][3] Under Computer Associates' ownership, CA-Clipper saw continued evolution with the release of version 5.2 in February 1993, which included refinements to the replaceable database driver (RDD) architecture for better extensibility, followed by bug-fix updates up to 5.2e in February 1995.[3] The pivotal CA-Clipper 5.3 arrived in June 1995, introducing object-oriented programming capabilities through class definitions, inheritance, and methods, while maintaining backward compatibility with procedural code; this allowed developers to create more modular applications without a full paradigm shift, as CA-Clipper was not positioned as a purely object-oriented language.[13][14] Version 5.3 also added native GUI elements such as buttons, list boxes, and check boxes via the LightLib library, enabling basic graphical interfaces in DOS environments and paving the way for integration with CA-Visual Objects, a Windows-native successor released in 1995 that supported ODBC and SQL database connectivity for enterprise applications.[13][15] Additionally, 5.3 enhanced SQL connectivity through extended RDD support and database engines compatible with SQL servers, facilitating hybrid dBase-SQL workflows.[13] Subsequent maintenance releases included CA-Clipper 5.3a in May 1996 and the final commercial version, 5.3b, in May 1997, which focused on stability and minor optimizations without major new features.[3] Efforts during this era included pilot projects for Windows compatibility, aiming to port DOS-based Clipper applications to 16-bit Windows environments, though these were limited in scope and ultimately transitioned into the full Windows development framework of CA-Visual Objects rather than a direct Clipper upgrade.[12][15] By the late 1990s, as Computer Associates prioritized enterprise and mainframe software solutions over PC-based tools, CA-Clipper received diminished support, reflecting the company's broader strategic shift toward larger-scale systems management products.[11] This de-emphasis culminated in 2002 when CA sold the Clipper source code to GrafX Software Development Tools, Inc., ending active commercial development.[16]Language Features
Syntax and Data Types
Clipper's syntax derives from the xBase family, featuring a straightforward, English-like structure that emphasizes readability for database-oriented programming. The language is case-insensitive, meaning commands, functions, and keywords can be written in uppercase, lowercase, or mixed case without affecting execution. Statements and commands typically conclude at the end of a line, with semicolons being optional and rarely used except in specific contexts like multi-line strings in functions such as Alert(). User-defined functions are declared using the FUNCTION keyword followed by the function name and optional parameter list, while procedures—subroutines that do not return values—are defined with the PROCEDURE keyword in a similar manner. For instance, a simple function might begin asFUNCTION AddNumbers(n1, n2) and end with RETURN n1 + n2.[17][18][13]
Clipper employs dynamic typing, where variables do not require explicit type declarations; their data types are determined at runtime based on assigned values, with implicit conversions occurring as needed—for example, a numeric value assigned to a character variable results in string conversion. The supported data types include Character for strings (enclosed in quotes, padded with spaces to fixed lengths in some contexts), Numeric for integers and floating-point numbers (initialized to zero), Logical for boolean values represented as .T. (true) or .F. (false), Date for calendar dates in the format YYYYMMDD, Memo for long text fields, Array for collections of elements, Codeblock for executable code fragments, and NIL for uninitialized or null values. These types facilitate flexible data handling, particularly in database applications, though Memo fields are often linked to external files for storage efficiency.[19][13]
Variable scoping in Clipper is managed through explicit declarations to control visibility and prevent naming conflicts. PUBLIC variables are accessible throughout the entire program, including all procedures and functions, and are declared with the PUBLIC statement followed by the variable name and optional initializer, such as PUBLIC nGlobal := 0. PRIVATE variables are visible within the declaring procedure or function and its callers but hide any PUBLIC variables of the same name, declared via PRIVATE in a similar syntax. LOCAL variables are restricted to the scope of the procedure or function where they are declared, making them ideal for temporary computations, as in LOCAL cTemp := "example". Arrays and codeblocks follow the same scoping rules when declared with these keywords.[20][21][22]
Arrays in Clipper are dynamic or fixed-size collections that can hold mixed data types, declared either as an empty array with aData := {} or a fixed-length one using the Array() function, such as aData := Array(5). Elements are appended dynamically with the AAdd() function; for example:
LOCAL aList := {}
AAdd(aList, "Item1")
AAdd(aList, 42)
LOCAL aList := {}
AAdd(aList, "Item1")
AAdd(aList, 42)
{ |nValue| nValue * 2 }. Codeblocks are evaluated using the Eval() function; a representative example is:
[LOCAL](/page/.local) bDouble := { |n| n * 2 }
? Eval(bDouble, 5) // Outputs: 10
[LOCAL](/page/.local) bDouble := { |n| n * 2 }
? Eval(bDouble, 5) // Outputs: 10
Database and File Management
Clipper's database management revolves around the DBF (dBase File Format), a binary file structure that stores records in fixed-length fields, supporting data types such as character, numeric, date, and logical. This format enables efficient storage and retrieval for applications, with each DBF file containing a header describing field names, types, and lengths, followed by the data records. Clipper applications primarily interact with DBF files through high-level commands that abstract underlying file operations.[13] To open a DBF file, the USE command specifies the file alias and work area, allowing multiple files to be handled simultaneously across up to 250 work areas managed by the SELECT command. For instance, SELECT 1 followed by USE customers NEW opens the "customers.dbf" file in work area 1. Adding records uses APPEND BLANK, which adds an empty record to the end of the file and positions the record pointer there, while REPLACE updates field values in the current record, such as REPLACE name WITH "John Doe". These operations ensure data persistence without direct file manipulation.[25][26][27] Indexing enhances query performance by creating separate index files: NDX for single-key indexes in earlier versions and CDX for multiple tags in later ones, compatible with FoxPro. The INDEX ONProgramming Practices
Basic Constructs and Control Flow
Clipper's basic constructs provide imperative control flow mechanisms derived from its dBase heritage, enabling sequential, conditional, and repetitive execution of statements within procedures or functions. These include conditional branching with IF...ENDIF and DO CASE...ENDCASE, looping via DO WHILE...ENDDO and FOR...NEXT, and subroutine definitions through FUNCTION and PROCEDURE statements. Expressions within these constructs operate on Clipper's core data types, such as logical (.T./.F.), numeric, character, and date values, evaluated from left to right with standard operator precedence.[37] The IF...ENDIF structure handles conditional execution by evaluating a logical condition and executing the associated statements if true (.T.), with optional ELSEIF and ELSE clauses for alternatives. Syntax is: IF... SKIP ENDDO, where EOF() checks the end-of-file, SKIP advances one record, and the loop continues until no more records remain.[39][40]
Advanced Programming Techniques
Clipper 5.0 introduced object-oriented programming capabilities, enabling developers to define custom classes using theCLASS and END CLASS constructs, along with METHOD definitions for object behaviors.[13] These classes support instance variables and methods invoked via the message-sending operator :<message>[(<arguments>)], such as myObject:processData().[13] Inheritance is achieved by specifying a parent class in the class declaration, allowing derived classes to extend or override methods from superclasses, with dynamic polymorphism facilitated through method resolution at runtime.[13] To invoke a superclass method explicitly, developers use the ::Super:<MethodName>() syntax, promoting code reuse and modular design in complex applications.[13] Predefined classes like Error for runtime error handling and Get for input field management exemplify these features, providing built-in methods such as varPut() for data assignment.[13]
Libraries and extensions significantly enhance Clipper's functionality for advanced development, with CA-Clipper Tools offering over 800 utility functions for tasks including graphics rendering, report generation, and system-level operations.[43] These libraries are compiled into .lib files and linked during the build process, allowing seamless integration of utilities like window management and data visualization without altering core language syntax.[43] User-defined libraries further extend this by packaging custom functions into reusable modules, often distributed as shareware or commercial add-ons to accelerate development of database-driven applications.[44]
Integration with external languages like C enables performance-critical extensions through the EXTERN directive, which declares C functions for linking into Clipper executables via the Extend API.[45] This allows developers to call C routines directly from Clipper code, passing parameters such as strings or numerics, and is particularly useful for low-level operations like custom I/O or algorithmic computations not natively optimized in Clipper.[45] For graphical user interfaces, third-party tools like FiveWin provide class-based wrappers around Windows APIs, predating Computer Associates' full acquisition and enabling event-driven GUI development with controls such as buttons and dialogs.[46]
Code blocks support event-driven programming by encapsulating executable code as data, defined with {|| <expression>} and evaluated via functions like EVAL() or passed to database operations for conditional logic.[47] This allows dynamic behavior, such as customizing browse table actions in a TBrowse object where user-supplied code blocks handle data retrieval and display updates.[13] Macros enable metaprogramming through the & operator for text substitution or runtime compilation, as in &<varName> to execute variable-stored commands, facilitating flexible code generation and indirect invocation in procedural scripts.[13]
