Cache Object Script
Cache Object Script
Using Cach ObjectScript Cach Version 2013.1 24 April 2013 Copyright 2013 InterSystems Corporation All rights reserved. This book was assembled and formatted in Adobe Page Description Format (PDF) using tools and information from the following sources: Oracle Corporation, RenderX, Inc., Adobe Systems, and the World Wide Web Consortium at www.w3c.org. The primary document development tools were special-purpose XML-processing applications built by InterSystems using Cach and Java.
Cach WEBLINK, and Distributed Cache Protocol are registered trademarks of InterSystems Corporation.
InterSystems Jalapeo Technology, Enterprise Cache Protocol, ECP, and InterSystems Zen are trademarks of InterSystems Corporation. All other brand or product names used herein are trademarks or registered trademarks of their respective companies or organizations. This document contains trade secret and confidential information which is the property of InterSystems Corporation, One Memorial Drive, Cambridge, MA 02142, or its affiliates, and is furnished for the sole purpose of the operation and maintenance of the products of InterSystems Corporation. No part of this publication is to be used for any other purpose, and this publication is not to be reproduced, copied, disclosed, transmitted, stored in a retrieval system or translated into any human or computer language, in any form, by any means, in whole or in part, without the express prior written consent of InterSystems Corporation. The copying, use and disposition of this document and the software programs described herein is prohibited except to the limited extent set forth in the standard software license agreement(s) of InterSystems Corporation covering such programs and related documentation. InterSystems Corporation makes no representations and warranties concerning such software programs other than those set forth in such standard software license agreement(s). In addition, the liability of InterSystems Corporation for any losses or damages relating to or arising out of the use of such software programs is limited in the manner set forth in such standard software license agreement(s). THE FOREGOING IS A GENERAL SUMMARY OF THE RESTRICTIONS AND LIMITATIONS IMPOSED BY INTERSYSTEMS CORPORATION ON THE USE OF, AND LIABILITY ARISING FROM, ITS COMPUTER SOFTWARE. FOR COMPLETE INFORMATION REFERENCE SHOULD BE MADE TO THE STANDARD SOFTWARE LICENSE AGREEMENT(S) OF INTERSYSTEMS CORPORATION, COPIES OF WHICH WILL BE MADE AVAILABLE UPON REQUEST. InterSystems Corporation disclaims responsibility for errors which may appear in this document, and it reserves the right, in its sole discretion and without notice, to make substitutions and modifications in the products and practices described in this document. For Support questions about any InterSystems products, contact: InterSystems Worldwide Customer Support Tel: +1 617 621-0700 Fax: +1 617 374-9391 Email: [email protected]
Table of Contents
About This Book .................................................................................................................................... 1 1 Introducing Cach ObjectScript ....................................................................................................... 3 1.1 Features ...................................................................................................................................... 3 1.2 Language Overview .................................................................................................................... 4 1.3 Invoking Commands and Functions ........................................................................................... 4 1.3.1 Statements and Commands .............................................................................................. 5 1.3.2 Functions .......................................................................................................................... 5 1.3.3 Expressions ...................................................................................................................... 5 1.3.4 Variables ........................................................................................................................... 6 1.3.5 Operators .......................................................................................................................... 6 1.4 Relationship with ISO Standard M ............................................................................................ 6 2 Syntax Rules ........................................................................................................................................ 7 2.1 Case Sensitivity .......................................................................................................................... 7 2.1.1 Identiers ......................................................................................................................... 8 2.1.2 Keyword Names ............................................................................................................... 8 2.1.3 Class Names ..................................................................................................................... 8 2.1.4 Namespace Names ........................................................................................................... 8 2.2 Unicode ...................................................................................................................................... 8 2.3 White Space ................................................................................................................................ 9 2.4 Comments ................................................................................................................................... 9 2.4.1 Comments in INT Code for Routines and Methods ...................................................... 10 2.4.2 Comments in MAC Code for Routines and Methods .................................................... 10 2.4.3 Comments in Class Denitions Outside of Method Code ............................................. 10 2.5 Literals ...................................................................................................................................... 11 2.5.1 String Literals ................................................................................................................. 11 2.5.2 Numeric Literals ........................................................................................................... 11 2.6 Identiers ................................................................................................................................. 12 2.6.1 Punctuation Characters within Identiers ...................................................................... 12 2.7 Labels ....................................................................................................................................... 13 2.8 Namespaces .............................................................................................................................. 14 2.8.1 Extended References ...................................................................................................... 14 2.9 Reserved Words ........................................................................................................................ 15 3 Data Types and Values ..................................................................................................................... 17 3.1 Strings ....................................................................................................................................... 17 3.1.1 Escaping Quotation Marks ............................................................................................. 17 3.1.2 Concatenating Strings .................................................................................................... 18 3.1.3 String Comparisons ........................................................................................................ 18 3.1.4 Long Strings ................................................................................................................... 18 3.2 Numbers ................................................................................................................................... 19 3.2.1 Fundamentals of Numbers ............................................................................................. 19 3.2.2 Canonical Form of Numbers .......................................................................................... 20 3.2.3 Strings as Numbers ........................................................................................................ 20 3.2.4 Concatenating Numbers ................................................................................................. 21 3.2.5 Fractional Numbers ........................................................................................................ 21 3.3 Objects ...................................................................................................................................... 22 3.4 Persistent Multidimensional Arrays (Globals) ......................................................................... 22
iii
3.5 Undened Values ...................................................................................................................... 23 3.6 Boolean Values ......................................................................................................................... 23 3.7 Dates ......................................................................................................................................... 24 4 Variables ............................................................................................................................................ 25 4.1 Categories of Variables ............................................................................................................. 25 4.1.1 Local Variables ............................................................................................................... 25 4.1.2 Process-private Globals .................................................................................................. 27 4.1.3 Globals ........................................................................................................................... 28 4.1.4 Array Variables ............................................................................................................... 29 4.1.5 Special Variables ............................................................................................................ 29 4.1.6 Object Properties ............................................................................................................ 30 4.2 Variable Typing and Conversion ............................................................................................... 30 4.2.1 Object Values .................................................................................................................. 31 4.3 Variable Declaration and Scope ................................................................................................ 32 4.3.1 Using #Dim .................................................................................................................... 32 5 Operators and Expressions .............................................................................................................. 33 5.1 Introduction to Operators and Expressions .............................................................................. 33 5.1.1 Table of Operator Symbols ............................................................................................ 34 5.1.2 Operator Precedence ...................................................................................................... 35 5.1.3 Expressions .................................................................................................................... 36 5.1.4 Assignment ..................................................................................................................... 38 5.2 String-to-Number Conversion .................................................................................................. 38 5.2.1 Numeric Strings ............................................................................................................. 38 5.2.2 Non-numeric Strings ...................................................................................................... 39 5.3 Arithmetic Operators ................................................................................................................ 39 5.3.1 Unary Positive Operator (+) ........................................................................................... 40 5.3.2 Unary Negative Operator (-) .......................................................................................... 40 5.3.3 Addition Operator (+) ..................................................................................................... 40 5.3.4 Subtraction Operator (-) ................................................................................................. 41 5.3.5 Multiplication Operator (*) ............................................................................................ 41 5.3.6 Division Operator (/) ...................................................................................................... 42 5.3.7 Exponentiation Operator (**) ........................................................................................ 42 5.3.8 Integer Divide Operator ( \ ) ........................................................................................... 43 5.3.9 Modulo Operator (#) ...................................................................................................... 44 5.4 Logical Comparison Operators ................................................................................................ 44 5.4.1 Unary Not ...................................................................................................................... 44 5.4.2 Precedence and Logical Operators ................................................................................. 45 5.4.3 Binary And .................................................................................................................... 45 5.4.4 Binary Or ....................................................................................................................... 46 5.5 String Operators ....................................................................................................................... 47 5.5.1 Binary Concatenate ....................................................................................................... 48 5.6 Numeric Relational Operators ................................................................................................. 48 5.6.1 Binary Less Than .......................................................................................................... 48 5.6.2 Binary Greater Than ...................................................................................................... 49 5.6.3 Greater Than or Equal To .............................................................................................. 49 5.6.4 Less Than or Equal To ................................................................................................... 49 5.7 String Relational Operators ...................................................................................................... 50 5.7.1 Binary Equals ................................................................................................................ 50 5.7.2 Binary Contains ............................................................................................................. 51 5.7.3 Binary Follows .............................................................................................................. 51
iv
5.7.4 Binary Sorts After ......................................................................................................... 52 5.8 Pattern Matching ...................................................................................................................... 53 5.8.1 Specifying How Many Times a Pattern Can Occur ....................................................... 56 5.8.2 Specifying Multiple Patterns .......................................................................................... 57 5.8.3 Specifying a Combination Pattern ................................................................................. 57 5.8.4 Specifying an Indenite Pattern ..................................................................................... 57 5.8.5 Specifying an Alternating Pattern (Logical OR) ............................................................ 58 5.8.6 Using Incomplete Patterns ............................................................................................. 58 5.8.7 Multiple Pattern Interpretations ..................................................................................... 59 5.8.8 Not Match Operator ....................................................................................................... 59 5.8.9 Pattern Complexity ......................................................................................................... 59 5.9 Indirection ................................................................................................................................ 59 5.9.1 Name Indirection ........................................................................................................... 60 5.9.2 Pattern Indirection ......................................................................................................... 61 5.9.3 Argument Indirection .................................................................................................... 62 5.9.4 Subscript Indirection ..................................................................................................... 62 5.9.5 $TEXT Argument Indirection ........................................................................................ 63 6 Regular Expressions ......................................................................................................................... 65 6.1 Wildcard and Quantiers .......................................................................................................... 66 6.2 Literals and Character Ranges .................................................................................................. 66 6.3 Character Type Meta-Characters .............................................................................................. 67 6.3.1 Single-letter Character Types ......................................................................................... 68 6.3.2 Unicode Property Character Types ................................................................................ 68 6.3.3 POSIX Character Types ................................................................................................. 70 6.4 Grouping Construct .................................................................................................................. 71 6.5 Anchor Meta-Characters .......................................................................................................... 71 6.5.1 String Beginning or End ................................................................................................. 71 6.5.2 Word Boundary .............................................................................................................. 72 6.6 Logical Operators ..................................................................................................................... 73 6.7 Character Representation Meta-Characters .............................................................................. 73 6.7.1 Hexadecimal, Octal, and Unicode Representation ......................................................... 74 6.7.2 Control Character Representation .................................................................................. 74 6.7.3 Symbol Name Representation ........................................................................................ 74 6.8 Modes ....................................................................................................................................... 74 6.8.1 Mode for a Regular Expression Sequence ..................................................................... 75 6.8.2 Mode for a Literal .......................................................................................................... 76 6.9 Comments ................................................................................................................................. 76 6.9.1 Embedded Comments .................................................................................................... 77 6.9.2 Line End Comment ........................................................................................................ 77 6.10 Error Messages ....................................................................................................................... 77 7 Commands ......................................................................................................................................... 79 7.1 Command Arguments ............................................................................................................... 79 7.1.1 Multiple Arguments ....................................................................................................... 80 7.1.2 Argumentless Commands ............................................................................................... 80 7.1.3 Maximum Command Length ......................................................................................... 81 7.2 Command Postconditional Expressions ................................................................................... 81 7.2.1 Postconditional Syntax ................................................................................................... 82 7.2.2 Evaluation of Postconditionals ....................................................................................... 82 7.3 Invoking Code .......................................................................................................................... 83 7.3.1 Do ................................................................................................................................... 83
7.3.2 Quit ................................................................................................................................. 83 7.3.3 Job .................................................................................................................................. 84 7.3.4 Xecute ............................................................................................................................ 84 7.4 Assignment Commands ............................................................................................................ 84 7.4.1 Set ................................................................................................................................... 84 7.4.2 Kill ................................................................................................................................. 85 7.4.3 New ................................................................................................................................ 85 7.5 Flow Control Commands ......................................................................................................... 85 7.5.1 If, ElseIf, and Else .......................................................................................................... 86 7.5.2 For .................................................................................................................................. 86 7.5.3 While and Do/While ...................................................................................................... 88 7.6 I/O Commands ......................................................................................................................... 88 7.6.1 Write ............................................................................................................................... 88 7.6.2 Read ............................................................................................................................... 89 7.6.3 Open, Use, and Close ..................................................................................................... 90 7.7 Other Commands ...................................................................................................................... 90 8 Functions ........................................................................................................................................... 91 8.1 Function Syntax ........................................................................................................................ 91 9 User-dened Code ............................................................................................................................ 93 9.1 Procedures, Routines, Subroutines, Functions, and Methods: What Are They? ...................... 94 9.1.1 Routines ......................................................................................................................... 95 9.1.2 Subroutines ..................................................................................................................... 95 9.1.3 Functions ........................................................................................................................ 95 9.2 Procedures in Detail ................................................................................................................. 96 9.2.1 Invoking Procedures ....................................................................................................... 96 9.2.2 Procedure Syntax ........................................................................................................... 97 9.2.3 Procedure Variables ........................................................................................................ 99 9.2.4 Public and Private Procedures ..................................................................................... 100 9.2.5 Procedure Parameters ................................................................................................... 100 9.2.6 Procedure Code ........................................................................................................... 103 9.2.7 Indirection, XECUTE Commands, and JOB Commands within Procedures .............. 104 9.2.8 Error Traps within Procedures .................................................................................... 105 9.3 Legacy User-Dened Code .................................................................................................... 105 9.3.1 Subroutines ................................................................................................................... 105 9.3.2 Functions ..................................................................................................................... 106 10 ObjectScript Macros and the Macro Preprocessor ................................................................... 111 10.1 Using Macros ....................................................................................................................... 111 10.1.1 Creating Custom Macros ........................................................................................... 112 10.1.2 Saving Custom Macros .............................................................................................. 113 10.1.3 Invoking Macros ......................................................................................................... 114 10.1.4 Referring to External Macros (Include Files) ............................................................ 114 10.2 Preprocessor Directives Reference ....................................................................................... 114 10.2.1 #; ................................................................................................................................. 115 10.2.2 #Def1Arg .................................................................................................................... 115 10.2.3 #Dene ....................................................................................................................... 116 10.2.4 #Dim ........................................................................................................................... 117 10.2.5 #Else ........................................................................................................................... 118 10.2.6 #ElseIf ........................................................................................................................ 118 10.2.7 #EndIf ......................................................................................................................... 118
vi
10.2.8 #Execute ..................................................................................................................... 118 10.2.9 #If ............................................................................................................................... 119 10.2.10 #IfDef ....................................................................................................................... 119 10.2.11 #IfNDef .................................................................................................................... 120 10.2.12 #Import ..................................................................................................................... 120 10.2.13 #Include .................................................................................................................... 121 10.2.14 #NoShow .................................................................................................................. 121 10.2.15 #Show ....................................................................................................................... 121 10.2.16 #SQLCompile Mode ................................................................................................ 122 10.2.17 #SQLCompile Path .................................................................................................. 122 10.2.18 #SQLCompile Select ................................................................................................ 124 10.2.19 #UnDef ..................................................................................................................... 124 10.2.20 ##; ............................................................................................................................. 125 10.2.21 ##Continue ............................................................................................................... 125 10.2.22 ##Expression ............................................................................................................ 126 10.2.23 ##Function ............................................................................................................... 127 10.2.24 ##lit .......................................................................................................................... 128 10.2.25 ##SQL ...................................................................................................................... 128 10.2.26 ##Unique .................................................................................................................. 129 10.3 Using System-supplied Macros ............................................................................................ 129 10.3.1 Making System-supplied Macros Accessible ............................................................ 129 10.3.2 System-supplied Macro Reference ............................................................................ 130 11 Multidimensional Arrays ............................................................................................................. 133 11.1 What Multidimensional Arrays Are ..................................................................................... 133 11.1.1 Multidimensional Tree Structures .............................................................................. 133 11.1.2 Sparse Multidimensional Storage .............................................................................. 134 11.1.3 Settings for Multidimensional Arrays ........................................................................ 134 11.2 Manipulating Multidimensional Arrays ............................................................................... 134 11.3 For More Information ........................................................................................................... 134 12 String Operations ......................................................................................................................... 135 12.1 Basic String Operations and Functions ................................................................................ 135 12.1.1 Advanced Features of $Extract .................................................................................. 136 12.2 Delimited Strings .................................................................................................................. 137 12.2.1 Advanced $Piece Features .......................................................................................... 137 12.3 List-Structure String Operations .......................................................................................... 138 12.3.1 Sparse Lists and Sublists ............................................................................................ 139 12.4 Lists and Delimited Strings Compared ................................................................................ 140 12.4.1 Advantages of Lists .................................................................................................... 140 12.4.2 Advantages of Delimited Strings ............................................................................... 140 13 Transaction Processing ................................................................................................................. 141 13.1 Managing Transactions Within Applications ....................................................................... 141 13.1.1 Transaction Commands .............................................................................................. 142 13.1.2 Using the Lock Command in Transactions ................................................................ 142 13.1.3 Transaction Rollback within an Application .............................................................. 143 13.1.4 Examples of Transaction Processing Within Applications ......................................... 144 13.2 Automatic Transaction RollBack ......................................................................................... 145 13.2.1 Rollback During Cach Startup ................................................................................. 145 13.2.2 Rollback at Halt from Cach ...................................................................................... 145 13.2.3 Rollback During RESJOB ......................................................................................... 145
vii
13.2.4 Restore Journal Option of JOURNAL Utility ............................................................ 145 13.3 System-Wide Issues with Transaction Processing ............................................................... 146 13.3.1 Backups and Journaling with Transaction Processing ............................................... 146 13.3.2 Asynchronous Error Notications ............................................................................. 146 14 Error Processing ........................................................................................................................... 149 14.1 The TRY-CATCH Mechanism ............................................................................................. 149 14.1.1 Using THROW with TRY-CATCH ............................................................................ 150 14.1.2 Using the %Exception.SystemException and %Exception.AbstractException Classes ................................................................................................................................................ 151 14.1.3 Other Considerations with TRY-CATCH ................................................................... 151 14.2 Traditional Error Processing ................................................................................................. 152 14.2.1 How Traditional Error Processing Works .................................................................. 152 14.2.2 Handling Errors with $ZTRAP .................................................................................. 155 14.2.3 Handling Errors with $ETRAP .................................................................................. 158 14.2.4 Handling Errors in an Error Handler .......................................................................... 161 14.2.5 Forcing an Error ......................................................................................................... 162 14.2.6 Processing Errors in Programmer Mode ................................................................... 162 15 Command-line Routine Debugging ............................................................................................. 167 15.1 Debugging with the Cach Debugger ................................................................................... 167 15.1.1 Using Breakpoints and Watchpoints .......................................................................... 167 15.1.2 Establishing Breakpoints and Watchpoints ................................................................ 168 15.1.3 Disabling Breakpoints and Watchpoints .................................................................... 171 15.1.4 Delaying Execution of Breakpoints and Watchpoints ................................................ 172 15.1.5 Deleting Breakpoints and Watchpoints ...................................................................... 172 15.1.6 Single-step Breakpoint Actions .................................................................................. 172 15.1.7 Tracing Execution ...................................................................................................... 173 15.1.8 INTERRUPT Keypress and Break ............................................................................. 175 15.1.9 Displaying Information About the Current Debug Environment ............................... 175 15.1.10 Using the Debug Device .......................................................................................... 177 15.1.11 Cach Debugger Example ........................................................................................ 177 15.1.12 Understanding Cach Debugger Errors ................................................................... 178 15.2 Debugging With BREAK ..................................................................................................... 179 15.2.1 Using Argumentless BREAK to Suspend Routine Execution ................................... 179 15.2.2 Using Argumentless BREAK with a Postconditional ................................................ 179 15.2.3 Using Argumented BREAK to Enable or Disable Interrupts ..................................... 179 15.2.4 Using Argumented BREAK to Suspend Routine Execution ..................................... 180 15.2.5 Enabling Single Stepping at the Previous Execution Level ....................................... 181 15.2.6 Understanding the Programmer Mode Prompt Information ...................................... 181 15.2.7 Resuming Execution after a BREAK or an Error ...................................................... 182 15.2.8 The NEW Command in Programmer Mode .............................................................. 183 15.2.9 The QUIT Command in Programmer Mode .............................................................. 184 15.2.10 Cach Error Messages .............................................................................................. 184 15.3 Using %STACK to Display the Stack .................................................................................. 184 15.3.1 Running %STACK ..................................................................................................... 184 15.3.2 Displaying the Process Execution Stack .................................................................... 185 15.3.3 Understanding the Stack Display ............................................................................... 185 15.4 Other Debugging Tools ........................................................................................................ 189 15.4.1 Displaying References to an Object with $SYSTEM.OBJ.ShowReferences ............ 189 15.4.2 Error Trap Utilities ..................................................................................................... 189
viii
16 Open M Language Compatibility ............................................................................................... 193 16.1 Displaying and Switching Language Mode ......................................................................... 193 16.2 DSM-11 Language Compatibility ........................................................................................ 194 16.2.1 Using Routine Interlock Devices ............................................................................... 194 16.2.2 Issuing I/O Commands for Routine Interlock Devices .............................................. 195 16.2.3 Working with DSM-11 Mode Routines ..................................................................... 195 16.2.4 Transferring Globals from DSM-11 Systems ............................................................ 196 16.2.5 I/O Programming in DSM-11 Compatibility Mode ................................................... 197 16.2.6 VIEW Command and $VIEW Function .................................................................... 201 16.2.7 ZAllocate and ZDeallocate ........................................................................................ 201 16.2.8 Extended Functions for DSM-11 Mode ..................................................................... 201 16.2.9 Unsupported DSM-11 Functions ............................................................................... 202 16.2.10 Extended Special Variables for DSM-11 Mode ....................................................... 202 16.2.11 Extended Commands for DSM-11 Compatibility Mode ......................................... 202 16.2.12 Error Handling for DSM-11 Compatibility Mode ................................................... 203 16.2.13 $TEXT Comment Lines ........................................................................................... 203 16.3 DSM Language Compatibility ............................................................................................. 203 16.3.1 Porting Routines from DSM to Cach ....................................................................... 203 16.3.2 Programming in DSM Language Mode ..................................................................... 204 16.3.3 Device Control Mnemonic Spaces and Device Control Mnemonics ......................... 206 16.3.4 Other DSM Language Features Implemented in Compatibility Mode ...................... 207 16.3.5 VIEW Command and $VIEW Function .................................................................... 209 16.3.6 Database Conversion .................................................................................................. 209 16.4 DSM-J Language Compatibility .......................................................................................... 209 16.5 DTM Language Compatibility ............................................................................................. 210 16.5.1 Programming in DTM Compatibility Mode .............................................................. 210 16.5.2 Commands, Functions, and Special Variables ........................................................... 212 16.5.3 Database Conversion .................................................................................................. 215 16.6 MSM Language Compatibility ............................................................................................. 215 16.6.1 Commands, Functions, and Special Variables ........................................................... 215 16.6.2 Database Conversion .................................................................................................. 216
ix
List of Figures
Figure 21: Studio Syntax Checking ....................................................................................................... 9 Figure 141: Frames on a Call Stack .................................................................................................. 153 Figure 142: $ZTRAP Error Handlers ................................................................................................ 158 Figure 143: $ETRAP Error Handlers ................................................................................................ 160
List of Tables
Table 31: Date Formats ........................................................................................................................ 24 Table 41: Cach ObjectScript Type Conversion Rules ........................................................................ 31 Table 51: ObjectScript Operators ........................................................................................................ 34 Table 52: Pattern Codes ....................................................................................................................... 55 Table 81: Invoking Cach ObjectScript Functions .............................................................................. 91 Table 131: Cach Transaction Commands ........................................................................................ 142 Table 151: Error Prompts in Programmer Mode ............................................................................... 182 Table 152: %STACK Utility Information .......................................................................................... 186 Table 153: Frame Types and Values Available .................................................................................. 186 Table 154: %ERN Options ................................................................................................................ 190 Table 161: Cach Language Modes ................................................................................................... 194 Table 162: DSM-11 Compatibility Mode Open/Use Command Parameters .................................... 197 Table 163: DSM-11 Compatibility Mode Set and Clear Status Bits ................................................. 199
xi
For a detailed outline, see the Table of Contents. Other, related documents in the Cach documentation set are: The Cach ObjectScript Language Reference Cach Programming Orientation Guide Using Cach Objects Using Cach SQL Using Cach Basic Using Cach Globals
1
Introducing Cach ObjectScript
Cach ObjectScript is an object programming language designed for rapidly developing complex business applications. It is well-suited for a variety of applications including: Business logic Application integration Data processing Cach ObjectScript source code is compiled into object code that executes within the Cach Virtual Machine. This object code is highly optimized for operations typically found within business applications, including string manipulations and database access. ObjectScript programs are completely portable across all platforms supported by Cach. You can use Cach ObjectScript in any of the following contexts: Interactively from the command line of the Cach Terminal. As the implementation language for methods of Cach object classes. To create Cach ObjectScript routines: individual programs contained and executed within Cach. As the implementation language for Stored Procedures and Triggers within Cach SQL. As a server-side scripting language within a Cach Server Pages application.
Cach ObjectScript is completely compatible and interoperable with the other Cach native scripting language: Cach Basic. To learn more about Cach ObjectScript, you can also refer to: The Cach ObjectScript Tutorial for an interactive introduction to most language elements. The Cach ObjectScript Reference for details on individual commands and functions.
1.1 Features
Some of the key features of Cach ObjectScript include: Powerful built-in functions for working with strings. Native support for objects including methods, properties, and polymorphism. A wide variety of commands for directing control ow within an application.
A set of commands for dealing with I/O devices. Support for multidimensional, sparse arrays: both local and global (persistent). Support for efcient, Embedded SQL. Support for indirection as well as runtime evaluation and execution of commands.
In Cach ObjectScript it is possible (though not recommended) to use any valid name as an identier name, as shown in the following program, which is functionally identical to the previous example:
SET SET = 100 WRITE SET
Some components of Cach ObjectScript, such as command names and function names, are not case-sensitive. Other components of Cach ObjectScript, such as variable names and method names, are case-sensitive. For details refer to the Syntax chapter of this document. Note that whitespace can be inserted or omitted almost anywhere in Cach ObjectScript. However, one use of whitespace is signicant; a statement cannot start on the rst character position on a line. Thus, all commands must be indented. Comments must also be indented. The only code element that can appear in the rst character position on a line is a label:
MyLabel SET x = 100 WRITE x
Whitespace rules are further discussed in the Syntax chapter of this document.
which invokes the WRITE command on the variable x (this displays the value of x). In the example above, x is an expression; an ObjectScript expression is one or more tokens that can be evaluated to yield a value. Each token can be a literal, a variable, the result of the action of one or more operators (such as the total from adding two numbers), the return value that results from evaluating a function, some combination of these, and so on. The valid syntax for a statement involves its commands, functions, and operators and expressions; see each chapter for information on these.
WRITE is a command. It does exactly what its name implies: it writes whatever you specify as its argument(s) to the current principal output device. In this case, WRITE writes three arguments: the literal string Hello ; the ! character, which is a symbolic operator specic to the WRITE command that issues a line feed/carriage return; and the local variable x, which is replaced during execution by its current value. Arguments are separated by commas; you may also add whitespace between arguments (with some restrictions). Whitespace is discussed in the Syntax chapter of this document. Most Cach ObjectScript commands (and many functions and special variables) have a long form and a short (abbreviated) form (typically one or two characters). For example, the following program is identical to the previous one, but uses the abbreviated command names:
S x="World" W "Hello",!,x
The short form of a command name is simply a device for developers who do not like to type long command names. It is exactly equivalent to the long form. This document uses the long form of command names. For a complete list, see Abbreviations Used in Cach ObjectScript in the Cach ObjectScript Reference. For more information on commands, refer to the Commands chapter or the individual reference page within the Cach ObjectScript Reference.
1.3.2 Functions
A function is a routine that performs a frequently required operation (for example, converting a string to its equivalent ASCII code values). A function is invoked within a command line. This invocation passes parameters to the function, which uses these parameter values to perform some operation. The function then returns a single value that is the result of the operation. You can use a function any place you can use an expression. A function invoked upon an object is called a method. (Expressions and methods are described later in this chapter.) In addition to its system-supplied functions, Cach ObjectScript allows you to write procedures, which are user-dened functions. The system-supplied functions are provided as part of Cach; they perform common string and data operations and each is described in the Cach ObjectScript Reference. For information on dening and calling user-dened functions, refer to User-Dened Code.
1.3.3 Expressions
An expression is any set of tokens that can be evaluated to yield a single value. For example, the literal string, hello , is an expression. So is l + 2. Variables such as x, functions such as $LENGTH(), and special variables such as $ZVERSION also evaluate to an expression. Within a program, you use expressions as arguments for commands and functions:
SET x WRITE WRITE WRITE WRITE = "Hello" x,! 1 + 2,! $LENGTH(x),! $ZVERSION
1.3.4 Variables
In ObjectScript, a variable is the name of a location in which a runtime value can be stored. Variables must be dened, for example, by using the SET command, but they do not have to be typed. Variables in Cach ObjectScript are untyped; that is, they do not have an assigned data type and can take any data value. (For compatibility, the $DOUBLE function can be used to convert untyped oating point numbers to a specic numeric data type format.) Cach ObjectScript supports several kinds of variables: Local variables A variable that is accessible only by the Cach process that created it, and which is automatically deleted when the process terminates. A local variable is accessible from any namespace. Process-private globals A variable that is accessible only by the Cach process and is deleted when the process ends. A process-private global is accessible from any namespace. Process-private globals are especially useful for temporary storage of large data values. Globals A persistent variable that is stored within the Cach database. A global is accessible from any process, and persists after the process that created it terminates. Globals are specic to individual namespaces. Array variables A variable with one or more subscripts. All user-dened variables can be used as arrays, including local variables, process-private globals, globals, and object properties. Special variables (also known as system variables) One of a special set of built-in variables that contain a value for a particular aspect of the Cach operating environment. All special variables are dened; Cach sets all special variables to an initial value (sometimes a null string value). Some special variables can be set by the user, others can only be set by Cach. Special variables are not array variables. Object properties A value associated with, and stored within, a specic instance of an object.
Cach ObjectScript supports various operations on or among variables. Variables are described in much greater detail in the Variables chapter of this document.
1.3.5 Operators
Cach ObjectScript denes a number of built-in operators. These include arithmetic operators, such as addition ( + ) and multiplication ( * ), logical operators, and pattern match operators. For details, refer to the Operators chapter of this document.
You can take advantage of these new features in an evolutionary fashion, using them within your applications as you see t.
2
Syntax Rules
This chapter describes the basic rules of ObjectScript syntax. Topics include: Case Sensitivity Unicode White Space Comments Literals Identiers Labels Namespaces Reserved Words
Syntax Rules
2.1.1 Identifiers
User-dened identiers (variable, routine, and label names) are case-sensitive. String, string, and STRING all refer to different variables. Global variable names are also case-sensitive, whether user-dened or system-supplied. Note: Cach SQL identiers, in contrast, are not case-sensitive.
2.2 Unicode
Your instance of Cach supports the Unicode international character set if you selected the Unicode option during Cach installation. Unicode characters are 16-bit characters, also known as wide characters. The $ZVERSION special variable shows if your Cach installation supports Unicode. On a Unicode installation of Cach, some names can contain Unicode letter characters, while other names cannot contain Unicode letters. Unicode letters are dened as alphabetic characters with ASCII values higher than 255. For example, the Greek lowercase lambda is $CHAR(955), a Unicode letter. Unicode Letters Permitted: local variable names; variable subscript names (for local, global, and process-private global variables); list element values; Embedded SQL host variable names; label names; namespace names; Cach and SQL user names, role names, and passwords; Embedded SQL <marker> values; SQL table, view, eld, and trigger names; ^%ZLANG names for user-dened commands, functions, and special variables. No Unicode Letters: global variable names; process-private global names; administrator user names and passwords. The Japanese locale does not support accented Latin letter characters in Cach names. Japanese names may contain (in addition to Japanese characters) the Latin letter characters A-Z and a-z (6590 and 97122), and the Greek capital letter characters (913929 and 931937).
Note:
White Space
There must be one and only one space (not tab) between a command and its rst argument; if a command uses a postconditional, there are no spaces between the command and its postconditional. If a postconditional expression includes any spaces, then the entire expression must be parenthesized. There can be any amount of white space between any pair of command arguments. If a line contains code and then a single-line comment, there must be white space between them. Typically, each command appears on its own line, though you can enter multiple commands on the same line. In this case, there must be white space between them; if the rst command is argumentless, then the second command must be preceded by two spaces or tabs (or one of each).
The Cach Studio provides built-in syntax checking, so that it will mark any illegal use of white space, such as the following insertion of multiple spaces before a commands rst argument:
2.4 Comments
It is good practice to use comments to provide in-line documentation in code, as they are a valuable resource when modifying or maintaining code. Cach ObjectScript supports several types of comments which can appear in several kinds of locations: Comments in INT Code for Routines and Methods Comments in MAC Code for Routines and Methods Comments in Class Denitions Outside of Method Code
Syntax Rules
A multiline comment (/* comment */) can be placed between command or function arguments, either before or after a comma separator. A multiline comment cannot be placed within an argument, or be placed between a command keyword and its rst argument or a function keyword and its opening parenthesis. It can be placed between two commands on the same line, in which case it functions as the single space needed to separate the commands. You can immediately follow the end of a multiline comment (*/) with a command on the same line, or follow it with a single line comment on the same line. The following example shows these insertions of /* comment */ within a line:
WRITE $PIECE("Fred&Ginger"/* WRITE "world" */,"&",2),! WRITE "hello",/* WRITE "world" */" sailor",! SET x="Fred"/* WRITE "world" */WRITE x,! WRITE "hello"/* WRITE "world" */// WRITE " sailor"
10
Literals
/// comments immediately preceding a member (either from the beginning of the class denition or after the previous
member) provide the class reference content for that member, where multiple lines of content are treated as a single block of HTML. For more information on the rules for /// comments and the class reference, see either Extending the Class Reference in Using InterSystems Documentation or the %CSP.Documatic entry in the InterSystems Class Reference.
2.5 Literals
A literal is a series of characters that represents a particular string or numeric value, such as Hello and 5 below:
WRITE "Hello" SET x = 5
To include the quotation mark character (") within a string, double the character, as shown in the following example:
WRITE "This character "" is a quotation mark"
A string that contains no value is known as a null string. It is represented by two quotation mark characters (""). A null string is considered to be an actual value. It has a length of 0. To concatenate strings, use the concatenate operator (_):
SET mystr="Two halves"_" make a whole" WRITE mystr
11
Syntax Rules
The decimal_separator character (by default this is the period or decimal point character; in European locales this is the comma character). The Letter E (used in scientic notation)
ObjectScript can work with the following types of numbers: Integers (whole numbers such as 100, 0, or -7) Fractional numbers: decimal numbers (real numbers such as 3.767) and decimal fractions (real numbers such as .0442). ObjectScript supports two representations of fractional numbers: standard Cach oating point numbers ($DECIMAL numbers) and IEEE double-precision oating point numbers ($DOUBLE numbers). For further details, refer to the $DOUBLE function. Scientic notation: numbers placed in exponential notation (such as 2.8E2). To specify exponential notation in ObjectScript, use the following format:
[-]mantissaE[-]exponent
where mantissa
E
The optional Unary Minus operator used with negative numbers. An integer or fractional number. An operator delimiting the exponent (can be uppercase or lowercase). The optional Unary Minus operator used with a negative exponent. The integer exponent (the power of 10).
exponent
For example, to represent the number 10, use 1E1; and to represent number 280, use 2.8E2.
2.6 Identifiers
An identier is the name of a variable, a routine, or a label. In general, legal identiers consist of letter and number characters; with few exceptions, punctuation characters are not permitted in identiers. Identiers are case-sensitive. The naming conventions for user-dened commands, functions, and special variables are more restrictive (only letters permitted) than identier naming conventions. Refer to Extending Languages with ^%ZLANG Routines in Cach Specialized System Tools and Utilities. Naming conventions for local variables, process-private globals, and globals are provided in the Variables chapter of this document.
12
Labels
Note that globals and process-private globals are identied by a caret (^) prex of one or more characters, such as the following:
Globals: ^globname ^|""|globname ^|"mynspace"|globname ^["mynspace"]globname Process-Private Globals: ^||ppgname ^|"^"|ppgname ^|"^",""|ppgname ^["^"]ppgname
These prex characters identify the type of storage and (in the case of globals) the namespace used for this storage. The actual name begins after the nal vertical bar or closing square bracket.
2.7 Labels
Any line of ObjectScript code can optionally include a label (also known as a tag). A label serves as a handle for referring to that line location in the code. A label is an identier that is not indented; it is specied in column 1. All Cach ObjectScript commands must be indented. Labels have the following naming conventions: The rst character must be an alphanumeric character or the percent character (%). The second and all subsequent characters must be alphanumeric characters. A label may contain Unicode letters. They can be up to 31 characters long. A label may be longer than 31 characters, but must be unique within the rst 31 characters. A label reference matches only the rst 31 characters of the label. However, all characters of a label or label reference (not just the rst 31 characters) must abide by label character naming conventions. They are case-sensitive.
A line can consist of only a label, a label followed by one or more commands, or a label followed by a comment. If a command or a comment follows the label on the same line, they must be separated from the label by a space or tab character. The following are all unique labels:
maximum Max MAX 86 agent86 86agent %control
Labels are useful identifying sections of code and for managing ow control, since you can use the label to invoke the code that follows it using the DO or GOTO command. Labels are also used by the PRINT and ZPRINT commands and the $TEXT function to identify source code lines. However, a label does not dene an encapsulated unit of code; this means that once the labelled code executes, execution continues with the next labelled unit of code, if there is one. For instance, in the following code:
SET x = 22 IF x=22 {DO label22 WRITE "All finished",! QUIT } ELSE {WRITE "This never happens"} label22 WRITE "x = ",x,! label23 SET x = 23 WRITE "x = ",x,!
13
Syntax Rules
execution continues from the code under label22 to that under label23, which results in the value of x being changed from 22 to 23. To avoid this situation, use the QUIT command to exit from the code where appropriate, as shown in the following example:
SET x = 22 IF x=22 {DO label22 WRITE "All finished",! QUIT } ELSE {WRITE "This never happens"} label22 WRITE "x = ",x,! QUIT label23 SET x = 23 WRITE "x = ",x,! QUIT
2.8 Namespaces
A namespace name may be an explicit namespace name or an implied namespace name. An explicit namespace name is not case sensitive; regardless of the case of the letters with which it is input, it is always stored and returned in uppercase letters. In an explicit namespace name, the rst character must be a letter or a percent sign (%). The remaining characters must be letters, numbers, hyphens (), or underscores (_). The name cannot be longer than 255 characters. When Cach translates an explicit namespace name to a routine or class name (for example, when creating a cached query class/routine name), it replaces punctuation characters with lowercase letters, as follows: % = p, _ = u, = d. An implied namespace name may contain other punctuation characters; when translating an implied namespace name, these punctuation characters are replaced by a lowercase "s". Thus the following seven punctuation characters are replaced as follows: @ = s, : = s, / = s, \ = s, [ = s, ] = s, ^ = s. When using Cach MultiValue, each MultiValue account is mapped to a Cach namespace. The naming conventions for MultiValue accounts and Cach namespaces differ. For details about how MultiValue account names are translated to namespace names, refer to the CREATE.ACCOUNT command in the Cach MultiValue Commands Reference. For information on using namespaces, see Namespaces and Databases in the Cach Programming Orientation Guide. For information on creating namespaces, see Conguring Namespaces in the Cach System Administration Guide.
In all these cases, the extended routine reference is prefaced by a ^ (caret) character to indicate that the specied entity is a routine (rather than a label or an offset). This caret is not part of the routine name. For example, DO
14
Reserved Words
^|"SAMPLES"|fibonacci invokes the routine named bonacci, which is located in the SAMPLES namespace. The command WRITE $$fun^|"SAMPLES"|house invokes the user-dened function fun() in the routine house,
located in the SAMPLES namespace. Extended SSVN Reference: references a structured system variable (SSVN) in another namespace. The following syntactic forms are supported: ^$["namespace"]ssvn and ^$|"namespace"|ssvn. For further details, refer to the ^$GLOBAL, ^$LOCK, and ^$ROUTINE structured system variables.
All extended references can, of course, specify the current namespace, either explicitly by name, or by specifying a null string placeholder.
15
3
Data Types and Values
Cach ObjectScript is a typeless language you do not have to declare the types of variables. Any variable can have a string, numeric, or object value. That being said, there is important information to know when using different kinds of data in ObjectScript, such as: Strings Numbers Objects Persistent Multidimensional Arrays (Globals) Undened Values Boolean Values Dates
3.1 Strings
A string is a set of characters: letters, digits, punctuation, and so on. You can dene a string literal by placing text within a matched set of quotation marks ("):
Set string = "This is a string." Write string
Topics about strings include: Escaping Quotation Marks Concatenating Strings String Comparisons Long Strings
17
Concatenation
Set string = "Hello" _ " Goodbye" Write string
The <, >, <=, or >= operators cannot be used to perform a string comparison. These operators treat strings as numbers and always perform a numeric comparison. Any non-numeric string is assigned a numeric value of 0 when compared using these operators.
As of Cach 2012.2, long strings are enabled by default for new installs. However, if you upgrade to 2012.2 from an existing install, the long string enabled/disabled option will be the same as before the upgrade. If long strings are enabled, the maximum length of a string is 3,641,144 characters. If long string are disabled, the maximum length of a string is 32,767 characters, which was the default for earlier versions of Cach. You can use either of the following methods to enable or disable long strings system-wide: In the Management Portal, select [System] > [Configuration] > [Memory and Startup]. On the System Memory and Startup Settings page, select the Enable Long Strings check box. If a process was already running when you enabled long strings, long strings will not be enabled for that process. In the Cach parameter le, specify the value of the EnableLongStrings parameter, as described in the EnableLongStrings section of the Cach Parameter File Reference.
Cach also supports the use of long strings on an optional, per-instance basis. To enable long strings for the current instance, use the EnableLongStrings property of the Config.Miscellaneous class.
18
Numbers
Note:
Performance may be affected when long strings are enabled. Enabling long strings increases the amount of memory allocated to the string stack by approximately 50 times. Cach uses the string stack for temporary string handling during command execution. This larger string stack memory is allocated to each process, whether the process uses long strings or not. You may need to retune your system to maintain performance.
When a process actually uses a long string, the memory for the string comes from the operating systems malloc() buffer, not from the partition memory space for the process. Thus the memory allocated for actual long string values is not subject to the limit set by the maximum memory per process (Maximum per Process Memory (KB)) parameter and does not affect the $STORAGE value for the process.
3.2 Numbers
Topics related to numbers include: Fundamentals of Numbers Canonical Form of Numbers Strings as Numbers Concatenating Numbers Fractional Numbers
It can contain at most one decimal separator character. In a numeric expression a second decimal separator results in a <SYNTAX> error. In a numeric string a second decimal separator is evaluated as the rst non-numeric character, terminating the number portion of the string. The decimal separator character may be the rst character or the last character of the numeric expression. The choice of decimal separator character is locale-dependent: American format uses a period (.) as the decimal separator, which is the default. European format uses a comma (,) as the decimal separator. To determine the DecimalSeparator character for your locale, invoke the GetFormatItem() method:
WRITE ##class(%SYS.NLS.Format).GetFormatItem("DecimalSeparator")
19
It can contain at most one letter E (or e ) to specify a base-10 exponent for scientic notation. This scientic notation character ( E or e ) must be preceded by a number character or decimal point, and followed by either a whole number, or a single plus or minus sign followed by a whole number. It cannot be followed by a blank space, a decimal point, multiple plus and minus signs, or a fractional number. The base-10 exponent can contain leading zeros. See the ScienticNotation() method of the %SYSTEM.Process class, which controls use of this letter symbol.
Numeric literal values do not support the following: They cannot contain numeric group separators. These are locale-dependent: American format uses commas, European format uses periods. You can use the $INUMBER function to remove numeric group separators, and the $FNUMBER function to add numeric group separators. They cannot contain currency symbols, hexadecimal letters, or other nonnumeric characters. They cannot contain blank spaces, except before or after arithmetic operators. They cannot contain trailing plus or minus signs. However, the $FNUMBER function can display a number as a string with a trailing sign, and the $NUMBER function can take a string in this format and convert it to a number with a leading sign. They cannot specify enclosing parentheses to represent a number as a negative number (a debit). However, the $FNUMBER function can display a negative number as a string with a enclosing parentheses, and the $NUMBER function can take a string in this format and convert it to a number with a leading negative sign.
A number or numeric expression can containing pairs of enclosing parentheses. These parentheses are not part of the number, but govern the precedence of operations. By default, Cach performs all operations in strict left-to-right order. Numbers of greater than 19 digits, or exponents greater than 130 may give unpredictable results. These may include (but are not limited to) the following: Integers of greater than 19 digits may have their low-order digits replaced by zeros. Decimal numbers with more than 19 fractional digits may have their fractional part rounded. Exponents larger than the maximum permitted generate a <MAXNUMBER> error. The largest permitted exponent depends on the size of the number that is receiving the exponent.
20
Numbers
For arithmetic operations, a string containing only numeric characters in non-canonical form is functionally identical to the corresponding number. For example, "003" + 3 = 6, "++-2.5000" + -2.5 = -5. For greater-than/less-than operations, a string containing only numeric characters in non-canonical form is functionally identical to the corresponding number. For example, the following statements are true: "003" > 2, "++-2.5000" >= -2.5. For equality operations (=, '=), a string containing only numeric characters in non-canonical form is treated as a string, not a number. For example, the following statements are true: "003" = "003", "003" '= 3, "+003" '= "003".
Some further guidelines concerning parsing strings as numbers: A mixed numeric string is a string that begins with numeric characters, followed by one or more non-numeric characters. For example 7 dwarves. Cach numeric and boolean operations (other than equality operations) commonly parse a mixed numeric string as a number until they encounter a non-numeric character. At that point the rest of the string is ignored. The following example shows arithmetic operations on mixed numeric strings:
WRITE WRITE WRITE WRITE WRITE "7dwarves" + 2,! "+24/7" + 2,! "7,000" + 2,! "7.0.99" + 2,! "7.5.99" + 2,! // // // // // returns returns returns returns returns 9 26 9 9 9.5
A non-numeric string is any string in which a non-numeric character is encountered before encountering a numeric character. Note that a blank space is considered a non-numeric character. Cach numeric and boolean operations (other than equality operations) commonly parse this string as having a numeric value of 0 (zero). The following example shows arithmetic operations on non-numeric strings:
WRITE "dwarves 7" + 2,! WRITE "+ 24/7" + 2,! WRITE "$7000" + 2,! // returns 2 // returns 2 // returns 2
You can prex a string with a plus sign to force its evaluation as a number for equality operations. A numeric string is parsed as a number in canonical form; a non-numeric string is parsed as 0. (A minus sign prex also forces evaluation of a string as a number for equality operations; the minus sign, of course, inverts the sign for a non-zero value.) The following example shows the plus sign forcing numeric evaluation for equality operations:
WRITE WRITE WRITE WRITE WRITE +"7" = 7,! +"+007" = 7,! +"7 dwarves" = 7,! +"dwarves" = 0,! +"" = 0,! // // // // // returns returns returns returns returns 1 1 1 1 1 (TRUE) (TRUE) (TRUE) (TRUE) (TRUE)
Numeric string handling exceptions for individual commands and functions are common, as noted in the Cach ObjectScript Reference.
21
The IEEE double-precision oating point standard is an industry-standard way of representing fractional numbers. IEEE oating point numbers are encoded using binary notation. They have a precision of 53 binary bits, which corresponds to 15.95 decimal digits of precision. (Note that the binary representation does not correspond exactly to a decimal fraction.) Because most decimal fractions cannot be exactly represented in this binary notation, an IEEE oating point number may differ slightly from the corresponding standard Cach oating point number. When an IEEE oating point number is displayed as a fractional number, the binary bits are often converted to a fractional number with far more than 18 decimal digits. This does not mean that IEEE oating point numbers are more precise than standard Cach fractional numbers. IEEE oating point numbers are able to represent larger and smaller numbers than standard Cach numbers, and support the special values INF (innity) and NAN (not a number). For further details, refer to the $DOUBLE function.
You can use the $DOUBLE function to convert a Cach standard oating-point number to an IEEE oating point number. You can use the $DECIMAL function to convert an IEEE oating point number to a Cach standard oating-point number.
3.3 Objects
An object value refers to an instance of an in-memory object. You can assign an object value to any local variable:
Set person = Sample.Person Write person
You cannot assign an object value to a global. Doing so results in a runtime error. Assigning an object value to a variable (or object property) has the side effect of incrementing the objects internal reference count. When the number of references to an object reaches 0, Cach automatically destroys the object (invoke its %OnClose method and remove it from memory).
22
Undefined Values
Set ^x = 10 Write "The value of ^x is: ", ^x
For more information on globals, see the Multidimensional Arrays chapter in this document and the Using Cach Globals document.
$Data returns a boolean that is True (1) if the variable has a value (that is, contains data) and that is False (0) if the variable has no value (that is, contains no data). With two arguments, it performs the test and sets the second arguments variable equal to the tested variables value:
If $Data(Var1,Var2) { Write "Var1 has a value of ",Var2,".",! } Else { Write "Var1 is undefined.",! } Set Var1 = 3 If $Data(Var1,Var2) { Write "Var1 has a value of ",Var2,".",! } Else { Write "Var1 is undefined.",! }
23
For further details on the evaluation of a string as a number, refer to String-to-Number Conversion in the Operators and Expressions chapter of this book.
3.7 Dates
Cach ObjectScript has no built-in date type; instead it includes a number of functions for operating on and formatting date values represented as strings. These date formats include:
ODBC Date
System Time
The following example shows how you can use the different date formats:
Date Formats
Set now = $Horolog Write "Current time and date ($H): ",now,! Set odbc = $ZDateTime(now,3) Write "Current time and date (ODBC): ",odbc,! Set time = $ZH Write "Current system time ($ZH): ",time,!
24
4
Variables
A variable is the name of a location in which a value can be stored. Within Cach ObjectScript, a variable does not have data type associated with it and you do not have to declare it. Commonly, you use the SET command to dene a variable and assign it a value. You can assign a null string ("") value to a variable. Most commands and functions require a variable to be dened before it is used; if the variable is undened, they return an <UNDEFINED> error. However, some operations, such as the READ command, the $INCREMENT function, the $BIT function, and the two-argument form of the $GET function can take an undened variable and dene a value for that variable. The $DATA function can take an undened or dened variable and return its status.
Each of these is used for a specic purpose and may have different scoping rules. Within a program you can use any category of variable in the same way (such as assigning values or passing them as function arguments.)
25
Variables
reserved for system use according to the rules described in Rules and Guidelines for Identiers in the Cach Programming Orientation Guide. The percent (%) character can only be used as the rst character of a local variable name. The other characters of a local variable name may be letters or numbers. On Unicode systems, these other characters may include letter characters above ASCII 255. Any word can be used as a variable name. However, it is strongly recommended that a variable name not be the name of a Cach ObjectScript command or an SQL reserved word. Local variable names are case-sensitive. For example: MYVAR, MyVar, and myvar are three different local variables. Local variable names must be unique for the current process. Other processes may have local variables with the same name. A process-private global or a global may have the same name as a local variable. For example: myvar, ^||myvar, and ^myvar are three different variables. Local variable names are limited to 31 characters. You may specify a name longer than 31 characters, but only the rst 31 characters are used. Therefore, a local variable name must be unique within its rst 31 characters. Local variables can take subscripts. By using subscripts, you can dene a local variable as an array of values. The maximum length of a local variable subscript name is 511 encoded bytes (the corresponding number of characters depends on the subscript name value and the current locale). Exceeding the maximum subscript name length results in a <SUBSCRIPT> error. The number of permitted subscript levels for a local variable is 255. Exceeding the maximum number of local variable subscripts results in a <SYNTAX> error. The local variable maximum subscript name length and maximum number of subscripts are not the same as the global maximums. For naming conventions and other information about the use of subscripts, refer to Global Structure in Using Cach Globals. The %IS utility sets several local variables with all-uppercase names. These variable names should be avoided in situations where %IS is invoked. For further details, see I/O Devices and Commands in the Cach I/O Device Guide.
Note:
The XECUTE command can specify the variables it uses as either private or public. Refer to the section on Variable Declaration and Scope for more on public and private variables.
26
Categories of Variables
You can use the WRITE or ZWRITE command, with no arguments, to list currently dened local variables. You can use the $QSUBSCRIPT function to return the components (name and subscripts) of a specied local variable, or the $QLENGTH function to return the number of subscript layers. You can use the KILL command to delete local variables.
These four prex forms are equivalent, and all four refer to the same process-private global. The rst form (^||name) is the most common, and the one recommended for new code. The second, third, and fourth forms are provided for compatibility with existing code that denes globals. They allow you to specify a variable that determines whether to dene name as a process-private global or a standard global. This is shown in the following example:
SET x=1 // toggle storage type IF x=1 { SET a="^" // for a process-private global } ELSE { SET a="" // for a standard global } SET ^|a|name="a value"
Process-private globals use the following naming conventions: A process-private global name must be a valid identier. Its rst character (after the second vertical bar) must be either a letter or the percent (%) character. The percent (%) character can only be used as the rst character of a processprivate global name. Only percent variables that begin with %Z or %z are available for application code (such as ^||%zmyppg or ^||%Z123); all other percent variables are reserved for system use according to the rules described in Rules and Guidelines for Identiers in the Cach Programming Orientation Guide. The second and subsequent characters of a process-private global name may be letters, numbers, or the period character. A period cannot be used as the rst or last character of the name. A process-private global name may not contain Unicode characters (letter characters above ASCII 255). Attempting to use a letter character above ASCII 255 results in a <WIDE CHAR> error. Process-private global names are case-sensitive. A process-private global name must be unique within its process. Process-private global names are limited to 31 characters, exclusive of the prex characters. You may specify a name longer than 31 characters, but only the rst 31 characters are used. Therefore, a process-private global name must be unique within its rst 31 characters. Process-private globals can take subscripts. By using subscripts, you can dene a process-private global as an array of values. For naming conventions, limitations on the number of subscript levels, and other information about use of subscripts, refer to Global Structure in Using Cach Globals.
27
Variables
The pdf argument can be a process Id or the * wildcard. The options argument can be a string containing any combination of the following: b (return values in bytes), Mnn (return only those process-private variables that use nn or more blocks); S (suppress screen display; used with outle); T (display process totals only). The outle argument is the le path for a le in CSV (comma-separated values) format that will be used to receive ^GETPPGINFO output. The following example writes process-private variables to an output le named ppgout. The S option suppresses screen display; the M500 option limits output to only process-private variables that use 500 or more blocks:
ZNSPACE "%SYS" DO ^GETPPGINFO("*","SM500","/home/myspace/ppgout")
4.1.3 Globals
A global is a special kind of variable that is automatically stored within the Cach database. It is mapped to a specic namespace, and can only be accessed within that namespace, unless an extended reference is used. A global can be accessed by any process. A global persists after the termination of the process that created it. It persists until explicitly deleted. Cach treats a SET or KILL of a global as a journaled transaction event; rolling back the transaction reverses these operations. Locks may be used to prevent access by other processes to changes to a global until the transaction that made the changes has been committed. Refer to the Transaction Processing chapter for further details. Within a Cach ObjectScript program, you can use a global in the same way as any other variable. Syntactically, a global name is distinguished by a caret ( ^ ) character followed by a letter or a % character:
Set mylocal = "This is a local variable" Set ^myglobal = "This is a global stored in the current namespace"
The naming conventions for globals are as follows: A global consists of a global prex and a global name. The global prex is commonly a caret (^) character, specifying a global in the current namespace. A global prex can also be an extended reference, such as ^|"samples"|, specifying a global in another namespace. A global name must be a valid identier. Its rst character (after the prex character(s)) must be either a letter or the percent (%) character. Only percent variables that begin with %Z or %z are available for application code (such as ^||%zmyppg or ^||%Z123); all other percent variables are reserved for system use according to the rules described in Rules and Guidelines for Identiers in the Cach Programming Orientation Guide. The second and subsequent characters of a global name may be letters, numbers, or the period character. A period cannot be used as the rst or last character of the name. A global name may not contain Unicode characters (letter characters above ASCII 255). Attempting to use a letter character above ASCII 255 results in a <WIDE CHAR> error. Global names are case-sensitive.
28
Categories of Variables
A global name must be unique within its namespace. Global names are limited to 31 characters, exclusive of the prex characters. You may specify a name longer than 31 characters, but only the rst 31 characters are used. Therefore, a global name must be unique within its rst 31 characters. Globals can take subscripts. By using subscripts, you can dene a global as an array of values. For naming conventions, limitations on the number of subscript levels, and other information about use of subscripts, refer to Global Structure in Using Cach Globals.
Optionally, a global may specify an extended reference that denes its namespace or directory using a pair of vertical bars or square brackets immediately after the caret characters (for example: ^|"samples"|myglobal or ^|""|myglobal). These extended global references should not be confused with process-private globals. You can use the $ZREFERENCE special variable to determine the name of the most recently used global. You can use the $QSUBSCRIPT function to return the components of a specied global, or the $QLENGTH function to return the number of subscript layers. For much more information on globals, refer to Using Cach Globals.
For local variables, the maximum number of subscript levels is 255. For global variables, the maximum number of subscript levels depends on the length of the subscript names. For subscript naming conventions and limits, refer to the Global Structure chapter in Using Cach Globals.
The special variable $HOROLOG stores the current system date and time. The SET command uses this special variable to set the user-dened local variable starttime to this value. The HANG command then suspends the program for 5 seconds. Finally, the two $ZDATETIME functions return starttime and the current system date and time in a user-readable format.
29
Variables
Many special variables are read-only; they cannot be set using the SET command. Other special variables, such as $DEVICE, are read-write, and can be set using the SET command. Special variables cannot take subscripts. Special variables cannot be incremented using the $INCREMENT function or killed using the KILL command. Special variables can be displayed using the WRITE or ZZDUMP commands; they cannot be displayed using the ZWRITE command. Refer to the Cach ObjectScript Reference for a list and detailed descriptions of the special variables.
There are some limitations for the use of property references as variables. A property of any type cannot be modied using SET $BIT() or SET $LISTBUILD(); a non-multidimensional property cannot be modied using SET $EXTRACT(), SET $LIST(), or SET $PIECE(). $DATA(), $GET(), and $INCREMENT() can only take a property if the property is multidimensional. Properties cannot be used with the MERGE command. These operations can be done within an object method using the special instance variable syntax i%PropertyName.
30
Write "Here are concatenations of int and num:",! Write "Concatenating int: ","I found " _ int _ " apples.",! Write "Concatenating num: ","There are " _ num _ " pounds per kilogram.",!
Note:
The value of person is that of an object reference (OREF) converted into a string. This string or its value cannot be used to load an object from the database.
You can refer to the methods and properties of an object using dot syntax:
Set person.Name = "El Vez"
You can determine if a variable contains an object using the $ISOBJECT function:
Set str = "A string" Set person = ##class(Sample.Person).%New() Write "Is string an object? ", $IsObject(str),! Write "Is person an object? ", $IsObject(person),!
You cannot use assign an object value to a global. Doing so will result in a runtime error. Assigning an object value to a variable (or object property) has the side effect of incrementing the objects internal reference count. When the number of references to an object reaches 0, Cach will automatically destroy the object (invoke its %OnClose method and remove it from memory). For example:
31
Variables
Set person = ##class(Sample.Person).%New() // one reference to Person Set alias = person // two references Set person = "" // 1 reference Set alias = "" // no references left, object destroyed
These mechanisms are described in greater detail in the User-dened Code chapter.
where VariableName is the variable for which you are naming a data type and DataTypeName species that data type. Cach Studio provides a menu from which you can select the DataTypeName value. #Dim also allows you to specify an initial value for a variable, as in the following:
#Dim President As %String = "Obama"
32
5
Operators and Expressions
Cach supports many different operators, which perform various actions, including mathematical actions, logical comparisons, and so on. Operators act on expressions, which are variables or other entities that ultimately evaluated to a value. This chapter describes expressions and the various ObjectScript operators. It contains the following topics: Introduction to Operators and Expressions String-to-Number Conversion Arithmetic Operators Logical Comparison Operators String Operators Numeric Relational Operators String Relational Operators Pattern Matching Indirection
33
34
Here, because of the parentheses, four and seven are added, as are six and six; this results in the logical expression 11 > 12, which is false. Compare this to:
Set Value = (4 + 7 > 6 + 6) // 7 Write Value
In this case, precedence proceeds from left to right, so four and seven are added. Their sum, eleven, is compared to six; since eleven is greater than six, the result of this logical operation is one (TRUE). One is then added to six, and the result is seven. Note that the precedence even determines the result type, since the rst expressions nal operation results in a boolean and the second expressions nal operation results in a numeric. The following example shows multiple levels of nesting:
WRITE WRITE WRITE WRITE 1+2*3-4*5,! // returns 25 1+(2*3)-4*5,! // returns 15 1+(2*(3-4))*5,! // returns -5 1+(((2*3)-4)*5),! // returns 11
Precedence from the innermost nested expression and proceeds out level by level, evaluating left to right at each level. Tip: For all but the simplest ObjectScript expressions, it is good practice to fully parenthesize expressions. This is to eliminate any ambiguity about the order of evaluation and to also eliminate any future questions about the original intention of the code.
For example, because the && operator, like all operators, is subject to left-to-right precedence, the nal statement in the following code fragment evaluates to 0:
35
This is because the evaluation occurs as follows: 1. 2. 3. 4. The rst action is to check if x is dened and has a non-zero value. Since x equals 3, evaluation continues. Next, there is a check if y is dened and has a non-zero value. Since y equals 2, evaluation continues. Next, the value of 3 && 2 is evaluated. Since neither 3 nor 2 equal 0, this expression is true and evaluates to 1. The next action is to compare the returned value to 2. Since 1 does not equal 2, this evaluation returns 0.
For those accustomed to many programming languages, this is an unexpected result. If the intent is to return True if x is dened with a non-zero value and if y equals 2, then parentheses are required:
Set x = Set y = If x && Write Write 3 2 (y = 2) { "True",! } Else { "False",! }
Cach ObjectScript rst evaluates var1, then the function $$ONE, then var2. It then multiplies var2 by 5. Finally, Cach ObjectScript tests to see if the result of the addition is equal to the value in var1. If it is, it executes the DO command to call the Test routine. As another example, consider the following logical expression:
SET var8=25,var7=23 IF var8 = 25 * (var7 < 24) { WRITE !,"True" } ELSE { WRITE !,"False" }
Cach evaluates expressions strictly left-to-right. The programmer must use parentheses to establish any precedence. In this case, Cach rst evaluates var8=25, resulting in 1. It then multiplies this 1 by the results of the expression in parentheses. Because var7 is less than 24, the expression in parentheses evaluates to 1. Therefore, Cach multiplies 1 * 1, resulting in 1 (true).
5.1.3 Expressions
An ObjectScript expression is one or more tokens that can be evaluated to yield a value. The simplest expression is simply a literal or variable:
Set expr = 22 Set expr = "hello" Set expr = x
You can create more complex expressions using arrays, operators, or one of the many ObjectScript functions:
Set Set Set Set Set expr expr expr expr expr = = = = = +x x + 22 array(1) ^data("x",1) $Length(x)
36
An expression may consist of, or include, an object property, instance method call, or class method call:
Set expr = person.Name Set expr = obj.Add(1,2) Set expr = ##class(MyApp.MyClass).Method()
You can directly invoke an ObjectScript routine call within an expression by placing $$ in front of the routine call:
Set expr = $$MyFunc^MyRoutine(1)
Expressions can be classied according to what kind of value they return: An arithmetic expression contains arithmetic operators, gives a numeric interpretation to the operands, and produces a numeric result:
Set expr = 1 + 2 Set expr = +x Set expr = a + b
Note that a string used within an arithmetic expression is evaluated as a numeric value (or 0 if it is not a valid numeric value). Also note that using the unary addition operator (+) will implicitly convert a string value to a numeric value. A string expression contains string operators, gives a string interpretation to the operands, and produces a string result.
Set expr = "hello" Set expr = "hello" _ x
A logical expression contains relational and logical operators, gives a logical interpretation to the operands, and produces a boolean result: TRUE (1) or FALSE (0):
Set expr = 1 && 0 Set expr = a && b Set expr = a > b
When an expression contains logical operators, Cach ObjectScript evaluates all operands, even when the Boolean result is known before evaluating all operands. In the following routine, all functions are executed even though the rst function returns a FALSE which automatically makes the result of the entire expression FALSE.
37
5.1.4 Assignment
Within ObjectScript the SET command is used along with the assignment operator ( = ) to assign a value to a variable. The right-hand side of an assignment command is an expression:
Set value = 0 Set value = a + b
Within ObjectScript it is also possible to use certain functions on the left-hand side of an assignment command:
Set pies = "apple,banana,cherry" Write "Before: ",pies,! // set the 3rd comma-delimited piece of pies to coconut Set $Piece(pies,",",3) = "coconut" Write "After: ",pies
Note that the NumericGroupSeparator property value (the , character, by default) is not considered a numeric character. Therefore, the string "123,456" is a partially numeric string that resolves to the number "123".
38
Arithmetic Operators
Numeric strings and partial numeric strings are converted to canonical form prior to arithmetic operations (such as addition and subtraction) and greater than/less than comparison operations (<, >, <=, >=). Numeric strings are not converted to canonical form prior to equality comparisons (=, '=), because these operators are also used for string comparisons. The following example shows arithmetic comparisons of numeric strings:
WRITE WRITE WRITE WRITE "3" + 4,! "003.0" + 4,! "++--3" + 4,! "3 blind mice" + 4,! // // // // returns returns returns returns 7 7 7 7
The following example shows less than (<) comparisons of numeric strings:
WRITE WRITE WRITE WRITE "3" < 4,! "003.0" < 4,! "++--3" < 4,! "3 blind mice" < 4,! // // // // returns returns returns returns 1 1 1 1
The following example shows equality comparisons of numeric strings. Non-canonical numeric strings are compared as character strings, not as numbers. Note that 0 is a non-canonical numeric string, and is therefore compared as a string, not a number:
WRITE WRITE WRITE WRITE WRITE WRITE WRITE WRITE "4" = 4.00,! "004.0" = 4,! "++--4" = 4,! "4 horsemen" = 4,! "-4" = -4,! "0" = 0,! "-0" = 0,! "-0" = -0,! // // // // // // // // returns returns returns returns returns returns returns returns 1 0 0 0 1 1 0 0
39
If the string has no leading numeric characters, the unary positive operator gives the operand a value of zero. For example:
Write + "Thirty-two dollars and 64 cents" // 0
The unary positive operator has no effect on numeric values. It does not alter the sign of either positive or negative numbers. For example:
Set x = -23 Write " x: ", x,! // -23 Write "+x: ",+x,! // -23
If its operand has a string value, the unary negative operator interprets it as a numeric value before reversing its sign. This numeric interpretation is exactly the same as that performed by the unary positive operator, described above. For example:
Set x = -23 Write -"32 dollars and 64 cents" // -32
Cach ObjectScript gives the unary negative operator precedence over the binary arithmetic operators. Cach ObjectScript rst scans a numeric expression and performs any unary negative operations. Then, Cach ObjectScript evaluates the expression and produces a result. In the following example, Cach ObjectScript scans the string and encounters the numeric value of 2 and stops there. It then applies the unary negative operator to the value and uses the concatenate operator (_) to concatenate the value Rats from the second string to the numeric value.
Write -"2Cats"_"Rats" // -2Rats
To return the absolute value of a numeric expression, use the $ZABS function.
40
Arithmetic Operators
The following example performs string arithmetic on two operands that have leading digits, adding the resulting numerics:
Write "4 Motorcycles" + "5 bicycles" // 9
The following example illustrates that leading zeros on a numerically evaluated operand do not affect the results the operator produces:
Write "007" + 10 // 17
The following example performs string arithmetic on two operands that have leading digits, subtracting the resulting numerics:
Write "8 apples" - "4 oranges" // 4
If the operand has no leading numeric characters, Cach ObjectScript assumes its value to be zero. For example:
Write "8 apples" - "four oranges" // 8
The following example performs string arithmetic on two operands that have leading digits, multiplying the resulting numerics:
Write "8 apples" * "4 oranges" // 32
If an operand has no leading numeric characters, Binary Multiply assigns it a value of zero.
Write "8 apples"*"four oranges" // 0
41
The following example performs string arithmetic on two operands that have leading digits, dividing the resulting numerics:
Write "8 apples" / "4 oranges" // 2
If the operand has no leading numeric characters, Binary Divide assumes its value to be zero. For example:
Write "eight apples" / "4 oranges" // 0 // "8 apples"/"four oranges" generates a <DIVIDE> error
Note that the second of these operations is invalid. Dividing a number by zero is not allowed. Cach ObjectScript returns a <DIVIDE> error message.
0 to the power of a negative number results in an error: Cach negative numbers generate an <ILLEGAL VALUE> error; $DOUBLE negative numbers generate a <DIVIDE> error.
num**0: Any non-zero number (positive or negative) raised to the power of zero is 1. This includes $DOUBLE("INF")**0. 1**n: 1 raised to the power of any number (positive, negative, or zero) is 1. -1**n: -1 raised to the power of zero is 1. -1 raised to the power of 1 or -1 is -1. For exponents larger than 1, see
below.
num**n: A positive number (integer or fractional) raised to any power (integer or fractional, positive or negative)
returns a positive number. A negative number (integer or fractional) raised to the power of an odd integer (positive or negative) returns a negative number.
-num**.n: Attempting to raise a negative number to the power of a fractional number results in an <ILLEGAL
VALUE> error.
$DOUBLE("INF")**n: An innite number (positive or negative) raised to the power of 0 is 1. An innite number
(positive or negative) raised to the power of any positive number (integer, fractional, or INF) is INF. An innite number (positive or negative) raised to the power of any negative number (integer, fractional, or INF) is 0.
42
Arithmetic Operators
$DOUBLE("NAN"): NAN on either side of the exponentiation operator always returns NAN, regardless of the value
of the other operand. Very large exponents may result in overow and underow values:
num**nnn: A positive or negative number greater than 1 with a large positive exponent value (such as 9**153 or -9.2**152) generates a <MAXNUMBER> error. num**-nnn: A positive or negative number greater than 1 with a large negative exponent value (such as 9**-135 or -9.2**-134) returns 0. .num**nnn: A positive or negative number less than 1 with a large positive exponent value (such as .22**196 or -.2**184) returns 0. .num**-nnn: A positive or negative number less than 1 with a large negative exponent value (such as .22**-196 or -.2**-184) generates a <MAXNUMBER> error.
An exponent that exceeds the maximum value supported by Cach numbers either issues a <MAXNUMBER> error or automatically converts to an IEEE double-precision oating point number. This automatic conversion is specied by using either the TruncateOverow() method of the %SYSTEM.Process class on a per-process basis, or the TruncateOverow property of the Config.Miscellaneous class on a system-wide basis. For further details, refer to the $DOUBLE function. The following examples performs exponentiation on two numeric literals:
Write "9 ** 2 = ",9 ** 2,! // 81 Write "9 ** -2 = ",9 ** -2,! // .01234567901234567901 Write "9 ** 2.5 = ",9 ** 2.5,! // 242.9999999994422343
The following example performs string arithmetic. Exponentiation uses any leading numeric characters as the values of the operands and produces a result.
Write "4 apples" ** "3 oranges" // 64
If an operand has no leading numeric characters, Exponentiation assumes its value to be zero. The following example demonstrates how to use exponentiation to nd the square root of a number.
Write 256 ** .5 // 16
The following example performs string arithmetic. Integer Divide uses any leading numeric characters as the values of the operands and produces an integer result.
Write "8 Apples" \ "3.1 oranges" // 2
43
If an operand has no leading numeric characters, Cach ObjectScript assumes its value to be zero. If you attempt integer division with a zero-valued divisor, Cach ObjectScript returns a <DIVIDE> error.
The following example performs string arithmetic. When operating on strings, they are converted to numeric values (according the values described in the section Variable Typing and Conversion) before the modulo operator is applied. Hence, the following two expressions are equivalent:
Write "8 apples" # "3 oranges",! Write 8 # 3 // 2 // 2
Because Cach evaluates a string with no leading numeric characters to zero, a right operand of this kind yields a DIVIDE error.
Unary Not with a comparison operator inverts the sense of the operation it performs. It effectively inverts the result of the operation. For example, the following statement displays a result of FALSE (0):
WRITE 3>5
44
However, to properly perform this logical comparison, you must use parentheses to nest the other operations. The following example gives the expected results:
SET x=1,y=0 WRITE (x=1)!(y=0) // Returns TRUE as expected
The following examples evaluate two nonzero-valued operands as TRUE and produces a value of TRUE (1).
Set A=-4,B=1 Write A&B // TRUE (1)
returns 1.
Set A=-4,B=1 Write A&&B // TRUE (1)
returns 1. The following examples evaluate one true and one false operand and produces a value of FALSE (0).
Set A=1,B=0 Write "A = ",A,! Write "B = ",B,! Write "A&B = ",A&B,! // FALSE (0) Set A=1,B=0 Write "A&&B = ",A&&B,! // FALSE (0)
both return FALSE (0). The following examples show the difference between the & operator and the && operator. In these examples, the left operand evaluates to FALSE (0) and the right operand is not dened. The & and && operators respond differently to this situation: The & operator attempts to evaluate both operands, and fails with an <UNDEFINED> error.
Kill B Set A=0 Write A&B
45
The && operator evaluates only the left operand, and produces a value of FALSE (0).
Kill B Set A=0 Write A&&B // FALSE (0)
The Not And operation reverses the truth value of the & Binary And applied to both operands. It produces a value of TRUE (1) when either or both operands are false. It produces a value of FALSE when both operands are TRUE. The && Binary And operator cannot be prexed with a Unary Not operator: the format '&& is not supported. However, the following format is supported:
'(operand && operand)
The following example performs two equivalent Not And operations. Each evaluates one FALSE (0) and one TRUE (1) operand and produces a value of TRUE (1).
Set A=0,B=1 Write !,A'&B // Returns 1 Write !,'(A&B) // Returns 1
The following example performs a Not And operation by performing a && Binary And operation and then using a Unary Not to invert the result. The && operation tests the rst operand and, because the boolean value is FALSE (0), && does not test the second operand. The Unary Not inverts the resulting boolean value, so that the expression returns TRUE (1):
Set A=0 Write !,'(A&&B) // Returns 1
5.4.4 Binary Or
Binary Or produces a result of TRUE (1) if either operand has a value of TRUE or if both operands have a value of TRUE (1). Binary Or produces a result of FALSE (0) only if both operands are FALSE (0). There are two forms to Binary Or: ! (exclamation point) and || (two vertical bars). The ! operator evaluates both operands and returns a value of FALSE (0) if both operand evaluates to a value of zero. Otherwise it returns a value of TRUE (1). The || operator evaluates the left operand. If the left operand evaluates to a nonzero value, the || operator returns a value of TRUE (1) without evaluating the right operand. Only if the left operand evaluates to zero does the || operator then evaluate the right operand. It returns a value of FALSE (0) if the right operand also evaluates to a value of zero. Otherwise it returns a value of TRUE (1).
The following examples evaluate two TRUE (nonzero) operands, apply the Binary Or to them, and produces a TRUE result:
Set A=5,B=7 Write "A!B = ",A!B,! Set A=5,B=7 Write "A||B = ",A||B,!
both return TRUE (1). The following examples evaluate one false and one true operand, apply the Binary Or to them, and produces a TRUE result:
46
String Operators
Set A=0,B=7 Write "A!B = ",A!B,! Set A=0,B=7 Write "A||B = ",A||B,!
both return TRUE (1). The following examples evaluate two false operands and produces a result with a value of FALSE.
Set A=0,B=0 Write "A!B = ",A!B,! Set A=0,B=0 Write "A||B = ",A||B,!
The Not Or operation produces a result of TRUE (1) if both operands have values of FALSE. The Not Or operation produces a result of FALSE (0) if either operand has a value of TRUE or if both operands are TRUE. The || Binary Or operator cannot be prexed with a Unary Not operator: the format '|| is not supported. However, the following format is supported:
'(operand || operand)
The following Not Or examples evaluate two false operands and produce a TRUE result.
Set A=0,B=0 Write "A'!B = ",A'!B // Returns 1
// Returns 1
The following Not Or examples evaluate one TRUE and one false operand and produce a result of FALSE.
Set A=0,B=1 Write "A'!B = ",A'!B // Returns 0
// Returns 0
The following Not Or (||) example evaluates the left operand, and because it is TRUE (1) does not evaluate the right operand. The Unary Not inverts the resulting boolean value, so the expression returns FALSE (0).
Set A=1 Write "'(A||B) = ",'(A||B) // Returns 0
47
returns Highchair . The following example concatenates two numeric literals and a string:
Write 609_"-"_24
returns 609-24. The following example concatenates two strings and the null string:
Set A="ABC"_""_"DEF" Write A
returns ABCDEF . The null string has no effect on the length of a string. You can concatenate an innite number of null strings to a string. The default maximum string size is 32,767 characters. To increase the maximum string size to 3,641,144 characters, enable long strings; for more information on long strings, see the Long Strings section in the Data Types and Values chapter. Concatenation that creates an extremely long string can result in a <STORE> error, when the concatenated string is too long to be stored in a variable. In the event of a <STORE> error, the variable being enlarged by concatenation retains its value prior to the concatenation.
48
than its right operand. Cach ObjectScript returns a Boolean result of FALSE (0) if the left operand has an equal or greater numeric value than the right operand. For example:
Write 9 < 6
returns 0.
Write 22 < 100
returns 1.
returns 0.
Write 22 > 100
returns 0.
Cach ObjectScript produces a result of TRUE (1) when the left operand is numerically greater than or equal to the right operand. It produces a result of FALSE (0) when the left operand is numerically less than the right operand. You can express the Greater Than or Equal To operation in any of the following ways:
operand_A >= operand_B operand_A '< operand_B '(operand_A < operand_B)
Cach ObjectScript produces a result of TRUE (1) when the left operand is numerically less than or equal to the right operand. It produces a result of FALSE (0) when the left operand is numerically greater than the right operand. You can express the Less Than or Equal To operation in any of the following ways:
49
The following example tests two variables in a Less Than or Equal To operation. Because both variables have an identical numerical value, the result is TRUE.
Set A="55",B="55" Write A'>B
returns 1.
returns TRUE (1). Binary Equals does not imply any numeric interpretation of either operand. For example, the following statement produces a value of FALSE (0), even though the two operands are numerically identical:
Write "007"="7"
returns FALSE (0). You can use Binary Equals to test for numeric equality if both operands have a numeric value. For example:
Write 007=7
returns TRUE (1). You can also force a numeric conversion by using the Unary Arithmetic Positive. For example:
Write +"007"="7"
returns TRUE (1). If the two operands are of different types, both operands are converted to strings and those strings are compared. Note that this may cause inaccuracy because of rounding and the number of signicant digits for conversion to string. For example:
Write "007"=7,! // converts 7 to "7", so FALSE (0) Write 007="7",! // converts 007 to "7", so TRUE (1) Write 17.1=$DOUBLE(17.1),! // converts both numbers to "17.1", so TRUE (1) Write 1.2345678901234567=$DOUBLE(1.2345678901234567),! // compares "1.2345678901234567" to "1.23456789012346", so FALSE (0)
50
Not Equals reverses the truth value of the Binary Equals operator applied to both operands. If the two operands are not identical, the result is TRUE (1). If the two operands are identical, the result is FALSE (0).
returns TRUE (1). The following example tests whether P contains S. Because the character sequence in the strings is different (a period in P and an exclamation point in S), the result is FALSE (0).
Set P="Let's play.",S="Let's play!" Write P[S
returns 1.
51
Cach ObjectScript returns a value of TRUE if the rst unique character in the left operand has a higher ASCII value than the corresponding character in the right operand (that is, if the character in the left operand comes after the character in the right operand in ASCII collating sequence.) If the right operand is shorter than the left operand, but otherwise identical, Cach ObjectScript also returns a value of TRUE. Cach ObjectScript returns a value of FALSE if any of the following conditions prevail: The rst unique character in the left operand has a lower ASCII value than the corresponding character in the right operand. The left operand is identical to the right operand. The left operand is shorter than the right operand, but otherwise identical.
The following example tests whether the string LAMPOON follows the string LAMP in ASCII collation order. The result is TRUE.
Write "LAMPOON"]"LAMP"
returns TRUE (1). The following example tests whether the string in B follows the string in A. Because BO follows BL in ASCII collation sequence, the result is TRUE.
Set A="BLUE",B="BOY" Write B]A
If all characters in the operands are identical or if the rst unique character in operand A has a lower ASCII value that the corresponding character in operand B, the Not Follows operation returns a result of TRUE. If the rst unique character in operand A has a higher ASCII value that the corresponding character in operand B, the Not Follows operation returns a result of FALSE. In the following example, because C in CDE does follow A in ABC, the result is FALSE.
Write "CDE"']"ABC",! Write '("CDE"]"ABC")
52
Pattern Matching
If operand A is identical to operand B or if operand B sorts after operand A, then Cach ObjectScript returns a result of TRUE. If operand A sorts after operand B, Cach ObjectScript returns a result of FALSE.
These pattern match systems are wholly separate, and cannot be combined. The Cach pattern match operator tests whether the characters in its left operand are correctly specied by the pattern in its right operand. It returns a boolean value. The pattern match operator produces a result of TRUE (1) when the pattern correctly species the pattern of characters in the left operand. It produces a result of FALSE (0) if the pattern does not correctly specify the pattern of characters in the left operand. For example, the following tests if the string ssn contains a valid U.S. Social Security Number (3 digits, a hyphen, 2 digits, a hyphen, and 4 digits):
SET ssn="123-45-6789" SET match = ssn ?3N1"-"2N1"-"4N WRITE match
The left operand (the test value) and the right operand (the pattern) may be separated by one or more blank spaces, or not separated by blank spaces, as shown in the following equivalent program example:
SET ssn="123-45-6789" SET match = ssn?3N1"-"2N1"-"4N WRITE match
No white space is permitted following the ? operator. White space within the pattern must be within a quoted string and is interpreted as being part of the pattern. The general format for a pattern match operation is as follows:
operand?pattern
53
operand pattern
An expression that evaluates to a string or number, the characters of which you want to test for a pattern. A pattern match sequence beginning with a ? character (or with ? for a not-match test). The pattern sequence can be one of the following: a sequence of one or more pattern-elements; an indirect reference that evaluates to a sequence of one or more pattern-elements
A pattern-element consists of one of the following: repeat-count pattern-codes repeat-count literal-string repeat-count alternation repeat-count A repeat count the exact number of instances to be matched. The repeat-count can evaluate to an integer or to the period wildcard character (.). Use the period to specify any number of instances. One or more pattern codes. If more than one code is specified, the pattern is satisfied by matching any one of the codes. A literal string enclosed in double quotes. A set of pattern-element sequences to choose from (in order to perform pattern matching on a segment of the operand string). This provides logical OR capability in pattern specifications.
Use a literal string enclosed in double quotes in a pattern if you want to match a specic character or characters. In other situations, use the special pattern codes provided by Cach ObjectScript. Characters associated with a particular pattern code are (to some extent) locale-dependent. The following table shows the available pattern codes and their meanings:
54
Pattern Matching
C E L
N P
R B M ZFWCHARZ
ZHWKATAZ
Pattern codes are not case-sensitive; you can specify them in either uppercase or lowercase. For example, ?5N is equivalent to ?5n. You can specify multiple pattern codes to match a specic character or string. For example, ?1NU matches either a number or an uppercase letter.
55
As stated in the Cach Glossary of Terms, the ASCII character set refers to an extended, 8-bit character set, rather than the more limited, 7-bit character set. Note: Pattern matching with double-quote characters can yield inconsistent results, especially when data is supplied from Cach implementations using different NLS locales. The straight double-quote character ($CHAR(34) = ") matches as a punctuation character. Directional double-quote characters (curly quotes) do not match as punctuation characters. The 8-bit directional double-quote characters ($CHAR(147) = and $CHAR(148) = ) match as control characters. The Unicode directional double-quote characters ($CHAR(8220) = and $CHAR(8221) = ) do not match as either punctuation or control characters.
The Pattern Match operator differs from the Binary Contains ([) operator. The Binary Contains operator returns TRUE (1) even if only a substring of the left-hand operand matches the right-hand operand. Also, Binary Contains expressions do not provide the range of options available with the Pattern Match operator. In Binary Contains expressions, you can use only a single string as the right-hand operand, without any special codes. For example, assume that variable var2 contains the value abc . Consider the following Pattern Match expression:
Set match = var2?2L
This sets match to FALSE (0) because var2 contains three lowercase characters, not just two. Here are some examples of basic pattern matching:
patternmatchtest Set var = "O" Write "Is the letter O",! Write "...an alphabetic character? " Write var?1A,! Write "...a numeric character? " Write var?1N,! Write "...an alphabetic or ",!," Write var?1AN,! Write "...an alphabetic or ",!," Write var?1AZFWCHARZ,! Write "...a numeric or ",!," Write var?1ZHWKATAZN a numeric character? " a ZENKAKU Kanji character? "
You can extend the scope of a pattern code by specifying: How many times a pattern can occur Multiple patterns A combination pattern An indenite pattern An alternating pattern
56
Pattern Matching
The expression returns a result of TRUE (1) even though var3 contains only three occurrences of AB . As another example, consider the following expression:
Set match = var3?1.6A
This expression checks to see whether var3 contains from one to six alphabetic characters. A result of FALSE (0) is returned only if var3 contains zero or more than six characters. If you omit either n, Cach ObjectScript supplies a default. The default for the rst n is zero (0). The default for the second n is any number. Consider the following example:
Set match = var3?1."AB"
This example returns a result of TRUE (1) as long as var3 contains at least one occurrence of the pattern string AB .
This expression checks for a date value in the format mm/dd/yy. The string 4/27/98 would return FALSE (0) because the month has only one digit. To detect both one and two digit months, you could modify the expression as:
Set match = date?1.2N1"/"2N1"/"2N
Now the rst pattern match (1.2N) accepts either 1 or 2 digits. It uses the optional period (.) to dene a range of acceptable occurrences as described in the previous section.
This expression checks for a pattern in which three numeric digits are followed by zero to four lowercase alphabetic characters. The expression returns TRUE (1) only if the target operand contains exactly one occurrence of the combined pattern. For example, the strings 345g and 345gj would qualify, but 345gjhkbc 345gj276hkbc would not.
This expression returns TRUE (1) if the target operand contains zero, one, or more than one numeric character, and contains no characters of any other type.
57
You can have nested alternation patterns, as in the following pattern match expression:
Set match = value?.(.(1A,1N),1P)
For example, you may want to validate a U.S. telephone number. At a minimum, the phone number must be a 7-digit phone number with a hyphen (-) separating the third and fourth digits. For example:
nnn-nnnn
The phone number can also include a three-digit area code that must either have surrounding parentheses or be separated from the rest of the number by a hyphen. For example:
(nnn) nnn-nnnn nnn-nnn-nnnn
The following pattern match expressions describe three valid forms of a U.S. telephone number:
Set match = phone?3N1"-"4N Set match = phone?3N1"-"3N1"-"4N Set match = phone?1"("3N1") "3N1"-"4N
Without an alternation, the following compound Boolean expression would be required to validate any form of U.S. telephone number.
Set match = ( (phone?3N1"-"4N) || (phone?3N1"-"3N1"-"4N) || (phone?1"("3N1") "3N1"-"4N) )
With an alternation, the following single pattern can validate any form of U.S. telephone number:
Set match = phone?.1(1"("3N1") ",3N1"-")3N1"-"4N
The alternation in this example allows the area code component of the phone number to be satised by either 1"("3N1") " or 3N1"-". The alternation count range of 0 to 1 indicates that the operand phone can have 0 or 1 area code components. Alternations with a repeat count greater than one (1) can produce many combinations of acceptable patterns. The following alternation matches the string shown and matches 26 other three-character strings.
Set match = "CAT"?3(1"C",1"A",1"T")
58
Indirection
Set match = "RAW BAR"?.U1P2U
1. 2.
The rst .E matches the substring ///// , the 1U matches the A , and the second .E matches the substring #####B$$$$$ . The rst .E matches the substring /////A##### , the 1U matches the character B , and the second .E matches the substring $$$$$ . As long as at least one interpretation of the expression is TRUE (1), then the expression has a value of TRUE.
Not Match reverses the truth value of the Pattern Match. If the characters in the operand cannot be described by the pattern, then Not Match returns a result of TRUE (1). If the pattern matches all of the characters in the operand, then Not Match returns a result of FALSE (0). The following example uses the Not Match operator:
WRITE WRITE WRITE WRITE WRITE !,"abc" !,"abc" !,"abc" !,"abc" !,"abc" ?3L '?3L ?3N '?3N '?3E
5.9 Indirection
The Cach ObjectScript indirection operator (@) allows you to assign values indirectly to variables. Indirection is a technique that provides dynamic runtime substitution of part or all of a command line, a command, or a command argument by the contents of a data eld. Cach performs the substitution before execution of the associated command. Although indirection can promote more economical and more generalized coding than would be otherwise available, it is never essential. You can always duplicate the effect of indirection by other means, such as by using the XECUTE command.
59
You should use indirection only in those cases where it offers a clear advantage. Indirection can have an impact on performance because Cach performs the required evaluation at runtime, rather than during the compile phase. Also, if you use complicated indirections, be sure to document your code clearly. Indirections can sometimes be difcult to decipher. Indirection is specied by the indirection operator (@) and, except for subscript indirection, takes the form: @variable where variable identies the variable from which the substitution value is to be taken. The variable can be an array node. The following routine illustrates that indirection looks at the entire variable value to its right.
indir ; gsm;11:37 PM 13 Jun 2000 Set x = "a" Set x(3) = "b" ;The next line will do b, NOT a(3) DO @x(3) Quit a(i) Write !,"At a" Quit b Write !,"At b" Quit
Cach recognizes ve types of indirection: Name indirection Pattern indirection Argument indirection Subscript indirection $TEXT argument indirection
Which type of indirection is performed depends on the context in which the @variable occurs. Each type of indirection is described separately below. Indirection cannot be used with dot syntax. This is because dot syntax is parsed at compile time, not at runtime.
Important:
If a call attempts to use indirection to get or set the value of object properties, it may result in an error. Do not use calls of this kind, as they attempt to bypass property accessor methods (<PropertyName>Get and <PropertyName>Set). Instead, use the $CLASSMETHOD, $METHOD, and $PROPERTY) functions, which are designed for this purpose; see the section Dynamically Accessing Objects in the Using Objects with Cach ObjectScript chapter of Using Cach Objects for more information.
When you use indirection to reference a line label, the value of the indirection must be a syntactically valid line label. In the following example, Cach sets D to: The value of the line label FIG if the value of N is 1.
60
Indirection
The value of the line label GO if the value of N is 2. The value of STOP in all other cases.
Later, Cach passes control to the label whose value was given to D.
B Set D = $SELECT(N = 1:"FIG",N = 2:"GO",1:"STOP") ; ... LV GoTo @D
When you use indirection to reference a routine name, the value of the indirection must be a syntactically valid routine name. In the following example, name indirection is used on the GoTo command to supply the appropriate subroutine name. At execution time, the contents of variable loc are substituted for the expected name. If the indirection operator were omitted, Cach would return a <NOLINE> error message (or GoTo a label called loc, if it existed).
Start Read !,"Enter choice (1, 2, or 3): ",num Set loc = "Choice"_num GoTo @loc Quit Choice1 ; ... Choice2 ; ... Choice3 ; ...
Name indirection can substitute only a name value. The second Set command in the following example returns an error message because of the context. When evaluating the expression to the right of the equal sign, Cach interprets @var1 as an indirect reference to a variable name, not a numeric value.
Set var1 = "5" Set x = @var1*6
The use of indirection with pattern matching is a convenient way to localize the patterns used in an application. In this case, you could store the patterns in separate variables and then reference them with indirection during the actual pattern tests.
61
(This is also an example of name indirection.) To port such an application, you would have to modify only the pattern variables themselves.
In this case, @loc is an example of argument indirection because it supplies the complete form of the argument (that is, label^routine). In the name indirection example, @loc is an example of name indirection because it supplies only part of the argument (the label name, whose entry point is assumed to be in the current, rather than a separate, routine). In the following example, the second Set command is an example of name indirection (only part of the argument, the name of the variable), while the third Set command is an example of argument indirection (the entire argument).
Set a = "var1",b = "var2 = 3*4" Set @a = 5*6 Set @b Write "a = ",a,! Write "b = ",b,!
To write out a range of records (say, the rst 10), you could modify the code so that the Write is executed within a FOR loop. For example,
FOR i = 1:1:10 { Write !,^client(i),!,^client(i,1),!,^client(i,1,1)}
As the FOR loop executes, the variable i is incremented by 1 and used to select the next record to be output. While more generalized than the previous example, this is still very specialized code because it explicitly species both the array name and the number of records to output.
62
Indirection
To transform this code into a more generalized form that would allow a user to list a range of records from any array (global or local) that stores name, street, and city information in three node levels, you could use subscript indirection as shown in the following example:
Start Read !,"Output Name, Street, and City info.",! Read !,"Name of array to access: ",name Read !,"Global or local (G or L): ",gl Read !,"Start with record number: ",start Read !,"End with record number: ",end IF (gl["L")!(gl["l") {Set array = name} ELSEIF (gl["G")!(gl["g") {Set array = "^"_name} Set x = 1,y = 1 FOR i = start:1:end {DO Output} Quit Output Write !,@array@(i) Write !,@array@(i,x) Write !,@array@(i,x,y) Quit
The Write commands in the Output subroutine use subscript indirection to reference the requested array and the requested range of records. In the evaluation of subscript indirection, if the instance of indirection refers to an unsubscripted global or local variable, the value of the indirection is the variable name and all characters to the right of the second Indirection operator, including the parentheses. For a local variable, the maximum number of subscript levels is 255. For a global variable, the maximum number of subscript levels depends on the subscript names, and may be higher than 255, as described in Global Structure in Using Cach Globals. Attempting to use indirection to populate a local variable with more than 255 subscript levels results in a <SYNTAX> error. A class parameter can be used as the base for subscript indirection in the same way that a local or global variable can be used as the base. For example, you can perform subscript indirection using a class parameter with the following syntax:
SET @..#myparam@(x,y) = "stringval"
You can use $TEXT argument indirection to produce the same result in a simpler manner, as follows:
Set LINETEXT = $T(@LINE)
63
6
Regular Expressions
Cach supports regular expressions for use with the following Cach ObjectScript functions $LOCATE and $MATCH and methods of the %Regex.Matcher class. All other Cach substring matching operations use the Cach Pattern Matching operators. This chapter describes the following features of regular expressions: Wildcard and Quantiers. Example: .* matches any number of characters of any type. Literals and Character Ranges. Example: [A-Z] matches a single uppercase character in the range A through Z. Character Type Meta-Characters are sequences that match a group of characters: Single-letter Character Types. Example: \d matches any digit character. Unicode Property Character Types. Example: \p{LL} matches any lowercase letter. POSIX Character Types. Example: [:print:] matches any printable character.
Grouping Construct uses parentheses to repeatedly apply a regular expression. Example: (\p{LL})+ checks each character to determine if it is a lowercase letter. Anchors that limit where a match can occur. Example: \b(day) matches only those occurrences of day that occur at a word boundary. Logical Operators. Example: [[:upper:]&&[:greek:]] matches uppercase Greek letters. Character Representation Meta-Characters are sequences that match a single character. Hexadecimal, Octal, and Unicode Representation. Example: \x5A is the hexadecimal representation for the letter Z. Control Character Representation. Example: \cM is the carriage return control character. Symbol Name Representation. Example: \N{equals sign} is the = character.
Modes. Example: (?i) makes all subsequent matches not case sensitive. Comments. Example: (?# date and 24hour time) inserts this comment into the regular expression string. Error Messages.
Cach implementation of regular expressions is based on the International Components for Unicode (ICU) standard for regular expressions. Users familiar with Perl regular expressions will nd many similarities to the Cach implementation.
65
Regular Expressions
66
Some literal characters are also used as regular expression meta-characters. You must use the escape prex (the backslash character) before a meta-character that is to be treated as a literal character. The following literal characters require an escape prex: dollar sign \$; asterisk \*; plus sign \+; period \.; question mark \?; backslash \\; caret \^; vertical bar \|; open and close parentheses \( \); open and close square brackets \[ \]; open and close curly braces \{ \}. The close square bracket ] does not always require an escape prex; the escape prex should be used for clarity and consistency. The quote character does not take an escape prex; to specify a literal quote character, double it "". The following are ways to specify more than one regular expression match for a literal: [x] A specified character or list of characters. Thus [A] means that only the uppercase letter character A is a match, and [ACE] matches any one of the letters A, C, or E. Characters may be listed in any sequence. Repeated characters are permitted. You can use a caret (^) to specify the inverse; for example, [^A] means that any character except A is a match; [^XYZ] means that any character except X, Y, or Z is a match. By default, these character matches are case sensitive.You can make character matching not case sensitive by preceding it with the (?i) mode modifier. To specify a caret (^) as a literal match character it cannot be the first character in the list. To specify a hyphen ($CHAR(45)) as a literal match character it must be the first or last character in the list. To specify a close bracket (]) as a literal match character it must be the first character in the list. (First character can mean the first character after the ^ inverse operator). Backslash escape prefix literals can also be used; for example [\\AB\[CD] matches backslash (\), open bracket ([), and the letters A, B, C, and D. [x-z] A range of specified characters beginning with x and ending with z (inclusive). Though commonly used for letters or numbers, any ascending ASCII sequence can be used as a range. Thus [A-Z] is the range for all uppercase letters. [A-z] is a range that includes not only all uppercase and lowercase letters, but the six ASCII punctuation characters between the alphabets. Specifying a range that is not in ascending ASCII sequence generates a <REGULAR EXPRESSION> error. You can also specify multiple ranges. Thus [A-Za-z] is the range for all uppercase and lowercase letters.You can use a caret (^) as the first character after the open bracket to specify the inverse; for example, [^A-F] means all character except A through F. The caret specifies the inversion of all of the specified ranges; thus [^A-Za-z] means any character except a letter. Ranges of characters and lists of single characters can be combined in any sequence. Thus [ABCa-fXYZ0-9] matches the characters specified and the characters within the specified ranges. A specified string or a list of strings separated by the OR logical operator (|). Thus (William) matches this exact substring in string, and (William|Willy|Wm\.|Bill) matches any of these substrings. You can use the escape prefix \| to specify a vertical bar as a literal within a string. By default, these substring matches are case sensitive. You can make a substring match not case sensitive by preceding it with the (?i) mode modifier. By default, these substring matches can occur anywhere in string. You can restrict substring matching to occurrences at a word boundary by preceding it with \b.
(str) (str1|str2)
67
Regular Expressions
Single-letter character types. For example: \d Unicode property character types. For example: \p{LL} POSIX character types. For example [:alpha:]
These character type meta-characters can be used in any regular expression in any combination.
\t \w
The \d, \s, and \w meta-characters also match appropriate Unicode characters beyond $CHAR(256). For meta-character sequences for other individual control characters, see Control Character Representation.
For example, \p{LL} matches any lowercase letter. A prop keyword consists of one or two letter characters; prop keywords are not case sensitive. The single-letter prop keywords are the most inclusive; two-letter prop keywords specify a subset. The inverse is \P{prop}. For example, \P{LL} matches any character that is not a lowercase letter. The following table shows the characters that match each prop keyword for the rst 256 characters (an example Unicode character is provided for the prop keywords that do not match any of the 256 characters):
68
C: control and miscellaneous characters 031, 127159, 173 L: letters 65-90, 97122, 170, 181, 186, 192214, 216246, 248255 M: marks (for example, 768)
CO: private use characters (for example, 57344) LT: titlecase letters (for example 453)
LL: lowercase letters 97122, 170, 181, 186, 223246, 248255 MC: modification characters (for example, 2307) ND: decimal numbers 4857
LO: other letters not LL, LU, LT, or LM (for example, 443)
ME: marks that enclose (for example, 1160) NL: letters representing numbers (for example, 5870) PD: dashes 45
MN: accent marks (for example, 768) NO: number subscripts and fractions 178179, 185, 188190 PE: closing punctuation 41, 93, 125 PS: opening punctuation 40, 91, 123 PI: initial punctuation 171 PF: final punctuation 187 PO: other punctuation 3335, 3739, 42, 44, 4647, 5859, 6364, 92, 161, 183, 191
N: numbers 4857, 178179, 185, 188190 P: punctuation 3335, 3742, 4447, 5859, 6364, 9193, 95, 123, 125, 161, 171, 183, 187, 191 S: symbols 36, 43, 6062, 94, 96, 124, 126, 162169, 172, 174177, 180, 182, 184, 215, 247 Z: separators 32, 160
SM: math symbols 43, 6062, 124, 126, 172, 177, 215, 247
You can use the following code to determine which characters match with a prop keyword:
READ prop#2:10 READ rangefrom:10 READ rangeto:10 FOR i=rangefrom:1:rangeto { IF $MATCH($CHAR(i),"\p{"_prop_"}")=1 { WRITE i,"=",$CHAR(i),!} }
69
Regular Expressions
For example, [:lower:] or \p{lower} matches any lowercase letter. You can specify the inverse (match anything except a lowercase letter) as follows: [:^lower:] or \P{lower}. The ptype keywords are not case sensitive. The general ptype keywords are: alnum letters and numbers. alpha letters. blank the tab $CHAR(9) or space $CHAR(32), $CHAR(160). cntrl control characters: $CHAR(0) through $CHAR(31), $CHAR(127) through $CHAR(159). digit the numbers 0 through 9. graph printable characters, excluding the space character: $CHAR(33) thorough $CHAR(126), $CHAR(161) thorough $CHAR(156). lower lowercase letters. math mathematics characters (a subset of symbol). Includes the following characters: +<=>^|~ print printable characters, including the space character: $CHAR(32) thorough $CHAR(126), $CHAR(160) thorough $CHAR(156). punct punctuation characters (excludes symbol characters). Includes the following characters:
!"#%&'()*,-./:;?@[\]_{}
space spacing characters, including the blank space, tab, and line spacing characters, including the following characters: $CHAR(9), $CHAR(10), $CHAR(11), $CHAR(12), $CHAR(13), $CHAR(32), $CHAR(133), and $CHAR(160). symbol symbol characters (excludes punctuation characters). Includes the following characters:
$+<=>^`|~
upper uppercase letters. xdigit hexadecimal digits: the numbers 0 through 9, the uppercase letters A through F, the lowercase letters a through f.
In addition, you can use ptype to specify a Unicode category. For example, [:greek:] matches any character in the Unicode Greek category (this includes the Greek letters which are found in the range $CHAR(900) through $CHAR(974)). A partial list of these POSIX Unicode categories includes: [:arabic:], [:cyrillic:], [:greek:], [:hebrew:], [:hiragana:], [:katakana:], [:latin:], [:thai:]. These Unicode categories can also be represented as [:script=greek:], for example. The following example uses POSIX matching to compare the [:letter:] character set and the [:latin:] character set in the rst 256 characters. They differ by a single character, $CHAR(181):
FOR i=0:1:255 { SET letr="foo" IF 1=$MATCH($CHAR(i),"[:letter:]") { SET letr=$CHAR(i)} IF 1=$MATCH($CHAR(i),"[:latin:]") { SET lat=$CHAR(i)} ELSE {SET lat="foo"} IF letr '= lat {WRITE i," ",$CHAR(i),!} }
70
Grouping Construct
Note:
Because grouping constructs apply a regular expression repeatedly, it is possible to create a matching operation that takes a long time to complete.
The following cautionary example shows how the execution time for a repeatedly applied grouping construct increases rapidly depending on the position of the pattern match error in the string. The more permutations that must be tested before declaring a non-match, the longer the execution time:
SET a=$ZHOROLOG WRITE $MATCH("1111111111,2222222222,3333333333","([0-9]+,?)+") SET b=$ZHOROLOG-a WRITE " duration: ",b,! SET a=$ZHOROLOG WRITE $MATCH("11111x11111,2222222222,3333333333","([0-9]+,?)+") SET b=$ZHOROLOG-a WRITE " duration: ",b,! SET a=$ZHOROLOG WRITE $MATCH("1111111111,22x22222222,3333333333","([0-9]+,?)+") SET b=$ZHOROLOG-a WRITE " duration: ",b,! SET a=$ZHOROLOG WRITE $MATCH("1111111111,2222222x222,3333333333","([0-9]+,?)+") SET b=$ZHOROLOG-a WRITE " duration: ",b,! SET a=$ZHOROLOG WRITE $MATCH("1111111111,22222222x22,3333333333","([0-9]+,?)+") SET b=$ZHOROLOG-a WRITE " duration: ",b
71
Regular Expressions
^ \A $
Beginning of string anchor prefix. Indicates that the regular expression match must occur at the beginning of the string. End of string anchor suffix. Indicates that the regular expression match must occur at the end of the string. End-of-line characters (ASCII 10, 11, 12, or 13) are ignored. Same as \Z. End of string anchor suffix. Indicates that the regular expression match must occur at the end of the string. End-of-line characters (ASCII 10, 11, 12, or 13) are ignored. Same as $. End of string anchor suffix. Indicates that the regular expression match must occur at the end of the string. End-of-line characters (ASCII 10, 11, 12, or 13) are treated as string characters for matching.
\Z
\z
The following example shows how a beginning of string anchor limits a $LOCATE match:
SET str="ABCDEFG" WRITE $LOCATE(str,"A"),! WRITE $LOCATE(str,"D"),! WRITE $LOCATE(str,"^A"),! WRITE $LOCATE(str,"^D"),! // // // // returns returns returns returns 1 4 1 0 (no match)
The following example shows how an end of string anchor limits a $LOCATE match:
SET str="ABCDABCD" WRITE $LOCATE(str,"(ABC)"),! WRITE $LOCATE(str,"D"),! WRITE $LOCATE(str,"(ABC)$"),! WRITE $LOCATE(str,"(ABCD)$"),! WRITE $LOCATE(str,"D$"),! // // // // // returns returns returns returns returns 1 4 0 (no match) 5 8
The following example shows how end-of-string anchors handle a line feed character:
SET str="ABCDEFG"_$CHAR(10) WRITE $LOCATE(str,"G$"),! WRITE $LOCATE(str,"G"_$CHAR(10)_"$"),! WRITE $LOCATE(str,$CHAR(10)_"$"),!! WRITE $LOCATE(str,"G\Z"),! WRITE $LOCATE(str,"G"_$CHAR(10)_"\Z"),! WRITE $LOCATE(str,$CHAR(10)_"\z"),!! WRITE $LOCATE(str,"G\z"),! WRITE $LOCATE(str,"G"_$CHAR(10)_"\z"),! WRITE $LOCATE(str,$CHAR(10)_"\z"),! // returns 7 // returns 7 // returns 8 // returns 7 // returns 7 // returns 8 // returns 0 // returns 7 // returns 8
The following example use \b to match word boundaries that begin with the substring in or un:
72
Logical Operators
SET SET SET SET SET SET SET SET FOR str(1)="unlucky" // match: "un" is at start of string str(2)="highly unlikely" // match: "un" follows a space character str(3)="fall in place" // match: "in" can be followed by a space str(4)="the %integer" // match: % is a non-word character str(5)="down-under" // match: - is a non-word character str(6)="winning" // no match: "in" preceded by word character str(7)="the 4instances" // no match: a number is a word character str(8)="down_under" // no match: an underscore is a word character i=1:1:8 { WRITE $MATCH(str(i),".*\b[iu]n.*")," string",i,! }
The following example uses \B to locate the regular expression when it is not at a word boundary:
SET str(1)="the thirteenth item" WRITE $LOCATE(str(1),"\Bth") // returns 13 ("th" preceded by a word character) SET str(2)="the^thirteenth^item"
The following example show how \b and \B can be used in a regular expression that does not specify a word character:
SET str(1)="this##item" WRITE $LOCATE(str(1),"\b#"),! WRITE $LOCATE(str(1),"\B#") // returns 5 (the first # at a word boundary) // returns 6 (the first # not at a word boundary)
73
Regular Expressions
\unnnn
where X is a letter or symbol that corresponds to an ASCII control character (characters 0 through 31). Letters correspond to $CHAR(1) through $CHAR(26). For example, \cH is $CHAR(8), the backspace character. An X letter is not case sensitive. The non-letter control characters follow the same ASCII character set sequence, as follows: $CHAR(0) = \c@ or \c`, $CHAR(27) = \c{ or \c[, $CHAR(28) = \c| or \c\, $CHAR(29) = \c} or \c], $CHAR(30) = \c^ or \c~, $CHAR(31) = \c_.
For example, \N{comma} matches a comma. Note that the meta-character \N must be an uppercase letter. The supported character names include: acute accent (), ampersand (&), apostrophe ('), asterisk (*), breve (), cedilla (), colon (:), comma (,), dagger (), degree sign (), division sign (), dollar sign ($), double dagger (), em dash (), en dash (), exclamation mark (!), equals sign (=), full stop (.), grave accent (`), innity ( ), left curly bracket ({), left parenthesis ((), left square bracket ([), macron (), multiplication sign (), plus sign (+), pound sign (#), prime ( ), question mark (?), right curly bracket (}), right parenthesis ()), right square bracket (]), semicolon (;), space ( ), square root ( ), tilde (~), vertical line (|). Also supported are subscript zero though subscript nine and superscript zero though superscript nine.
6.8 Modes
A mode changes the interpretation of the character matches that follows it. The mode is specied by a single lowercase letter. There are two ways to use modes:
74
Modes
Mode for a regular expression sequence. For example: (?i) Mode for a specied literal within a regular expression. . For example: (?i:(fred|ginger))
The following mode characters are supported: (?i) (?m) Case mode. When active, letter case is disregarded when matching uppercase and lowercase letters to a regular expression. Multi-line mode. Affects the behavior of ^ (beginning of string) and $ (end of string) anchors, when applied to a multi-line string. By default these anchors apply to the entire string. When multi-line mode is active, these anchors apply to the beginning and end of each line within a multi-line string. A line can be begun by any of the newline characters: 10, 11, 12, 13, 133 (and Unicode 8232 and 8233). Single-line mode. When off, the dot (.) wildcard does not match the newline characters: 10, 11, 12, 13, 133 (and Unicode 8232 and 8233). When on, the dot (.) wildcard matches all characters, including newline characters. Note that the pair of characters carriage return ($CHAR(13)) and line feed (($CHAR(10)), when specified in that order, are counted in a regular expression as a single character. Free-spacing mode. Allows for whitespace and trailing comments in a regular expression.
(?s)
(?x)
Where n is a single lowercase letter that species the mode type. The following example shows case mode (?i):
WRITE $MATCH("A","(?i)[abc]"),! WRITE $MATCH("a","(?i)[abc]")
The following example shows case mode (?i). The rst regular expression is case sensitive. The second regular expression begins with the case mode modier (?i) makes the regular expression not case sensitive:
SET name(1)="Smith,John" SET name(2)="dePaul,Lucius" SET name(3)="smith,john" SET name(4)="John Smith" SET name(5)="Smith,J" SET name(6)="R2D2,CP30" SET n=1 WHILE $DATA(name(n)) { IF $MATCH(name(n),"\p{LU}\p{LL}+,\p{LU}\p{LL}+") { WRITE name(n)," : case match",! } ELSEIF $MATCH(name(n),"(?i)\p{LU}\p{LL}+,\p{LU}\p{LL}+") { WRITE name(n)," : non-case match",! } ELSE { WRITE name(n)," : not a valid name",! } SET n=n+1 }
The following example shows single-line mode (?s), which allows ".*" to match a string containing newline characters:
75
Regular Expressions
SET line(1)="This is a string without line breaks." SET line(2)="This is a string with"_$CHAR(10)_"one line break." SET line(3)="This is a string"_$CHAR(11)_"with"_$CHAR(12)_"two line breaks." SET i=1 WHILE $DATA(line(i)) { IF $MATCH(line(i),".*") {WRITE "line(",i,") is a single line string",! } ELSEIF $MATCH(line(i),"(?s).*") {WRITE "line(",i,") is a multiline string",! } ELSE {WRITE "string error",! } SET i=i+1 }
The following example shows in single-line mode (?s) that the carriage return/line feed pair (in that order) are counted in a regular expression as one character:
SET str(1)="one"_$CHAR(13)_$CHAR(10)_"two" // CR/LF SET str(2)="one"_$CHAR(10)_$CHAR(13)_"two" // LF/CR SET i=1 WHILE $DATA(str(i)) { WRITE $LENGTH(str(i))," is the length of string ",i,! IF $MATCH(str(i),"(?s).{7}") { WRITE "string ",i," matches 7 chars",! } ELSEIF $MATCH(str(i),"(?s).{8}") { WRITE "string ",i," matches 8 chars",! } ELSE { WRITE "string match error",! } SET i=i+1 }
The following example shows multi-line mode (?m). It locates the substring identied by the end anchor ($). In single-line mode, this end substring is always break, the last substring in the string. In multi-line mode the end substring can be any of the substrings that end a line within a multi-line string:
SET line(1)="String without line break" SET line(2)="String with"_$CHAR(10)_" one line break" SET line(3)="String"_$CHAR(11)_" with"_$CHAR(12)_" two line break" SET i=1 WHILE $DATA(line(i)) { WRITE $LOCATE(line(i),"(String|with|break)$")," line(",i,") in single-line mode",! WRITE $LOCATE(line(i),"(?m)(String|with|break)$")," line(",i,") in multi-line mode",!! SET i=i+1 }
This mode modication applies just to the literal(s) within the parentheses. The following case mode (?i) example matches last names (lname) that begin with the de, del, dela, and della, regardless of the capitalization of this prex. The rest of lname must begin with a capital letter, followed by at least one lowercase letter:
SET lname(1)="deTour" SET lname(2)="DeMarco" SET lname(3)="DeLaRenta" SET lname(4)="DelCarmine" SET lname(5)="dellaRobbia" SET i=1 WHILE $DATA(lname(i)) { WRITE $MATCH(lname(i),"(?i:de|del|dela|della)\p{LU}\p{LL}+")," = ",lname(i),! SET i=i+1 }
6.9 Comments
Within a regular expression you can specify two types of comments: Embedded comments Line end comment (in (?x) mode only)
76
Error Messages
The following example show the use of comments within a regular expression to document that this format match is for an American format date (MM/DD/YYYY), not a European format date (DD/MM/YYYY):
WRITE $MATCH("04/28/2012","^[01]\d(?# months)/[0123]\d(?# days)/\d\d\d\d$")
For a list of these errors, refer to General Error Messages 8300 through 8352 in the Cach Error Reference.
77
7
Commands
The command is the basic unit of code in Cach ObjectScript programming. All of the common execution tasks are controlled by commands. Cach ObjectScript commands are similar to English sentences. Just as an English sentence expresses a complete thought, the command expresses a complete action that Cach ObjectScript can perform. Consider the following:
WRITE "Hello"
The word WRITE is a command. It species the action to perform. The WRITE command does exactly what its name implies: it writes to the principal device whatever you specify as its argument. In this case, WRITE writes the string Hello . Note: Cach ObjectScript command names are not case-sensitive. Most command names can be represented by an abbreviated form. Therefore, WRITE , Write , write , W , and w are all valid forms of the WRITE command. For a list of command abbreviations, see Table of Abbreviations in the Cach ObjectScript Reference.
ObjectScript includes commands that perform various kinds of operations. These include: Invoking code Do; Quit; Job; and Xecute Assignment Set; Kill; Merge; and New Flow control If, ElseIf, and Else; For; and While and Do/While Input/Output Write; Read; and general I/O commands
This chapter addresses these commands and a quick overview of other commands, as well as describing the principles of command arguments and postconditionals.
This command uses one argument, x = y * 2 as a whole. (Set requires the equals sign, which you must always specify.) The argument instructs Set to multiply the current value of user-dened variable y by 2 and store the result in user-dened variable x.
79
Commands
If a command takes one or more arguments, you must include exactly one space between the command keyword and the rst argument. For example:
Set x = y * 2
Spaces can appear within the rst argument, so long as the rst character of that argument is separated from the command itself by exactly one space (as appears above). If a command takes a postconditional expression, there must be no spaces between the command keyword and the postconditional, and there must be exactly one space between the postconditional and the beginning of the rst argument. Thus, the following are all valid forms of the Quit command:
Quit x+y Quit x + y Quit:x<0 Quit:x<0 x+y Quit:x<0 x + y
This command uses three arguments to assign values to the three specied variables. In this case, these multiple arguments are repetitive; that is, the command is applied independently to each argument in the order specied. It is equivalent to three separate Set commands. In the command syntax provided in the command reference pages, arguments that can be repeated are followed by a comma and ellipsis: ,.... The comma is a required character for the argument, and the ellipsis indicates that the preceding argument can be repeated multiple times. No spaces are required between arguments, but multiple blank spaces can be used between arguments. These blank spaces have no effect on the execution of the command. Line breaks, tabs, and comments can also be included within or between command arguments with no effect on the execution of the command. Many command arguments also accept parameters (not to be confused with function parameters described in Functions). If a given argument can take parameters, the delimiter for the parameters is the colon : ). The following sample command shows the comma used as the argument delimiter and the colon used as the parameter delimiter. In this example, there are two arguments, with four parameters for each argument.
View X:y:z:a,B:a:y:z
80
In this case, Quit is an argumentless command with a postconditional expression, and a minimum of two spaces is required between it and the next command.
} For{ Write !,"Quit out of 2nd endless loop" Quit } For { Write !,"Quit out of 3rd endless loop" Quit }
An argumentless command that is immediately followed by a closing curly brace does not require trailing spaces, because the closing curly brace acts as a delimiter. For example, the following is a valid use of the argumentless QUIT:
If 1=2 { Write "Math error"} Else { Write "Arthmetic OK" Quit} Write !,"Done"
81
Commands
If both a command keyword and one or more of that commands arguments specify a postconditionals, the keyword postconditional is evaluated rst. Only if this keyword postconditional evaluates to TRUE are the command argument postconditionals evaluated. If a command keyword postconditional evaluates to FALSE, the command is not executed and program execution continues with the next command. If a command argument postconditional evaluates to FALSE, the argument is not executed and execution of the command continues with the next argument in left-to-right sequence.
where Command is the command keyword, the colon is a required literal character, and pc can be any valid expression. A command postconditional must follow these syntax rules: No spaces, tabs, line breaks, or comments are permitted between a command keyword and its postconditional, or between a command argument and its postconditional. No spaces are permitted before or after the colon character. No spaces, tabs, line breaks, or comments are permitted within a postconditional expression, unless either an entire postconditional expression is enclosed in parentheses or the postconditional expression has an argument list enclosed in parentheses. Spaces, tabs, line breaks, and comments are permitted within parentheses. Spacing requirements following a postconditional expression are the same as those following a command keyword: there must be exactly one space between the last character of the keyword postconditional expression and the rst character of the rst argument; for argumentless commands, there must be two or more spaces between the last character of the postconditional expression and the next command on the same line, unless the postconditional is immediately followed by a close curly brace. (If parentheses are used, the closing parenthesis is treated as the last character of the postconditional expression.)
Note that a postconditional expression is not technically a command argument (though in the ObjectScript reference pages the explanation of the postconditional is presented as part of the Arguments section). A postconditional is always optional.
For example, the following Write commands action depends on the value of the variable count:
Set count = 4 Write:count<5 "count is less than 5.",! Set count = 6 Write:count>5 "count is greater than 5.",!
82
Invoking Code
7.3.1 Do
To invoke any routine, function, procedure, or method in ObjectScript, use the Do command. In this sense, Do and Set serve as fundamental commands in Cach, since Do allows you to call other code and Set allows you to specify variable values. The basic syntax of Do is:
Do ^CodeToInvoke
where CodeToInvoke can be a Cach system routine or a user-dened routine. The caret character ^ must appear immediately before the name of the routine. You can run procedures within a routine by referring to the label of the line (also called a tag) where the procedure begins within the routine. The label appears immediately before the caret. For example,
Set %X = 484 Do INT^%SQROOT Write %Y
This code sets the value of the %X system variable to 484; it then uses Do to invoke the INT procedure of the Cach system routine %SQROOT, which calculates the square root of the value in %X and stores it in %Y. The code then displays the value of %Y using the Write command. When invoking methods, Do takes as a single argument the entire expression that species the method. The form of the argument depends on whether the method is an instance or a class method. To invoke a class method, use the following construction:
Do ##class(PackageName.ClassName).ClassMethodName()
where ClassMethodName is the name of the class method that you wish to invoke, ClassName is the name of the class containing the method, and PackageName is the name of the package containing the class. The ##class() construction is a required literal part of the code. To invoke an instance method, you need only have a handle to the locally instantiated object:
Do InstanceName.InstanceMethodName()
where InstanceMethodName is the name of the instance method that you wish to invoke and InstanceName is the name of the instance containing the method.
7.3.2 Quit
The Quit command terminates execution of a code block, including a method. Without an argument, it simply causing the invoking block to exit; with an argument, the invoking block uses the argument of Quit as a return value.
83
Commands
7.3.3 Job
While Do runs code in the foreground, Job runs it in the background. This occurs independently of the current process, usually without user interaction. A jobbed process inherits all system defaults, except those explicitly specied.
7.3.4 Xecute
The Xecute command runs one or more Cach ObjectScript commands; it does this by evaluating the expression that it receives as an argument (and its argument must evaluate to a string containing Cach ObjectScript commands). In effect, each Xecute argument is like a one-line subroutine called by a Do command and terminated when the end of the argument is reached or a Quit command is encountered. After Cach executes the argument, it returns control to the point immediately after the Xecute argument.
7.4.1 Set
The Set command assigns values to variables. It can assign a value to a single variable or to multiple variables at once. To most basic syntax of Set is:
Set variable = expression
This sets the value of a single variable. It also involves several steps: ObjectScript evaluates the expression, determining its value (if possible). This step can generate errors, if the expression contains an undened variable, invalid syntax (such as division by zero), or other errors. If the variable does not already exist, ObjectScript creates it. This is an example Once the variable has been created, or if it already exists, ObjectScript sets its value to that of the expression.
To set the value for each of multiple variables, use the following syntax:
Set variable1 = expression1, variable2 = expression2, variable3 = expression3
To set multiple variables equal to a single expression use the following syntax:
Set (variable1,variable2,variable3)= expression
For example, to set the value of the Gender property of an instance of the Person class use the following code:
Set person.Gender = "Female"
where person is the object reference to the relevant instance of the Person class. You can also set the Gender property of multiple Person objects at the same time:
84
where per1, per2, and per3 are object references to three different instances of the Person class. You can also use Set to invoke a method that returns a value When invoking methods, Set allows you to set a variable, global reference, or property equal to the return value of an expression that species the method. The form of the argument depends on whether the method is an instance or a class method. To invoke a class method, use the following construction:
Set LocalVariable = ##class(PackageName.ClassName).ClassMethodName()
where LocalVariable is that being assigned the return value, ClassMethodName is the name of the class method that you wish to invoke, ClassName is the name of the class containing the method, and PackageName is the name of the package containing the class. The ##class() construction is a required literal part of the code. To invoke an instance method, you need only have a handle to the locally instantiated object:
Set LocalVariable = InstanceName.InstanceMethodName()
where LocalVariable is that being assigned the return value, InstanceMethodName is the name of the instance method that you wish to invoke, and InstanceName is the name of the instance containing the method. If you need to use the value that a method, class or instance, returns, invoke it using Set.
7.4.2 Kill
The Kill command deletes variables from memory and can be used to delete them from disk. Its basic form is:
Kill expression
where expression is one or more variables to delete. The simplest forms of Kill, then, are:
Kill x Kill y,z
A special form of Kill, called an exclusive Kill , deletes all local variables except those specied. To use an exclusive Kill, place its argument in parentheses. For example, if you have variables x, y, and z, you can delete y, z, and any other local variables except x by invoking:
Kill (x)
7.4.3 New
The New command initializes variables. In an application that uses procedures, use New to initialize variables for the entire application or a major subsystem of the application.
85
Commands
ElseIf and Else are both optional, and there can be more than one ElseIf. If there are two conditions, the construct is:
IF if-condition { code } ELSE {code}
7.5.2 For
You use the For construct to repeat sections of code. You can create a For loop based on numeric or string values. Typically, For executes a code block zero or more times based on the value of a numeric control variable that is incremented or decremented at the beginning of each loop through the code. When the control variable reaches its end value, control exits the For loop; if there is no end value, the loop executes until it encounters a Quit command. When control exits the loop, the control variable maintains its value from the last loop executed. The form of a numeric For loop is:
For ControlVariable = StartValue:IncrementAmount:EndValue { // code block content }
86
All values can be positive or negative; spaces are permitted but not required around the equals sign and the colons. The code block following the For will repeat for each value assigned to the variable. For example, the following For loop will execute ve times:
Write "The first five multiples of 3 are:",! For multiple = 3:3:15 { Write multiple,! }
You can also use a variable to determine the end value. In the example below, a variable species how many iterations of the loop occur:
Set howmany = 4 Write "The first ",howmany," multiples of 3 are " For multiple = 1:1:howmany { Write (multiple*3),", " If multiple = (howmany - 1) { Write "and " } If multiple = howmany { Write "and that's it!" } } Quit
Because this example uses multiple, the control variable, to determine the multiples of 3, it displays the expression multiple*3. It also uses the If command to insert and before the last multiple. Note: The If command in this example provides an excellent example of the implications of order of precedence in ObjectScript (order of precedence is always left to right with no hierarchy among operators). If the If expression were simply multiple = howmany - 1 , without any parentheses or parenthesized as a whole, then the rst part of the expression, multiple = howmany , would be evaluated to its value of False (0); the expression as a whole would then be equal to 0 - 1 , which is -1, which means that the expression will evaluate as true (and insert and for every case except the nal iteration through the loop).
The argument of For can also be a variable set to a list of values; in this case, the code block will repeat for each item in the list assigned to the variable.
For b = "John", "Paul", "George", "Ringo" { Write !, "Was ", b, " the leader? " Read choice }
You can specify the numeric form of For without an ending value by placing a Quit within the code block that triggers under particular circumstances and thereby terminates the For. This approach provides a counter of how many iterations have occurred and allows you to control the For using a condition that is not based on the counters value. For example, the following loop uses its counter to inform the user how many guesses were made:
For i = 1:1 { Read !, "Capital of MA? ", a If a = "Boston" { Write "...did it in ", i, " tries" Quit } }
If you have no need for a counter, you can use the argumentless For:
For { Read !, "Know what? ", wh Quit:(wh = "No!") Write " That's what!"
Note:
The section below contains information on the conditions for using For with Quit instead of Do/While or While.
87
Commands
The following example displays values in the Fibonacci sequence up to a user-specied value twice rst using Do/While and then using While:
fibonacci() PUBLIC { // generate Fibonacci sequences Read !, "Generate Fibonacci sequence up to where? ", upto Set t1 = 1, t2 = 1, fib = 1 Write ! Do { Write fib," " set fib = t1 + t2, t1 = t2, t2 = fib } While ( fib '> upto ) Set t1 = 1, t2 = 1, fib = 1 Write ! While ( fib '> upto ) { Write fib," " Set fib = t1 + t2, t1 = t2, t2 = fib } }
The distinction between While, Do/While, and For is that While necessarily tests the control expressions value before executing the loop, Do/While necessarily tests the value after executing the loop, and For can test it anywhere within the loop. This means that if you have two parts to a code block, where execution of the second depends on evaluating the expression, the For construct is best suited; otherwise, the choice depends on whether expression evaluation should precede or follow the code block.
7.6.1 Write
The Write command displays content. It can be used with or without an argument. With an argument that is a valid expression, Write displays the value of that expression; the expression can be a literal, a local variable, a global reference, an object property, or the value returned by method or function. Without an argument the Write command displays the names and values of all local variables, but neither global references, properties, or the results of any code. For example, to write the literal string Hello to the current output device, use the following:
Write "Hello"
88
I/O Commands
Note:
Since Write simply concatenates the elements of its output, you need to add any formatting that you wish to display, as in the example above.
You can use Write to display values of local variables, globals, and properties:
Set x = 2 Write "x = ",x,! Set ^x = 4 Write "^x = ",^x,! Set per = ##class(Sample.Person).%OpenId(5) Write "per.Name = ",per.Name,! Kill x, ^x, per
You can also display the output of methods and functions. For methods, the syntax is:
Write instance.method()
where instance is the object in memory, method is its method, and the displayed value is the return value of the method. For instance, the Sample.Person class (which comes with Cach) has a method called NinetyNine(), which returns 99. Here, the code for instance of Person called MyPerson is:
Set MyPerson = ##class(Sample.Person).%OpenId(3) Write MyPerson.NinetyNine()
To invoke a routine or other ObjectScript code that returns a value, the syntax is:
Write $$label^routine()
where label is the label in the routine, routine is the name of the routine being invoked, and the leading $$ and trailing () are required. For instance, suppose there is a subroutine with the label Fun in the routine house :
Fun() Set place = "Funhouse" Quit place
Here, invoking Fun^house would be in the form have the result of:
USER>Write $$Fun^house() Funhouse
When invoking a subroutine with Write, the subroutine must Quit with a value and the subroutines label must have trailing parentheses; otherwise, errors will result.
7.6.2 Read
The Read command allows you to accept and store input entered by the end user via the current input device. The Read command can have any of the following arguments:
Read format, string, variable
Where format controls where the user input area will appear on the screen, string will appear on the screen before the input prompt, and variable will store the input data. The following format codes are used to control the user input area:
89
Commands
Format Code ! # ?n
Effect Starts a new line. Starts a new page. On a terminal it clears the current screen and starts at the top of a new screen. Positions at the nth column position where n is a positive integer.
90
8
Functions
Functions are pieces of code which perform common tasks. Functions may either return a value or execute silently without returning a value. Cach supplies dozens of functions, which can perform mathematical operations, manipulation of strings and time values, and perform other actions. System-supplied functions (sometimes known as intrinsic functions), which you cannot modify, are identiable as they always begin with a single dollar sign ( $ ); the Cach ObjectScript Language Reference describes each of the systemsupplied functions. In addition to its system-supplied functions, ObjectScript also supports user-dened code (sometimes known as extrinsic code).
where
parameters
Function parameters represent specic values that you supply. All dened parameters are shown in each syntax section. Some of these parameters are required and some are optional. Optional arguments and parameters are indicated as such in the Parameters section of each reference page. Also shown in many syntax sections are required punctuation characters used with some parameters. These include parentheses, commas, curly braces, colons, equal signs, and plus and minus signs.
91
Functions
Function parameters are values that the function uses to produce its result. You place function parameters within parentheses. The opening parenthesis must immediately follow the function keyword with no intervening spaces, as follows:
Write $CHAR(65)
Spaces and comments are permitted within the parentheses, as shown in the following example:
Write $CHAR( 65 /* this parameter is the letter A */)
Some functions take one parameter, some take several. When specifying more than one function parameter, you separate the parameters with commas. Spaces and comments are permitted between parameters, before or after the comma.
Write $FIND(X,Y)
For most functions, you cannot specify multiple instances of the same parameter. The exceptions are $CASE, $CHAR, and $SELECT.
92
9
User-defined Code
Cach comes with many system-supplied functions (sometimes known as intrinsic functions), which are described in the Cach ObjectScript Language Reference. As in other languages, ObjectScript allows you to create named code blocks that you can invoke directly. Such blocks are known as procedures. Strictly speaking, in ObjectScript terminology, a code block that is a procedure has a specic syntax and structure. The syntax of a procedure denition is as follows:
ProcedureName(Parameters) [PublicVariables] { /* code goes here */ QUIT ReturnValue }
The elements of the procedure, here called ProcedureName, are: Parameters (zero or more) These can be of any type and, as is typical of ObjectScript, you do not need to declare their types when you dene the procedure. By default, they are passed by value (not by reference). Unless otherwise specied, their scope is local to the procedure. For more information on parameters generally, see the section Procedure Parameters. References to public variables (zero or more) These, too, can be of any type. The procedure can both reference and set such a variables value. For more information on public variable references, see the section Procedure Variables. Declaration that the procedure is public (optional) By default, procedures are private, which means that you can only call them from elsewhere in the same routine (in ObjectScript terminology, a routine is a le containing one or more procedures or other user-dened code blocks). You can also create procedures that are public, using the PUBLIC keyword after the procedure name. Public procedures can be called from other routines or methods. For more information on public and private procedures, see Public and Private Procedures. Code The code in a procedure has all the features available in Cach ObjectScript. Procedure code can also include Basic and Java. The code is delimited by curly braces and is also known as a procedure block. Return value (optional) This is the value that the procedure returns, and, must be a standard ObjectScript expression. Flow control within a procedure can specify various return values using computed expression values, multiple QUIT statements, or both.
93
User-defined Code
Note:
For those familiar with versions of Cach before version 5 (and code written for those versions), procedures represent an advance from coding that was previously available with subroutines and user-dened functions. Procedure parameters are automatically local in scope within the procedure. They do not require a NEW command to ensure that they do not overwrite other values, since they are private to the procedure and do not interact with the symbol table. Also, the explicit declaration of public variables allows you to refer to global variables within an application, such a bank-wide interest rate; it also allows you to create and set values for variables within the procedure that are available to the rest of an application.
Procedures are a particular kind of ObjectScript routine. Cach also provides a large number of system-supplied functions, all of which are described in the Cach ObjectScript Language Reference; these are sometimes known as intrinsic functions. Calls to system functions are identied by a $ prex.
9.1 Procedures, Routines, Subroutines, Functions, and Methods: What Are They?
This chapter describes how to implement your own code using procedures, which are the recommended form for implementing user-dened functionality. Cach documentation as a whole talks about procedures, routines, subroutines, functions, and methods. Though all these entities share features, each has its own characteristics. Most notably, applications created before the release Cach 5.0 often include subroutines and functions that are not implemented as procedures. For that reason, it is important to provide a brief overview of all of these different structures for implementing your own code. The most exible, most powerful, and recommended form of named, user-dened code block is the procedure. The features of a procedure includes that it: Can be private or public. Can accept zero or more arguments. Automatically maintains any variables created within it as local in scope. Can refer to and alter variables outside it. Can return a value of any type or no return value. By default, methods are procedures. Because of this, all content on procedures in this chapter also describes methods. For more information about methods, see the chapter Methods in the book Using Cach Objects.
Important:
By contrast: A subroutine is always public and cannot return a value. A function is always public, requires explicit declaration of local variables (and, otherwise, overwrites external variables), and must have a return value. By default, a method is a procedure that is specied as part of a class denition and that you can invoke on one or more objects or on a class. If you explicitly declare it a function, it is then a function with all the accompanying characteristics; this is not recommended. A routine is a Cach ObjectScript program. It can include one or more procedures, subroutines, and functions, as well as any combination of the three.
94
Note:
ObjectScript also supports a related form of user-dened code through its macro facility.
9.1.1 Routines
A routine is a callable block of user-written code that is a Cach ObjectScript program. A routine performs commonly needed operations. Its name is determined by the name of the .MAC le that you choose for saving it. Depending on if a routine returns a value, you can invoke a routine with one or both of the following sets of syntax:
DO ^RoutineName SET x = $$^RoutineName
A routine is dened within a namespace. You can use an extended routine reference to execute a user-dened routine dened in a namespace other than the current namespace:
DO ^|"SAMPLES"|RoutineName
Generally, routines serve as containers for subroutines, methods, and procedures. The routine is identied by a label (also referred to as a tag) at the beginning of the block of code. This label is the name of the routine. This label is (usually) followed by parentheses which contain a list of parameters to be passed from the calling program to the routine. When you save a routine to a le, the le name cannot include the underscore ( _ ), hyphen ( - ), or semicolon ( ; ) characters; names that include such characters are not valid.
9.1.2 Subroutines
A subroutine is a named block of code within a routine. Typically, a subroutine begins with label and ends with a QUIT statement It can accept parameters and does not return a value. To invoke a subroutine, use the following syntax:
DO Subroutine^Routine
where Subroutine is a code block within the Routine le (Routine.MAC). The form of a subroutine is:
Label(parameters) // comment // code QUIT // note that QUIT has no arguments
For more details on subroutines, see the section below on subroutines as legacy code. If you enclose the code and QUIT statement within curly braces, the subroutine is a procedure and can be treated as such.
9.1.3 Functions
A function is a named block of code within a routine. Typically, a function begins with label and ends with a QUIT statement. It can accept parameters and can also return a value. To invoke a function, there are two valid forms of the syntax:
SET rval=$$Function() DO Function^Routine /* returning a value */ /* ignoring the return value */
where Function is a code block within the Routine le (Routine.MAC). In both syntactic forms you can use an extended routine reference to execute a function located in a different namespace. The form of a function is:
95
User-defined Code
Label(parameters) // comment // code QUIT ReturnValue
For more details on functions, see the section below on functions as legacy code. If you enclose the code and QUIT statement within curly braces, the function is a procedure and can be treated as such.
denes a public procedure named MyProc which takes two parameters, x and y. It denes two public variables, a and b. All other variables used in the procedure (in this case, x and y) are private variables. By default, procedures are private, which means that you can only call them from elsewhere in the same routine. You can also create procedures that are public, using the Public keyword after the procedure name. Public procedures can be called from other routines. Procedures need not have dened parameters. To create procedures with parameters, place a parenthesized list of variables immediately after the label.
where: name species the name of the function. Depending on where the function is dened, name can be specied as: label is a line label within the current routine. label^routine is a line label within the named routine that resides on disk. ^routine is a routine that resides on disk. The routine must contain only the code for the function to be performed.
param species the values to be passed to the function. The supplied parameters are known as the actual parameter list. They must match the formal parameter list dened for the function. For example, the function code may expect two parameters, with the rst being a numeric value and the second being a string literal. If you specify the string literal
96
Procedures in Detail
for the rst parameter and the numeric value for the second, the function may yield an incorrect value or possibly generate an error. Parameters in the formal parameter list always have NEW invoked by the function. See the NEW command. Parameters can be passed by value or by reference. See Parameter Passing. If you pass fewer parameters to the function than are listed in the functions formal parameter list, parameter defaults are used (if dened); if there are no defaults, these parameters remain undened.
Invoking syntax:
DO label([param[,...]])
or
command $$label([param][,...])
where label param The procedure name. A standard label. It must start in column one. The parameter parentheses following the label are mandatory. A variable for each parameter expected by the procedure. These expected parameters are known as the formal parameter list. The parameters themselves are optional (there may be none, one, or more than one param) but the parentheses are mandatory. Multiple param values are separated by commas. Parameters may be passed to the formal parameter list by value or by reference. Procedures that are routines do not include type information about their arguments; procedures that are methods do include this information. The maximum number of formal parameters is 255.
97
User-defined Code
default
An optional default value for the param preceding it.You can either provide or omit a default value for each parameter. A default value is applied when no actual parameter is provided for that formal parameter, or when an actual parameter is passed by reference and the local variable in question does not have a value. This default value must be a literal: either a number, or a string enclosed in quotation marks. You can specify a null string ( ) as a default value. This differs from specifying no default value, because a null string defines the variable, whereas the variable for a parameter with no specified or default value would remain undefined. If you specify a default value that is not a literal, Cach issues a <PARAMETER> error. Public variables. An optional list of public variables used by the procedure and available to other routines and procedures. This is a list of variables both defined within this procedure and available to other routines and defined within another routine and available to this procedure. If specified, pubvar is enclosed in square brackets. If no pubvar is specified, the square brackets may be omitted. Multiple pubvar values are separated by commas. All variables not declared as public variables are private variables. Private variables are available only to the current invocation of the procedure. They are undefined when the procedure is invoked, and destroyed when the procedure is exited with a QUIT. If the procedure calls any code outside of that procedure, the private variables are preserved, but are unavailable until the call returns to the procedure. All % variables are always public, whether or not they are listed here. The list of public variables can include one or more of the param specified for this routine. An optional keyword that declares whether the procedure is public or private. There are two available values: PUBLIC, which declares that this procedure can be called from any routine. PRIVATE, which declares that this procedure can only be called from the routine in which it is defined. PRIVATE is the default. A block of code, enclosed in curly braces. The opening curly brace ({) must be separated from the characters preceding and following it by at least one space or a line break. The closing curly brace (}) must not be followed by any code on the same line; it can only be followed by blank space or a comment. The closing curly brace can be placed in column one. This block of code is only entered by the label.
pubvar
access
code
You cannot insert a line break between a command and its arguments. Each procedure is implemented as part of a routine; each routine can contain multiple procedures. In addition to standard ObjectScript syntax, there are special rules governing routines. A line in a routine can have a label at the beginning (also called a tag), ObjectScript code, and a comment at the end; but all of these elements are optional. InterSystems recommends that the rst line of a routine have a label matching the name of the routine, followed by a tab or space, followed by a short comment explaining the purpose of the routine. If a line has a label, you must separate it from the rest of the line with a tab or a space. This means that as you add lines to your routine using Cach Studio, you either type a label and a tab/space, followed by ObjectScript code, or you skip the label and type a tab or space, followed by ObjectScript. So in either case, every line must have a tab or space before the rst command. To denote a single-line comment use either a double forward-slash ( // ) or a semicolon ( ; ). If a comment follows code, there must be a space before the slashes or semicolon; if the line contains only a comment, there must be a tab or space before the slashes or semicolon. By denition, there can be no line break within a single-line comment; for a multiline comment, mark the beginning of the comment with /* and the end with */ .
98
Procedures in Detail
99
User-defined Code
the public list. If it is a public variable being introduced by this procedure, then it makes sense to perform a NEW on it. That way it will be automatically destroyed when we QUIT the procedure, and also it protects any previous value that public variable may have had. For example, the code:
MyProc(x,y)[name]{ NEW name SET name="John" DO xyz^abc QUIT }
enables procedure xyz in routine abc to see the value John for name, because it is public. Invoking the NEW command for name protects any public variable named name that may already have existed when the procedure MyProc was called. The NEW command does not affect private variables; it only works on public variables. Within a procedure, it is illegal to specify NEW x or NEW (x) if x is not listed in the public list and x is not a % variable.
and
MyProc(x,y) { }
100
Procedures in Detail
When Cach executes a user-dened function, it maps the parameters in the actual list, by position, to the corresponding parameters in the formal list. For example, the value of the rst parameter in the actual list is placed in the rst variable in the formal list; the second value is placed in the second variable; and so on. The matching of these parameters is done by position, not name. Thus, the variables used for the actual parameters and the formal parameters are not required to have (and usually should not have) the same names. The function accesses the passed values by referencing the appropriate variables in its formal list. The maximum number of actual parameters is 254. If there are more variables in the formal list than there are parameters in the actual list, and a default value is not provided for each, the extra variables are left undened. Your function code should include appropriate If tests to make sure that each function reference provides usable values. When passing parameters to a user-dened function, you can use passing by value or passing by reference. You can mix passing by value and passing by reference within the same function call. Parameter passing can be done by reference or by value. System-supplied functions these can be passed parameters by value only. User-dened functions these can be passed parameters by value or by reference. Subroutines can be passed parameters by value or by reference. Procedures can be passed parameters by value or by reference.
With passing by reference, a specied variable or array name does not have to exist before the function reference. Passing by reference is the only way you can pass an array name to a function.
101
User-defined Code
Actual parameter list: The period preceding the variable or array name in the actual parameter list is required. It species that the variable is being passed by reference, not passed by value. Formal parameter list: No special syntax is required in the formal parameter list to receive a variable passed by reference. The period prex is not permitted in the formal parameter list. However, an ampersand (&) prex is permitted before the name of a variable in the formal parameter list; by convention this & prex is used to indicate that this variable is being passed in by reference. The & prex is optional and performs no operation; it is a useful convention for making your source code easier to read and maintain.
In passing by reference, each variable or array name in the actual list is bound to the corresponding variable name in the functions formal list. Passing by reference provides an effective mechanism for two-way communication between the referencing routine and the function. Any change that the function makes to a variable in its formal list is also made to the corresponding by-reference variable in the actual list. This also applies to the KILL command. If a by-reference variable in the formal list is killed by the function, the corresponding variable in the actual list is also killed. If a variable or array name specied in the actual list does not already exist, the function reference treats it as undened. If the function assigns a value to the corresponding variable in the formal list, the actual variable or array is also dened with this value. The following example uses passing by reference to achieve two-way communication between the referencing routine and the function through the variable result. The period prex species that result is passed by reference. When the function is executed, result in the actual parameter list is created and bound to z in the functions formal parameter list. The calculated value is assigned to z and passed back to the referencing routine in result. The & prex to z in the formal parameter list is optional and non-functional, but helps to clarify the source code. Note that num and powr are passed by value, not reference. This is an example of mixing passing by value and passing by reference:
Start ; Raise an integer to a power. READ !,"Integer= ",num QUIT:num="" READ !,"Power= ",powr QUIT:powr="" SET output=$$Expo(num,powr,.result) WRITE !,"Result= ",output GOTO Start Expo(x,y,&z) SET z=x FOR i=1:1:y {SET z=z*x} QUIT z
The following example uses args... as the only argument. It receives a variable number of values passed by reference:
102
Procedures in Detail
Main SET a=7,b=8,c=9,d=100,e=2000 DO AddNumbers(.a,.b,.c,.d,.e) WRITE "all done" AddNumbers(&args...) { SET sum = 0 FOR i = 1 : 1 : $GET(args, 0) { SET sum = sum + $GET(args(i)) } WRITE "The sum is ",sum,! QUIT sum }
The following example uses args... as the nal argument, following two dened arguments. This procedure must receive at least two argument values, but can receive a variable number of additional arguments:
Main SET a=7,b=8,c=9,d=100,e=2000 DO AddNumbers(a,b,c,d,e) WRITE "all done" AddNumbers(x,y,args...) { SET sum = x+y FOR i = 1 : 1 : $GET(args, 0) { SET sum = sum + $GET(args(i)) } WRITE "The sum is ",sum,! QUIT }
The following example uses args... as the nal argument, following two dened arguments. This procedure receives exactly two argument values; the args... variable number of additional arguments is 0:
Main SET a=7,b=8,c=9,d=100,e=2000 DO AddNumbers(a,b) WRITE "all done" AddNumbers(x,y,args...) { SET sum = x+y FOR i = 1 : 1 : $GET(args, 0) { SET sum = sum + $GET(args(i)) } WRITE "The sum is ",sum,! QUIT }
As specied, AddNumbers(x,y,args...) can receive a minimum of two arguments and a maximum of 255. If you supply defaults for the dened arguments AddNumbers(x=0,y=0,args...) this procedure can receive a minimum of no arguments and a maximum of 255. For specics about methods that can accept a variable number of arguments, see the section Variable Numbers of Arguments in Methods in the Methods chapter of Using Cach Objects.
103
User-defined Code
Rou1 // Rou1 routine Proc1(x,y) { Label1 // Label1 within the proc1 procedure within the Rou1 routine } Proc2(a,b,c) { Label1 // Label1 within the Proc2 procedure (local, as with previous Label1) } Label1 // Label1 that is part of Rou1 and neither procedure
If the procedure contains a DO command or user-dened function without a routine name, it refers to a label within the procedure, if one exists. Otherwise, it refers to a label in the routine but outside of the procedure. If the procedure contains a DO or user-dened function with a routine name, it always identies a line outside of the procedure. This is true even if that name identies the routine that contains the procedure. For example:
ROU1 ; PROC1(x,y) { DO Label1^ROU1 Label1 ; } Label1 ; The DO calls this label
If a procedure contains a GOTO, it must be to a private label within the procedure. You cannot exit a procedure with a GOTO. "label+offset" syntax is not supported within a procedure, with a few exceptions: $TEXT supports label+offset from the procedure label. GOTO label+offset is supported in direct mode lines from the procedure label as a means of returning to the procedure following a Break or error. The ZBREAK command supports a specication of label+offset from the procedure label. The $TEST state in effect when the procedure was called is restored upon the QUIT for the procedure. The } that denotes the end of the procedure can be in any character position on the line, including the rst character position. Code can precede the } on the line, but cannot follow it on the line. An implicit QUIT is present just before the closing brace. Indirection and XECUTE commands behave as if they are outside of a procedure.
Similarly, a reference to a label within indirection or an XECUTE is to a label outside of the procedure. Hence GOTO @A is not supported within a procedure, since a GOTO from within a procedure must be to a label within the procedure. Other parts of the documentation contain more detail on indirection and the XECUTE command. Similarly, when you issue a JOB command within a procedure, it starts a child process that is outside the method. This means that for code such as the following:
104
In order for the child process to be able to see the label, the method or the class cannot be contained in a procedure block.
For more information on error traps, see the chapter of this document on Error Processing.
9.3.1 Subroutines
9.3.1.1 Syntax
Routine syntax:
label [ ( param [ = default /* code */ QUIT ][ , ...] ) ]
Invoking syntax:
DO label [ ( param [ , ...] ) ]
or
GOTO label
label
The name of the subroutine. A standard label. It must start in column one. The parameter parentheses following the label are optional. If specified, the subroutine cannot be invoked using a GOTO call. Parameter parentheses prevent code execution from falling through into a subroutine from the execution of the code that immediately precedes it. When Cach encounters a label with parameter parentheses (even if they are empty) it performs an implicit QUIT, ending execution rather than falling through.
105
User-defined Code
param
The parameter value(s) passed from the calling program to the subroutine. A subroutine invoked using the GOTO command cannot have param values, and must not have parameter parentheses. A subroutine invoked using the DO command may or may not have param values. If there are no param values, empty parameter parentheses may be specified or omitted. Specify a param variable for each parameter expected by the subroutine. The expected parameters are known as the formal parameter list.. There may be none, one, or more than one param. Multiple param values are separated by commas. Cach automatically invokes NEW on the referenced param variables. Parameters may be passed to the formal parameter list by value or by reference. An optional default value for the param preceding it.You can either provide or omit a default value for each parameter. A default value is applied when no actual parameter is provided for that formal parameter, or when an actual parameter is passed by reference and the local variable in question does not have a value. This default value must be a literal: either a number, or a string enclosed in quotation marks. You can specify a null string ( ) as a default value. This differs from specifying no default value, because a null string defines the variable, whereas the variable for a parameter with no specified or default value would remain undefined. If you specify a default value that is not a literal, Cach issues a <PARAMETER> error. A block of code. This block of code is normally accessed by invoking the label. However, it can also be entered (or reentered) by calling another label within the code block or issuing a label + offset GOTO command. A block of code can contain nested calls to other subroutines, functions, or procedures. It is recommended that such nested calls be performed using DO commands or function calls, rather than a linked series of GOTO commands. This block of code is normally exited by an explicit QUIT command; this QUIT command is not always required, but is a recommended coding practice. You can also exit a subroutine by using a GOTO to an external label.
default
code
9.3.1.2 Description
A subroutine is a block of code identied by a label found in the rst column position of the rst line of the subroutine. Execution of a subroutine most commonly completes by encountering an explicit QUIT statement. A subroutine is invoked by either the DO command or the GOTO command. A DO command executes a subroutine and then resumes execution of the calling routine. Thus, when Cach encounters a QUIT command in the subroutine, it returns to the calling routine to execute the next line following the DO command. A GOTO command executes a subroutine but does not return control to the calling program. When Cach encounters a QUIT command in the subroutine, execution ceases.
You can pass parameters to a subroutine invoked by the DO command; you cannot pass parameters to a subroutine invoked by the GOTO command. You can pass parameters by value or by reference. See Parameter Passing. The same variables are available to a subroutine and its calling routine. A subroutine does not return a value.
9.3.2 Functions
As of Cach 5, a function, by default and recommendation, is a procedure. You can, however, continue to dene a function that is not a procedure. This section describes such functions.
106
9.3.2.1 Syntax
Non-procedure function syntax:
label([param[=default]][,...]) code QUIT expression
Invoking syntax:
command $$label([param[ ,...]])
or
DO label([param[ ,...]])
label param
The name of the function. A standard label. It must start in column one. The parameter parentheses following the label are mandatory. A variable for each parameter expected by the function. The expected parameters are known as the formal parameter list . There may be none, one, or more than one param. Multiple param values are separated by commas. Cach automatically invokes NEW for the referenced param variables. Parameters may be passed to the formal parameter list by value or by reference. An optional default value for the param preceding it. You can either provide or omit a default value for each parameter. A default value is applied when no actual parameter is provided for that formal parameter, or when an actual parameter is passed by reference and the local variable in question does not have a value. This default value must be a literal: either a number, or a string enclosed in quotation marks. You can specify a null string ( ) as a default value. This differs from specifying no default value, because a null string defines the variable, whereas the variable for a parameter with no specified or default value would remain undefined. If you specify a default value that is not a literal, Cach issues a <PARAMETER> error. A block of code. This block of code can contain nested calls to other functions, subroutines, or procedures. Such nested calls must be performed using DO commands or function calls. You cannot exit a functions code block by using a GOTO command. This block of code can only be exited by an explicit QUIT command with an expression. The functions return value, specified using any valid Cach ObjectScript expression. The QUIT command with expression is a mandatory part of a user-defined function. The value that results from expression is returned to the point of invocation as the result of the function.
default
code
expression
9.3.2.2 Description
User-dened functions are described in this section. Calls to user-dened functions are identied by a $$ prex. (A user-dened function is also known as an extrinsic function.) User-dened functions allow you to add functions to those supplied by Cach. Typically, you use a function to implement a generalized operation that can be invoked from any number of programs. A function is always called from within a Cach command. It is evaluated as an expression and returns a single value to the invoking command. For example:
SET x=$$myfunc()
107
User-defined Code
When Cach executes a user-dened function, it maps the parameters in the actual list, by position, to the corresponding parameters in the formal list. For example, the value of the rst parameter in the actual list is placed in the rst variable in the formal list; the second value is placed in the second variable; and so on. The matching of these parameters is done by position, not name. Thus, the variables used for the actual parameters and the formal parameters are not required to have (and usually should not have) the same names. The function accesses the passed values by referencing the appropriate variables in its formal list. If there are more variables in the formal list than there are parameters in the actual list, and a default value is not provided for each, the extra variables are left undened. Your function code should include appropriate If tests to make sure that each function reference provides usable values. When passing parameters to a user-dened function, you can use passing by value or passing by reference. You can mix passing by value and passing by reference within the same function call. See Parameter Passing.
The function must contain a QUIT command followed by an expression. Cach terminates the execution of the function when it encounters the QUIT, and returns the single value that results from the associated expression to the invoking program. If you specify a QUIT command without an expression, Cach issues an error.
9.3.2.5 Variables
The invoking program and the called function use the same set of variables, with the following special considerations. Cach executes an implicit NEW command for each parameter in the formal list. This is shown in the following example, where x is reinitialized when myfunc is invoked:
mainprog SET x=7 SET y=$$myfunc(99) myfunc(x) WRITE x QUIT 66
Cach saves the current value of the system variable $TEST when it enters the function and restores it when the function terminates. Any change in the $TEST value during execution of the function will be discarded when the function exits, unless you include code to explicitly save it by some other means.
108
where name species the name of the function. Depending on where the function is dened, name can be specied as: label A line label within the current routine. label^routine A line label within the named routine that resides on disk. ^routine A routine that resides on disk. The routine must contain only the code for the function to be performed.
A routine is dened within a namespace. You can use an extended routine reference to execute a user-dened function that is located in a routine dened in a namespace other than the current namespace:
WRITE $$myfunc^|"SAMPLES"|routine
param species the values to be passed to the function. The supplied parameters are known as the actual parameter list. They must match the formal parameter list dened for the function. For example, the function code may expect two parameters, with the rst being a numeric value and the second being a string literal. If you specify the string literal for the rst parameter and the numeric value for the second, the function may yield an incorrect value or possibly generate an error. Parameters in the formal parameter list always have NEW invoked by the function. See the NEW command. Parameters can be passed by value or by reference. See Parameter Passing. If you pass fewer parameters to the function than are listed in the functions formal parameter list, parameter defaults are used (if dened); if there are no defaults, these parameters remain undened.
The DO command calls the function named label and passes it the parameters (if any) specied by param. Note that the $$ prex is not used, and that the parameter parentheses are mandatory. The same rules apply for specifying the label and param as when invoking a user-dened function using the $$ prex. A function must always return a value. However, when a function is called with DO, this returned value is ignored by the calling program.
109
10
ObjectScript Macros and the Macro Preprocessor
The Cach ObjectScript compiler includes a preprocessor and Cach ObjectScript includes support for preprocessor directives. These directives allow you to create macros for use in applications both in methods and routines. These macros provide the functionality for simple textual substitutions in code. Cach itself also includes various predened macros, which are described in the relevant contexts within the Cach documentation set. This chapter has three parts: Using Macros Describes how to dene and use macros. Preprocessor Directives Reference Provides a list of the preprocessor directives available for use in macro denitions. Using System-supplied Macros Describes using predened macros that are available with Cach and provides a list of them. The preprocessor expands macros before the ObjectScript parser handles any embedded SQL or HTML code. This means that there is no support for macros within embedded HTML. The preprocessor supports embedded SQL in either embedded or deferred compilation mode; the preprocessor does not expand macros within dynamic SQL. The ObjectScript parser removes multiple line comments before parsing preprocessor directives. Therefore, any macro preprocessor directive specied within a /* . . . */ multiple line comment is not executed.
Note:
111
ObjectScript allows you to invoke a macro using the $$$ syntax, such as:
WRITE $$$StringMacro
which, in this case, displays the string Hello, World! Here is the entire sample:
#Define StringMacro "Hello, World!" WRITE $$$StringMacro
As is typical in ObjectScript, the denition of the numeric macro does not require quoting the number, while the string must be quoted in the string macros denition. Variable substitutions:
#Define VariableMacro Variable
Here, the macro name substitutes for the name of a variable that is already dened. If the variable is not dened, there is an <UNDEFINED> error. Command and argument invocations:
#Define CommandArgumentMacro(%Arg) WRITE %Arg,!
Macro argument names must start with the % character, such as the %Arg argument above. Here, the macro invokes the WRITE command, which uses the %Arg argument. Use of functions, expressions, and operators:
#Define FunctionExpressionOperatorMacro ($ZDate(+$Horolog))
Here, the macro as a whole is an expression whose value is the return value of the $ZDate function. $ZDate operates on the expression that results from the operation of the + operator on the system time, which the system variable $Horolog holds. As shown above, it is a good idea to enclose expressions in parentheses so that they minimize their interactions with the statements in which they are used. References to other macros:
#Define ReferenceOtherMacroMacro WRITE $$$ReferencedMacro
Here, the macro uses the expression value of another macro as an argument to the WRITE command. Note: If one macro refers to another, the referenced macro must appear on a line of code that is compiled before the referencing macro.
112
Using Macros
For information on making macros available through include les, see Referring to External Macros (Include Files). For information on Studio Assist, see the Editor Options section of the Setting Studio Options chapter of Using Cach Studio.
113
where MacroIncFile refers to an included le containing macros that is called MacroIncFile.inc. Note that the .inc sufx is not included in the name of the referenced le when it is an argument of #Include. For example, if you have one or more macros in the le MyMacros.inc, you can include them with the following call:
#Include MyMacros
114
#Include #NoShow #Show #SQLCompile Mode #SQLCompile Path #SQLCompile Select #UnDef ##; ##Continue ##Expression ##Function ##SQL ##Unique The macro preprocessor directives are not case-sensitive. This document displays their names in title case for clarity, but this is not required.
Note:
10.2.1 #;
The #; preprocessor directive creates a single line comment that does not appear in .int code. The comment appears only in either .mac code or in an include le. The #; appears at the beginning (column 1) of the line. The comment continues for the remainder of the current line. It has the form:
#; Comment here...
where the comment follows the #; . Compare with the ##; preprocessor directive.
10.2.2 #Def1Arg
The #Def1Arg preprocessor directive denes a macro with only one argument, where that argument can have commas in it. #Def1Arg is a special version of #Dene, since #Dene treats commas within arguments as delimiters between arguments. It has the form:
#Def1Arg Macro(%Arg) Value
where Macro is the name of the macro being dened, which accepts only one argument. A valid macro name is an alphanumeric string. %Arg is the name of the argument for the macro. The name of the variable specifying the macros argument must begin with a percent sign. Value is the macros value, which includes the use of value of %Arg specied at runtime
For more information on dening macros generally, see the entry for #Dene.
115
For example, the following MarxBros macro accepts the comma-separated list of the names of the Marx brothers as its argument:
#Def1Arg MarxBros(%MBNames) Write "%MBNames:",!,"The Marx Brothers!",! // some movies have all four of them $$$MarxBros(Groucho, Chico, Harpo, and Zeppo) Write ! // some movies only have three of them $$$MarxBros(Groucho, Chico, and Harpo)
where the MarxBros macro takes an argument, %MBNames argument, which accepts a comma-delimited list of the names of the Marx brothers.
10.2.3 #Define
The #Dene preprocessor directive denes a macro. It has the form:
#Define Macro[(Args)] [Value]
where Macro is the name of the macro being dened. A valid macro name is an alphanumeric string. Args (optional) are the one or more arguments that it accepts. These are of the form (arg1, arg2, ...). The name of each variable specifying a macro argument must begin with a percent sign. Argument values cannot include commas. Value (optional) is the value being assigned to the macro, where the value can be any valid Cach ObjectScript code. This can be something as simple as a literal or as complex as an expression.
If a macro is dened with a value, then that value replaces the macro in Cach ObjectScript code. If a macro is dened without a value, then code can use other preprocessor directives to test for the existence of the macro and then perform actions accordingly.
Macro arguments cannot include commas. If commas are required, the #Def1Arg directive is available. The following are examples of denitions for macros being used in various ways.
116
Macro1A(%x) 22+%x Macro2A(%x) "Wilma" _ ": %x" Macro3A(%x) (x+y)*%x Macro4A(%x) $Length(x) + $Length(%x) Macro5A(%x) film.Title _ ": " _ film.%x Macro6A(%x) +$h - %x Macro7A(%x) Set x = 4+%x Macro8A(%x) Do ##class(%Library.PopulateUtils).Name(%x) Macro9A(%x) Read !,"Name: ",name Write !,"%x ",name,! Macro9B(%x,%y) Read !,"Name: ",name Write !,"%x %y",name,!
Though this is clearly valid ObjectScript syntax, this use of macros is discouraged.
10.2.4 #Dim
The #Dim preprocessor directive species the intended type of a variable. It has the form:
#Dim #Dim #Dim #Dim VariableName VariableName VariableName VariableName As As As As DataTypeName DataTypeName = InitialValue List Of DataTypeName Array Of DataTypeName
where: VariableName is the variable being dened. DataTypeName is the type of VariableName. InitialValue is a value optionally specied for VariableName. (This syntax is not available for lists or arrays.)
117
10.2.5 #Else
The #Else preprocessor directive species the beginning of the fall-through case in a set of preprocessor conditions. It can follow #IfDef, #If, or #ElseIf. It is followed by #EndIf. It has the form:
#Else // subsequent lines for specified actions #EndIf
For an example of #Else with #If, see that directive; for an example with #EndIf, see that directive. Note: If #Else appears in method code and has an argument other than a literal value of 0 or 1, the compiler generates code in subclasses (rather than invoking the method in the superclass). To avoid generating this code, test conditions for a value of 0 or 1, which results in simpler code and optimizes performance.
10.2.6 #ElseIf
The #ElseIf preprocessor directive species the beginning of a secondary case in a set of preprocessor conditions that begin with #If. Hence, it can follow #If or another #ElseIf. It is followed by another #ElseIf, #Else or #EndIf. (The #ElseIf directive is not for use with #IfDef or #IfNDef.) It has the form:
#ElseIf <expression> // subsequent lines for specified actions // next preprocessor directive
where <expression> is a valid Cach ObjectScript expression. For an example, see #If. Note: #ElseIf has an alternate name of #ElIf. The two names behave identically.
10.2.7 #EndIf
The #EndIf preprocessor directive concludes a set of preprocessor conditions. It can follow #IfDef, #IfUnDef, #If, #ElseIf, and #Else. It has the form:
// #IfDef, #If, or #Else specifying the beginning of a condition // subsequent lines for specified actions #EndIf
10.2.8 #Execute
The #Execute preprocessor directive executes a line of Cach ObjectScript at compile time. It has the form:
#Execute <ObjectScript code>
where the content that follows #Execute is valid Cach ObjectScript code. This code can refer to any variable or property that has a value at compile time; it can also invoke any method or routine that is available at compile time. ObjectScript commands and functions are always available to be invoked. #Execute does not return any value indicating if the code has successfully run or not. Application code is responsible for checking a status code or other information of this kind; this can use additional #Execute directives or other code.
118
Note:
There may be unexpected results if you use #Execute with local variables. Reasons for this include: A variable used at compile time may be out of scope at runtime. With multiple routines or methods, the variable may not be available when referenced. This issue may be exacerbated by the fact that the application programmer does not control compilation order.
For example, you can determine the day of the week at compile time and save it using the following code:
#Execute KILL ^DayOfWeek #Execute SET ^DayOfWeek = $ZDate($H,12) WRITE "Today is ",^DayOfWeek,".",!
10.2.9 #If
The #If preprocessor directive begins a block of conditional text. It takes a Cach ObjectScript expression as an argument, tests the truth value of the argument, and compiles a block of code if the truth value of its argument is true. The block of code concludes with a #Else, #ElseIf, or #EndIf directive.
#If <expression>
where <expression> is a valid Cach ObjectScript expression. If <expression> evaluates to a non-zero value, it is true. For example:
Kill ^MyColor, ^MyNumber #Define ColorDay $ZDate($H,12) #If $$$ColorDay="Monday" Set ^MyColor = "Red" Set ^MyNumber = 1 #ElseIf $$$ColorDay="Tuesday" Set ^MyColor = "Orange" Set ^MyNumber = 2 #ElseIf $$$ColorDay="Wednesday" Set ^MyColor = "Yellow" Set ^MyNumber = 3 #ElseIf $$$ColorDay="Thursday" Set ^MyColor = "Green" Set ^MyNumber = 4 #ElseIf $$$ColorDay="Friday" Set ^MyColor = "Blue" Set ^MyNumber = 5 #Else Set ^MyColor = "Purple" Set ^MyNumber = -1 #EndIf Write ^MyColor, ", ", ^MyNumber
This code sets the value of the ColorDay macro to the name of the day at compile time. The conditional statement that begins with #If then uses the value of ColorDay to determine how to set the value of the ^MyColor variable. This code has multiple conditions that can apply to ColorDay one for each weekday after Monday; the code uses the #ElseIf directive to check these. The fall-through case is the code that follow the #Else directive. The #EndIf closes the conditional. Note: If #If appears in method code and has an argument other than a literal value of 0 or 1, the compiler generates code in subclasses (rather than invoking the method in the superclass). To avoid generating this code, test conditions for a value of 0 or 1, which results in simpler code and optimizes performance.
10.2.10 #IfDef
The #IfDef preprocessor directive marks the beginning of a block of conditional code where execution depends on a macro having been dened. It has the form:
119
where macro-name appears without any leading $$$ characters. Execution of the code is contingent on the macro having been dened. Execution continues until reaching a #Else directive or a closing #EndIf directive. #IfDef checks only if a macro has been dened, not what its value is. Hence, if a macro exists and has a value of 0 (zero), #IfDef still executes the conditional code (since the macro does exist). Also, since #IfDef checks only the existence of a macro, there is only one alternate case (if the macro is not dened), which the #Else directive handles. The #ElseIf directive is not for use with #IfDef. For example, the following provides a simple binary switch based on a macros existence:
#Define Heads #IfDef Heads WRITE "The coin landed heads up.",! #Else WRITE "The coin landed tails up.",! #EndIf
10.2.11 #IfNDef
The #IfNDef preprocessor directive marks the beginning of a block of conditional code where execution depends on a macro having not been dened. It has the form:
#IfNDef macro-name
where macro-name appears without any leading $$$ characters. Execution of the code is contingent on the macro having not been dened. Execution continues until reaching a #Else directive or a closing #EndIf directive. The #ElseIf directive is not for use with #IfNDef. Note: #IfNDef has an alternate name of #IfUnDef. The two names behave identically.
For example, the following provides a simple binary switch based on a macro not having been dened:
#Define Multicolor 256 #IfNDef Multicolor SET NumberOfColors = 2 #Else SET NumberOfColors = $$$Multicolor #EndIf WRITE "There are ",NumberOfColors," colors in use.",!
10.2.12 #Import
The #Import preprocessor directive determines the schema for an unqualied table name or view name in SQL DML statements. For example, if you have:
#Import Dave #Import Bill &sql(SELECT * FROM Patient)
The SQL compiler looks in both package Dave schema and package Bill schema for the Patient table. It must nd exactly one occurrence of Patient in Dave and Bill, or an SQLCODE -43 error occurs. If the Patient table is not found in either Dave or Bill, an SQLCODE -30 error occurs. (In an instance of Cach with installation default settings, running the above sample results in an SQLCODE of 30.)
120
If the table name is already qualied, the #Import commands do not apply. For example:
#Import Dave #Import Bill &sql(SELECT * FROM Medical.Patient)
In this case, Cach searches the Medical schema for the Patient table. It does not search the Dave and Bill schemas. (Again, in an instance of Cach with installation default settings, running the above sample results in an SQLCODE of 30.) #Import has no effect on SQL DDL statements. If you create an unqualied table or view, it will be created in the default SQLUser schema (User package). For example: CREATE TABLE Patient ... creates table SQLUser.Patient. CREATE TABLE Medical.Patient ... creates table Medical.Patient. Compare with the #SQLCompile Path preprocessor directive.
10.2.13 #Include
The #Include preprocessor directive loads a specied le name that contains preprocessor directives. It has the form:
#Include <filename>
where lename is the name of the include le, not including the .inc sufx. Include les are typically located in the same directory as the le calling them. Their names are case sensitive. For example, suppose there is an OS.inc header le that contains macros
#Include OS #IfDef Windows Write "The operating system is not case-sensitive.",! #Else Write "The operating system is case-sensitive.",! #EndIf
Note:
When using #Include in stored procedure code, it must be preceded by a colon character : , such as:
CREATE PROCEDURE SPxx() Language OBJECTSCRIPT { :#Include %occConstant s x=##lit($$$NULLOREF) }
10.2.14 #NoShow
The #NoShow preprocessor directive ends a comment section that is part of an include le. It has the form:
#NoShow
where #NoShow follows a #Show directive. It is strongly recommended that every #Show have a corresponding #NoShow, even when the comment section continues to the end of the le. For an example, see the entry for #Show.
10.2.15 #Show
The #Show preprocessor directive begins a comment section that is part of an include le. By default, comments in an include le do not appear within the calling code. Hence, include le comments outside the #Show#NoShow bracket do not appear in the referencing code.
121
It is strongly recommended that every #Show have a corresponding #NoShow, even when the comment section continues to the end of the le. In the following example, the le OS.inc (from the #Include example) includes the following comments:
#Show // If compilation fails, check the file // OS-errors.log for the statement "No valid OS." #NoShow // Valid values for the operating system are // Windows, UNIX, and OpenVMS (and are case-sensitive).
where the rst two lines of comments (starting with If compilation fails... ) appear in the code that includes the include le and the second two lines of comments (starting with Valid values... ) appear only in the include le itself.
where value is one of the following: Embedded Compiles Cach ObjectScript code and embedded SQL code prior to runtime. This is the default. Deferred Compiles Cach ObjectScript code, but defers compiling embedded SQL code until runtime. This enables you to compile a routine containing SQL that references a table that does not yet exist at compile time.
Deferred mode and Embedded mode statements are otherwise identical. Both Deferred mode statements and Embedded mode statements are static. That is, they cannot be dynamically assembled at runtime and submitted for processing. If dynamic code is required, use Dynamic SQL, as described in Using Cach SQL. Deferred mode can be used for INSERT, UPDATE, and DELETE operations, and SELECT statements that return a single row of data. Deferred SQL cannot be used for multi-row SELECT statements that declare a cursor and fetch rows of data. Like Embedded SQL, Deferred SQL does not check privileges. In Deferred mode, SQL can refer to tables, user-dened functions, and other entities that do not yet exist at compile time. If an embedded SQL statement contains an invalid SQL statement (for example, an SQL syntax error), the Macro Preprocessor generates the code "** SQL Statement Failed to Compile **" and continues to compile Cach ObjectScript code. Thus when compiling a class with a method that contains invalid embedded SQL, the SQL error is reported, but the method is generated. The invalid SQL causes an error when this method is run. Embedded SQL provides optimal SQL performance, and should be used whenever possible. Deferred SQL is generally more efcient than Dynamic SQL. Deferred SQL may be needed when converting Transact-SQL or Informix SPL stored procedures to Cach. The Cach conversion tools for stored procedures support this feature. For further details, refer to the Embedded SQL chapter of Using Cach SQL.
122
where schema is a schema name used to look up an unqualied SQL table name or CALL procedure name in the current namespace. You can specify one schema name or a comma-separated list of schema names. Schemas are searched in the order specied. #SQLCompile Path can be used to resolve unqualied table names for SQL queries, and for INSERT, UPDATE, and DELETE operations. #SQLCompile Path can also be used to resolve unqualied procedure names in SQL CALL statements. It cannot be used for unqualied table names in DDL statements, such as CREATE TABLE and the other CREATE, ALTER, and DROP statements. The following example resolves the unqualied table name Person to the Sample.Person table. It rst searches the Cinema schema (which does not contain a table named Person), then searches the Sample schema:
#SQLCompile Path=Cinema,Sample &sql(SELECT Name,Age INTO :a,:b FROM Person) WRITE "Name is: ",a,! WRITE "Age is: ",b
In addition to specifying schema names as search path items, you can specify the following keywords: CURRENT_PATH: species the current schema search path, as dened in a prior #SQLCompile Path preprocessor directive. This is commonly used to add schemas to the beginning or end of an existing schema search path, as shown in the following example:
#SQLCompile Path=schema_A,schema_B,schema_C #SQLCompile Path=CURRENT_PATH,schema_D
CURRENT_SCHEMA: species the current schema container class name. If #SQLCompile Path is dened in a class method, the CURRENT_SCHEMA is the schema mapped to the current class package. If #SQLCompile Path is dened in a .MAC routine, the CURRENT_SCHEMA is the conguration default schema. For example, if you dene a class method in the class User.MyClass that species #SQLCompile Path=CURRENT_SCHEMA, the CURRENT_SCHEMA will (by default) resolve to SQLUser, since SQLUser is the default schema name for the User package. This is useful when you have a superclass and subclass in different packages, and you dene a method in the superclass that has an SQL query with an unqualied table name. Using CURRENT_SCHEMA, you can have the table name resolve to the superclass schema in the superclass and to the subclass schema in the subclass. Without the CURRENT_SCHEMA search path setting, the table name would resolve to the superclass schema in both classes. If #SQLCompile Path=CURRENT_SCHEMA is used in a trigger, the schema container class name is used. For example, if class pkg1.myclass has a trigger than species #SQLCompile Path=CURRENT_SCHEMA, and class pkg2.myclass extends pkg1.myclass, Cach resolves the non-qualied table names in the SQL statements in the trigger to the schema for package pkg2 when the pkg2.myclass class is compiled.
If you specify a schema search path, the SQL query processor uses the schema search path rst when attempting to resolve an unqualied name. If it does not nd specied table or procedure, it then looks in the default schema(s) that are provided via #Import, or the conguration default schema setting. #SQLCompile Path can be used with #SQLCompile Mode values Embedded or Deferred. For further details, refer to the Embedded SQL chapter of Using Cach SQL. The scope of the schema search path is the routine or method it is dened in. If a schema path is specied in a class method, it only applies to that class method, and not to other methods in the class. If it is specied in a .MAC routine, it applies from that point forward in the routine until another #SQLCompile Path directive is found, or the end of the routine is reached. Schemas are dened for the current namespace.
123
where value is one of the following: Display Formats data for screen and print. Logical Leaves data in its in-memory format. ODBC Formats data for presentation via ODBC or JDBC. Runtime Supports automatic conversion of input data values from a display format (DISPLAY or ODBC) to logical storage format based on the execution-time select mode value. The output values are converted to the current mode. You can get the execution-time select mode value using the GetSelectMode method of the %SYSTEM.SQL class. You can set the execution-time select mode value using the SetSelectMode method of the %SYSTEM.SQL class. Text Alternate name for Display.
The value of this macro determines the output format of Embedded SQL SELECT operations, and whether data conversion is performed during INSERT and UPDATE operations. The following Embedded SQL examples use the different compile modes to return three elds from the Sample.Person table, which are Name (a string eld), DOB (a date eld), and Home (a list eld):
#SQLCOMPILE SELECT=Logical &sql(SELECT Name,DOB,Home INTO :n,:d,:h FROM Sample.Person) WRITE "name is: ",n,! WRITE "birthdate is: ",d,! WRITE "home is: ",h #SQLCOMPILE SELECT=Display &sql(SELECT Name,DOB,Home INTO :n,:d,:h FROM Sample.Person) WRITE "name is: ",n,! WRITE "birthdate is: ",d,! WRITE "home is: ",h #SQLCOMPILE SELECT=ODBC &sql(SELECT Name,DOB,Home INTO :n,:d,:h FROM Sample.Person) WRITE "name is: ",n,! WRITE "birthdate is: ",d,! WRITE "home is: ",h #SQLCOMPILE SELECT=Runtime &sql(SELECT Name,DOB,Home INTO :n,:d,:h FROM Sample.Person) WRITE "name is: ",n,! WRITE "birthdate is: ",d,! WRITE "home is: ",h
10.2.19 #UnDef
The #UnDef preprocessor directive removes the denition for an already-dened macro. It has the form:
#UnDef macro-name
124
where macro-name is a macro that has already been dened. #UnDef follows an invocation of #Dene or #Def1Arg. It works in conjunction with #IfDef and its associated preprocessor directives (#Else, #EndIf, and #IfNDef). The following example demonstrates code that is conditional on a macro being dened and then undened.
#Define TheSpecialPart #IfDef TheSpecialPart Write "We're in the special part of the program.",! #EndIf // // code here... // #UnDef TheSpecialPart #IfDef TheSpecialPart Write "We're in the special part of the program.",! #Else Write "We're no longer in the special part of the program.",! #EndIf #IfNDef TheSpecialPart Write "We're still outside the special part of the program.",! #Else Write "We're back inside the special part of the program.",! #EndIf
10.2.20 ##;
The ##; preprocessor directive creates a single line comment that does not appear in .int code. The comment appears only in either .mac code or in an include le. The ##; may be used anywhere in an ObjectScript code line or an SQL code line. The comment continues for the remainder of the current line. It has the form:
WRITE "Invoking Embedded SQL",! ##; Comment One &sql(SELECT Name INTO :a ##; Comment Two FROM Sample.Person) ##; Comment Three WRITE "The SQL error code is ",SQLCODE,! WRITE "The name is ",a
where the comment follows the ##; . When ##; appears in the rst column of the line, it is functionally identical to the #; preprocessor directive.
10.2.21 ##Continue
The ##Continue preprocessor directive continues a macro denition on the next line, to support multiline macro denitions. It appears at the end of a line of a macro denition to signal the continuation, in the form:
#Define <beginning of macro definition> ##Continue <continuation of macro definition>
125
$$$Multiline(Scarecrow,Tin woodman,Lion) Write "Here is line 1: ",line1,! Write "Here is line 2: ",line2,! Write "Here is line 3: ",line3,!
where the macro being dened accepts three arguments. The code of the macro then sets each of three local variables equal to the values passed in as arguments to the macro. The Write commands display these values.
10.2.22 ##Expression
The ##Expression preprocessor directive evaluates a Cach ObjectScript expression at compile time. It has the form
##Expression(content)
where content is valid Cach ObjectScript code that does not include any quoted strings or any preprocessor directives (with the exception of a nested ##Expression, as described below). The preprocessor evaluates the value of the directives argument at compile time and replaces ##Expression(content) with the evaluation in the ObjectScript .int code. Variables must appear in quotation marks within ##Expression; otherwise, they are evaluated at compile time. For example, the following code generates a Write command that displays the time at which the routine was compiled:
#Define CompTS ##Expression("""Compiled: " _ $ZDateTime($Horolog) _ """,!") Write $$$CompTS
where the argument of ##Expression is parsed in three parts, which are concatenated using the _ operator: The initial string, """Compiled: ". This is delimited by double-quotes. Within that, the pair of double-quotes species a double-quote to appear after evaluation. The value, $ZDateTime($Horolog). The value of the $Horolog special variable at compile-time, as converted and formatted by the $ZDateTime function. The nal string, """,!". This is also delimited by double-quotes. Within that, there are a pair of double-quotes (which results in a single double-quote after evaluation). Since the value being dened is being passed to the Write command, the nal string includes ,!, so that the Write command includes a carriage return.
The routines intermediate (.int) code would then include a line such as:
Write "Compiled: 05/19/2007 07:49:30",!
where the argument to the Write command is determined by the fact that the routine was compiled at 7:49:30 AM on May 19, 2007.
the quoted right parenthesis is treated as if it is a closing parenthesis for specifying the argument.
126
where expression is an ObjectScript expression that determines the value of value and may not contain macros or a ##Expression directive. However, the results of the eXecute value may contain macros, another ##Expression, or both. The ObjectScript preprocessor further expands any of these, as in this example. Suppose the content of routine A.mac includes:
#Define BB ##Expression(10_"_"_$$aa^B()) Set CC = $$$BB Quit
10.2.23 ##Function
The ##Function preprocessor directive evaluates a Cach ObjectScript function at compile time. It has the form
##Function(content)
where content is an ObjectScript function and can be user-dened. ##Function replaces ##Function(content) with the returned value from the function. For example, suppose there is a function in the GetCurrentTime.mac le:
127
It is then possible to invoke this code in a separate routine, called ShowTimeStamps.mac, as follows:
Tag2 #define CompiletimeTimeStamp ##function($$Tag1^GetCurrentTime()) #define RuntimeTimeStamp $$Tag1^GetCurrentTime() Set x=$$$CompiletimeTimeStamp Write x,! Set y=$$$RuntimeTimeStamp Write y,!
where the rst line of output is the value of $Horolog at compile time and the second line is the value of $Horolog at runtime. (The rst line of output is not quoted and the second line is quoted because x substitutes a quoted string for its value, so there are no quotes displayed in the Terminal, while y prints the quoted string directly to the Terminal.) Note: It is the responsibility of the application programmer to make sure that the return value of the ##Function call makes both semantic and syntactic sense, given the context of the call.
10.2.24 ##lit
The ##lit preprocessor directive preserves the content of its argument in literal form:
##lit(content)
where content is a string that is valid Cach ObjectScript expression. The ##lit preprocessor directive ensures that the string it receives is not evaluated, but that it is treated as literal text. For example, the following code:
#Define Macro1 "Row 1 Value" #Define Macro2 "Row 2 Value" ##lit(;;) Column 1 Header ##lit(;) Column 2 Header ##lit(;;) Row 1 Column 1 ##lit(;) $$$Macro1 ##lit(;;) Row 2 Column 1 ##lit(;) $$$Macro2
By using the ##lit directive, macros are evaluated and are delimited by the semicolons in the .int code
10.2.25 ##SQL
The ##SQL preprocessor directive invokes a specied SQL statement at compile time. It has the form:
##SQL(SQL-statement)
where SQL-statement is a valid SQL statement. The ##SQL preprocessor directive is analogous to the &SQL directive ##SQL() invokes the statement at compile time, which &SQL() does so at runtime.
128
If a ##SQL directive contains invalid SQL (such as a syntax error) or refers to a nonexistent table or column, then the macro preprocessor generates a compilation error. For example, the following code runs a query at rst at compile time and then again at runtime:
##sql(SELECT COUNT(*) INTO :count1 FROM Sample.Person) &sql(SELECT COUNT(*) INTO :count2 FROM Sample.Person) Write "Number of instances of Sample.Person at compile time: ",count1,! Write "Number of instances of Sample.Person at runtime: ",count2,!
10.2.26 ##Unique
The ##Unique preprocessor directive creates a new, unique variable within a macro denition for use at compile time or runtime. This directive is available for use only as part of #Dene or #Def1Arg call. It has the form:
##Unique(new) ##Unique(old)
where new species the creation of a new, unique variable and old species a reference to that same variable. When creating the variable with ##Unique(new), its value can be set just as can any other ObjectScript variable. Similarly, code can refer to the ##Unique(old) variable just as it can refer to any other ObjectScript variable. The ##Unique(old) syntax can be used an indenite number of times to refer to the created variable. Subsequent calls to ##Unique(new) create a new variable; after calling ##Unique(new) again, subsequent calls to ##Unique(old) refer to the subsequently created variable. For example, the following code uses ##Unique(new) and ##Unique(old) to swap values between two variables:
#Define Switch(%a,%b) Set ##Unique(new)=%a, %a=%b, %b=##Unique(old) Read "First variable value? ",first,! Read "Second variable value? ",second,! $$$Switch(first,second) Write "The first value is now ",first," and the second is now ",second,!
See each macro below for which include le it requires. The syntax for such statements is:
#Include %occStatus
129
For more details on using externally dened macros, see the section Referring to External Macros (Include Files).
130
ISOK(sc) The ISOK macro returns True if the supplied %Status code (sc) is successful completion. Otherwise, it returns False. This macro requires %occStatus.inc. OK The OK macro creates a %Status code for successful completion. This macro requires %occStatus.inc. Text(text, domain, language) The Text macro is used for localization. It generates a new message at compile time and generates code to retrieve the message at runtime. This macro requires %occMessages.inc. For more information on this macro, see the section $$$Text Macros at Compile Time and Runtime in the chapter Localizing Text in a CSP Application of Using Cach Server Pages (CSP). TextHTML(text, domain, language) The TextHTML macro is used for localization. It performs the same processing as the Text macro; it then additionally applies HTML escaping. It then returns the resulting string. This macro requires %occMessages.inc. For more information on this macro, see the section $$$Text Macros at Compile Time and Runtime in the chapter Localizing Text in a CSP Application of Using Cach Server Pages (CSP). TextJS(text, domain, language) The TextJS macro is used for localization. It performs the same processing as the Text macro; it then additionally applies JavaScript escaping. It then returns the resulting string. This macro requires %occMessages.inc. For more information on this macro, see the section $$$Text Macros at Compile Time and Runtime in the chapter Localizing Text in a CSP Application of Using Cach Server Pages (CSP). THROWONERROR(sc, expr) The THROWONERROR macro evaluates an expression (expr), where the expressions value is assumed to be a %Status code; the macro stores the %Status code in the variable passed as sc. If the %Status code is an error, THROWONERROR performs a THROW operation to throw an exception of type %Exception.StatusException to an exception handler. This macro requires %occStatus.inc. ThrowStatus(sc) The ThrowStatus macro uses the specied %Status code (sc) to perform a THROW operation to throw an exception of type %Exception.StatusException to an exception handler. This macro requires %occStatus.inc.
131
11
Multidimensional Arrays
Cach includes support for multidimensional arrays. A multidimensional array is a persistent variable consisting of one or more elements, each of which has a unique subscript identier and where you can intermix different kinds of subscripts. An example is the following MyVar array: MyVar MyVar(22) MyVar(-3) MyVar(MyString) MyVar(-123409, MyString) MyVar(MyString, 2398) MyVar(1.2, 3, 4, Five, Six, 7)
The subscripts of MyVar are positive and negative real numbers, strings, and combinations of these. Additionally, each array node is a typical ObjectScript variable.
133
Multidimensional Arrays
This set of commands and functions can operate on multidimensional globals and multidimensional local variables. Globals can be easily identied by their leading ^ (caret) character.
134
12
String Operations
ObjectScript provides several groups of operations related to strings, each with its own purpose and features. These are: Basic String Operations and Functions Delimited String Operations List-Structure String Operations
returns 17, the length of a string. For more details, see the $Length reference page in the Cach ObjectScript Reference. $Justify returns a right-justied string, padded on the left with spaces (and can also perform operations on numeric values). For example, the code:
Write "one",!,$Justify("two",8),!,"three"
For more details, see the $Justify reference page in the Cach ObjectScript Reference. $ZConvert converts a string from one form to another. It supports both case translations (to uppercase, to lowercase, or to title case) and encoding translation (between various character encoding styles). For example, the code:
Write $ZConvert("cRAZy cAPs","t")
returns:
CRAZY CAPS
For more details, see the $ZConvert reference page in the Cach ObjectScript Reference.
135
String Operations
The $Find function searches for a substring of a string, and returns the position of the character following the substring. For example, the code:
Write $Find("Once upon a time...", "upon")
returns 10 character position immediately following upon. For more details, see the $Find reference page in the Cach ObjectScript Reference. The $Translate function performs a character-by-character replacement within a string. For example, the code:
Set text = "11/04/2008" Write $Translate(text,"/","-")
replaces the dates slashes with hyphens. For more details, see the $Translate reference page in the Cach ObjectScript Reference. The $Replace function performs string-by-string replacement within a string; the function does not change the value of the string on which it operates. For example, the code:
Set text = "green leaves, brown leaves" Write text,! Write $Replace(text,"leaves","eyes"),! Write $Replace(text,"leaves","hair",15),! Write text,!
performs two distinct operations. In the rst call, $Replace replaces the string leaves with the string eyes. In the second call, $Replace discards all the characters prior to the fteenth character (specied by the fourth argument) and replaces the string leaves with the string hair. The value of the text string is not changed by either $Replace call. For more details, see the $Replace reference page in the Cach ObjectScript Reference. The $Extract function, which returns a substring from a specied position in a string. For example, the code:
Write $Extract("Nevermore"),$Extract("prediction",5),$Extract("xon/xoff",1,3)
returns three strings. The one-argument form returns the rst character of the string; the two-argument form returns the specied character from the string; and the three-argument form returns the substring beginning and ending with specied characters, inclusive. In the example above, there are no line breaks, so the return value is:
Nixon
For more details, see the next section or the $Extract reference page in the Cach ObjectScript Reference.
This code takes the string abc and places at the third character of string y. Because y has no specied value, $Extract assumes that its characters are blank, which acts to pad the string. You can also use $Extract to insert a new string at a particular point in variable. It extracts the characters specied and replaces them with the supplied substring, whether or not the lengths of the old and new strings match. For example:
Set x = "1234" Write x,! Set $Extract(x, 3) = "abc" Write x,! Set $Extract(y, 3) = "abc" Write y
136
Delimited Strings
This code sets x to 1234 ; it then extracts the third character of x using $Extract and inserts abc in its place, making the string 12abc4 .
The $Piece function provides uniquely important functionality because it allows you to use a single string that contains multiple substrings, with a special delimiter character (such as ^ ) to separate them. The large string acts as a record, and the substrings are its elds. The syntax for $Piece is:
Write $Piece("ListString","QuotedDelimiter",ItemNumber)
where ListString is a quoted string that contains the full record being used; QuotedDelimiter is the specied delimited, which must appear in quotes; and ItemNumber is the specied substring to be returned. For example, to display the second item in the following space-delimited list, the syntax is:
Write $Piece("Kennedy Johnson Nixon"," ",2)
which returns Johnson . You can also return multiple members of the list, so that the following:
Write $Piece("Nixon***Ford***Carter***Reagan","***",1,3)
returns Nixon***Ford***Carter . Note that both values must refer to actual substrings and the third argument (here 1) must be a smaller value than that of the fourth argument (here 3). The delimiter can be anything you choose, such as with the following list:
Set x = $Piece("Reagan,Bush,Clinton,Bush,Obama",",",3) Set y = $Piece("Reagan,Bush,Clinton,Bush,Obama","Bush",2) Write x,!,y
which returns
Clinton ,Clinton,
In the rst case, the delimiter is the comma; in the second, it is the string Bush , which is why the returned string includes the commas. To avoid any possible ambiguities related to delimiters, use the list-related functions, described in the next section.
137
String Operations
Set $Piece(Alphalist, "^", 1) = "a" Write "First, the length of the list is ",$Length(Alphalist,"^"),".",! Set $Piece(Alphalist, "^", 4) = "d" Write "Then, the length of the list is ",$Length(Alphalist,"^"),".",! Set $Piece(Alphalist, "^", 20) = "t" Write "Finally, the length of the list is ",$Length(Alphalist,"^"),".",!
The $Length function returns a value of 1, then 4, then 20, since it creates the necessary number of delimited items. However, items 2, 3, and 5 through 19 do not have values set. Hence, if you attempt to display any of their values, nothing appears. A delimited string item can also contain a delimited string. To retrieve a value from a sublist such as this, nest $Piece function calls, as in the following code:
Set $Piece(Powers, "^", 1) = Set $Piece(Powers, "^", 2) = Set $Piece(Powers, "^", 3) = Write Powers,! Write $Piece( $Piece(Powers, "1::1::1::1::1" "2::4::8::16::32" "3::9::27::81::243" "^", 2), "::", 3)
This code returns two lines of output: the rst is the string Powers, including all its delimiters; the second is 8, which is the value of the third element in the sublist contained by the second element in Powers. (In the Powers list, the nth item is a sublist of two raised to the rst through fth powers, so that the rst item in the sublist is n to the rst power, and so on.) For more details, see the $Piece reference page in the Cach ObjectScript Reference.
List data retrieval: $LIST returns a list element value by position. It can count positions from the beginning or the end of the list. $LISTNEXT returns list element values sequentially from the beginning of the list. While both $LIST and $LISTNEXT can be used to sequentially return elements from a list, $LISTNEXT is signicantly faster when returning a large number of list elements. $LISTGET returns a list element value by position, or returns a default value. $LISTTOSTRING returns all of the element values in a list as a delimited string.
List manipulation: SET $LIST inserts, updates, or deletes elements in a list. SET $LIST replaces a list element or a range of list elements with one or more values. Because SET $LIST can replace a list element with more than one element, you can use it to insert elements into a list. Because SET $LIST can replace a list element with a null string, you can use it to delete a list element or a range of list elements.
List evaluation:
138
$LISTVALID determines if a string is a valid list. $LISTLENGTH determines the number of elements in a list. $LISTDATA determines if a specied list element contains data. $LISTFIND determines if a specied value is found in a list, returning the list position. $LISTSAME determines if two lists are identical.
Because a list is an encoded string, Cach treats lists slightly differently than standard strings. Therefore, you should not use standard string functions on lists. Further, using most list functions on a standard string generates a <LIST> error. The following procedure demonstrates the use of the various list functions:
ListTest() PUBLIC { // set values for list elements SET Addr="One Memorial Drive" SET City="Cambridge" SET State="MA" SET Zip="02142" // create list SET Mail = $LISTBUILD(Addr,City,State,Zip) // get user input READ "Enter a string: ",input,!,! // if user input is part of the list, print the list's content IF $LISTFIND(Mail,input) { FOR i=1:1:$LISTLENGTH(Mail) { WRITE $LIST(Mail,i),! } } }
This procedure demonstrates several notable aspects of lists: $LISTFIND only returns 1 (True) if the value being tested matches the list item exactly. $LISTFIND and $LISTLENGTH are used in expressions.
For more detailed information on list functions see the corresponding reference pages in the Cach ObjectScript Reference.
Because the second $LIST in this example creates list element 20, $LISTLENGTH returns a value of 20. However, elements 2 through 19 do not have values set. Hence, if you attempt to display any of their values, you will receive a <NULL VALUE> error. You can use $LISTGET to avoid this error. An element in a list can itself be a list. To retrieve a value from a sublist such as this, nest $LIST function calls, as in the following code:
SET $LIST(Powers,2)=$LISTBUILD(2,4,8,16,32) WRITE $LIST($LIST(Powers,2),5)
This code returns 32, which is the value of the fth element in the sublist contained by the second element in the Powers list. (In the Powers list, the second item is a sublist of two raised to the rst through fth powers, so that the rst item in the sublist is two to the rst power, and so on.)
139
String Operations
140
13
Transaction Processing
This chapter covers the following topics: Managing Transactions Within Applications Automatic Transaction Rollback System-Wide Issues with Transaction Processing A transaction is a logical unit of work. Transaction processing helps maintain the logical integrity of your database. For example, when transferring money from one account to another, a bank may need to subtract an amount from a eld in one table and add the same amount to a eld in another table. By specifying that both updates form a single transaction, you ensure that either both operations are performed or neither is performed, which means that one cannot be executed without the other. Within your application, a single SQL INSERT, UPDATE, or DELETE statement, or a single global Set or Kill, may not in itself constitute a complete transaction. In such cases, you use transaction processing commands to dene the sequence of operations that forms a complete transaction. One command marks the beginning of the transaction; after a sequence of possibly many commands, another command marks the end of the transaction. Under normal circumstances, the transaction executes in its entirety. If a program error or system malfunction leads to an incomplete transaction, then the part of the transaction that was completed is rolled back. Application developers should handle transaction rollback within their applications. Cach also handles transaction rollback automatically in the event of a system failure and at various junctures, such as recovery and during HALT or ResJob. In Cach, the error trap STU always rolls back a transaction. Cach records rollbacks in the cconsole.log le if there is a ^%LOGROLLBACK global.
Both techniques work, regardless of whether the database modications that constitute the transactions are performed with SQL INSERT, UPDATE, and DELETE statements or Cach ObjectScript SET and KILL commands.
141
Transaction Processing
Mark a point within a transaction. Can be used for partial rollback to a savepoint. Signals a successful end of transaction. Signals an unsuccessful end of transaction; all the database updates performed since the beginning of transaction should be rolled back or undone.
Note:
Cach treats a Set or Kill of a global variable as a journaled transaction event; rolling back the transaction reverses these operations. Cach does not treat a Set or Kill of a local variable or a process-private global variable as a journaled transaction event; rolling back the transaction has no effect on these operations. To prevent the Set or Kill of a global variable invoked within a transaction from being seen by other users before the transaction has been committed, you must coordinate access to the global variable via the Lock command.
142
unlocks ^A (if you had it locked) without affecting other lock items. The system manager can unlock any item with the LOCKTAB program. If you unlock a global within a transaction before the transaction is complete, Cach defers the unlock until the transaction is committed or rolled back. Within the transaction, the data appears to be unlocked, permitting a subsequent lock of the same value within the same transaction to work correctly. Outside of the transaction, however, the data remains locked. Consider the following common case, which adds a name and related information to the end of a list. ^A(0) contains the last-used number, for instance 4, as you enter this code:
&sql(START TRANSACTION) Lock ^A(0) set id=^A(0)+1,^A(0)=id Lock ^A(id) set ^A(id)=name // processing continues ... Lock &sql(COMMIT WORK)
You are sure to get an id equal to 5. The second Lock allows another caller of this code to get an id equal to 6 without interference, while we complete the transaction on id equal to 5. So far, this logic appears to work correctly. If an error occurs, however, and the transaction is rolled back, which resets ^A(0) to 4, a third caller gets an id equal to 5, and a fourth caller gets an id equal to 6. To prevent this from happening, Cach defers the effect of all unlocks until the transaction is committed or rolled back. After your second Lock in the example, a display of the lock table by LOCKTAB shows your lock on ^A(id) but not on ^A(0). Nevertheless, another process cannot lock ^A(0) until you complete your transaction. If you do not wish to hold the lock throughout a possibly lengthy transaction, split it into two transactions, as in this example:
##sql(START TRANSACTION) Lock ^A(0) set id=^A(0)+1,^(0)=id ##sql(COMMIT WORK) ##sql(START TRANSACTION) Lock ^A(id) set ^A(id)=name // processing continues ... ##sql(COMMIT WORK) Lock
If the lock table lls up, Cach sends the following message to the cconsole.log le:
LOCK TABLE FULL
Filling the lock table is not an error condition as far as an application is concerned, unless a deadlock occurs; jobs will just wait until there is space to add their locks to the lock table. However, if all the jobs that have been granted locks at a particular time want to add more locks and no one is willing to release any locks, the application will get a deadlock. This is considered an application programming error.
143
Transaction Processing
Issue the Cach ObjectScript rollback command, TRollBack Make a call to %ETN When you roll back a transaction, the IDKey for any default class is not decremented. Rather, the value of the IDKey is automatically modied by the $Increment function.
Note:
The rollback command must cooperate with an error trap, as in the following example:
ROU ##sql(START TRANSACTION) set $ZT="ERROR" Set ^ZGLO(1)=100 Set ^ZGLO=error Set ^ZGLO(1,1)=200 ##sql(COMMIT WORK) Write !,"Transaction Committed" Quit ##sql(ROLLBACK WORK) Write !,"Transaction failed." Quit
ERROR
In the example code, $ZT is set to run the subroutine ERROR if a program error occurs before the transaction is committed. Line ROU begins the transaction and sets the error trap. Lines ROU+1 and ROU+3 set the nodes of the global ^ZGLO. However, if the variable error is undened, ROU+2 causes a program error and line ROU+3 does not execute. Program execution goes to the subroutine ERROR and the set of ^ZGLO(1) is undone. If line ROU+2 were deleted, ^ZGLO would have its value set both times, the transaction would be committed, and the message Transaction committed would be written.
If there is no response within a 10-second timeout period, the system defaults to rollback. In a jobbed job or an application mode job, the transaction is rolled back with no message. %ETN itself does not do anything to trigger transaction rollback, but it typically ends by halting out of Cach. Transaction rollback occurs when you halt out of Cach ObjectScript and the system runs %HALT to perform Cach process cleanup. There is an entry point into %ETN, called BACK^%ETN, which ends with a quit, rather than a halt. If a routine calls BACK^%ETN, rather than ^%ETN or FORE^%ETN, it will not perform transaction rollback as part of the error handling process.
144
In addition, system managers can roll back incomplete transactions in cluster-specic databases by running the Restore Journal option of the JOURNAL utility.
145
Transaction Processing
The AsynchError property of the Config.Miscellaneous class sets a system-wide default for new processes for whether processes are willing to be interrupted by asynchronous errors. It defaults to 1, meaning YES. If multiple asynchronous errors are detected for a particular job, the system triggers at least one such error. However, there is no guarantee which error will be triggered. The asynchronous errors currently implemented include: <LOCKLOST> Some locks once owned by this job have been reset. <DATALOST> Some data modications performed by this job have received an error from the server. <TRANLOST> A distributed transaction initiated by this job has been asynchronously rolled back by the server.
Even if you disable a job receiving asynchronous errors, the next time the job performs a ZSync command, the asynchronous error is triggered.
146
At each TStart, TCommit, or Lock operation, and at each network global reference, Cach checks for pending asynchronous errors. Since Set and Kill operations across the network are asynchronous, an arbitrary number of other instructions may interpose between when the Set is generated and when the asynchronous error is reported.
147
14
Error Processing
Managing the behavior of Cach when an error occurs is called error processing or error handling. Error processing performs one or more of the following functions: Correcting the condition that caused the error Performing some action that allows execution to resume despite the error Diverting the ow of execution Logging information about the error
Cach supports two types of error processing, which can be used simultaneously. These are: The TRY-CATCH mechanism Traditional error processing The preferred mechanism for Cach ObjectScript error handling is the TRY-CATCH mechanism. If traditional error processing is to be used, the $ZTRAP mechanism is preferred. Use of $ETRAP is discouraged.
Important:
where: The TRY command identies a block of Cach ObjectScript code statements enclosed in curly braces. TRY takes no arguments. This block of code is protected code for structured exception handling. If an exception occurs within the
149
Error Processing
block, Cach sets $ZERROR and $ECODE, then transfers execution to an exception handler, identied by the CATCH command. This is known as throwing an exception. The protected statements are ObjectScript statements that are part of normal execution. (These can include calls to the THROW command. This scenario is described in the following section.) The CATCH command denes an exception handler, which is a block of code to execute when an exception occurs in a TRY block. The ErrorHandle variable is a handle to an exception object. This can be either an exception object that Cach has generated in response to a runtime error or an exception object explicitly issued by invoking the THROW command (described in the next section). The error statements are ObjectScript statements that are invoked if there is an exception. The further statements are ObjectScript statements that either follow execution of the protected statements if there is no exception or follow execution of the error statements if there is an exception and control passes out of the CATCH block.
Depending on events during execution of the protected statements, one of the following events occurs: If an error does not occur, execution continues with the further statements that appear outside the CATCH block. If an error does occur, control passes into the CATCH block and error statements are executed. Execution then depends on contents of the CATCH block: If the CATCH block contains a THROW or GOTO command, control goes directly to the specied location. If the CATCH block does not contain a THROW or GOTO command, control passes out of the CATCH block and execution continues with the further statements.
where expression is an instance of a class that inherits from the %Exception.AbstractException class, which Cach provides for exception handling. For more information on %Exception.AbstractException, see the following section. The form of the TRY-CATCH block with a THROW is:
TRY { protected statements THROW expression protected statements } CATCH ErrorHandle { error statements } further statements
where the THROW command explicitly issues an exception. The other elements of the TRY-CATCH block are as described in the previous section. The effects of THROW depends on where the throw occurs and the argument of THROW: A THROW within a TRY block passes control to the CATCH block.
150
A THROW within a CATCH block passes control up the execution stack to the next error handler. If the exception is a %Exception.SystemException object, the next error handler can be any type (CATCH or traditional); otherwise there must be a CATCH to handle the exception or a <NOCATCH> error will be thrown.
If control passes into a CATCH block because of a THROW with an argument, the ErrorHandle contains the value from the argument. If control passes into a CATCH block because of a system error, the ErrorHandle is a %Exception.SystemException object. If no ErrorHandle is specied, there is no indication of why control has passed into the CATCH block. For example, suppose there is code to divide two numbers:
div(num,div) public { TRY { SET ans=num/div } CATCH errobj { IF errobj.Name="<DIVIDE>" { SET ans=0 } ELSE { THROW errobj } } QUIT ans }
If a divide-by-zero error happens, the code is specically designed to return zero as the result. For any other error, the THROW sends the error on up the stack to the next error handler.
151
Error Processing
2.
If an error occurs and no error handler has been established, the behavior depends on how the Cach session was started: 1. If you signed onto Cach in Programmer Mode and have not set an error trap, Cach displays an error message on the principal device and enters Programmer Mode with the program stack intact. The programmer can later resume execution of the program. If you invoked Cach in Application Mode and have not set an error trap, Cach displays an error message on the principal device and executes a HALT command.
2.
152
An XECUTE command argument causes Cach ObjectScript code to execute. (This kind of frame is also known as a XECUTE frame. ) A user-dened function is executed.
The frame is built on the call stack, one of the private data structures in the address space of your process. Cach stores the following elements in the frame for a routine: The value of the $ZTRAP special variable (if any) The value of the $ETRAP special variable (if any) The position to return from the subroutine
When routine A calls routine B with DO ^B, Cach builds a DO frame on the call stack to preserve the context of A. When routine B calls routine C, Cach adds a DO frame to the call stack to preserve the context of B, and so forth.
If routine A in the gure above is invoked at the Programmer Mode prompt using the DO command, then an extra DO frame, not described in the gure, exists at the base of the call stack.
153
Error Processing
When an error occurs, all context information is immediately saved on your process error stack. The context information is then accessible by the $STACK function until the value of $ECODE is cleared by an error handler. In other words, while the value of $ECODE is non-null, the $STACK function returns information about a context saved on the error stack rather than an active context at the same specied context level. See the $STACK function in the Cach ObjectScript Reference for details. When an error occurs and an error stack already exists, Cach records information about the new error at the context level where the error occurred, unless information about another error already exists at that context level on the error stack. In this case, the information is placed at the next level on the error stack (regardless of the information that may already be recorded there). Therefore, depending on the context level of the new error, the error stack may extend (one or more context levels added) or information at an existing error stack context level may be overwritten to accommodate information about the new error. Keep in mind that you clear your process error stack by clearing the $ECODE special variable.
$ZERROR Value
Cach sets $ZERROR to a string containing: The Cach error code, enclosed in angle brackets. The label, offset, and routine name where the error occurred. (For some errors): Additional information, such as the name of the item that caused the error.
154
The following examples show the type of messages to which $ZERROR is set when Cach encounters an error. In the following example, the undened local variable abc is invoked at line offset 2 from label PrintResult of routine MyTest. $ZERROR contains:
<UNDEFINED>PrintResult+2^MyTest *abc
The following error occurred when a non-existent class is invoked at line offset 3:
<CLASS DOES NOT EXIST>PrintResult+3^MyTest *%SYSTEM.XXQL
The following error occurred when a non-existent method of an existing class is invoked at line offset 4:
<METHOD DOES NOT EXIST>PrintResult+4^MyTest *BadMethod,%SYSTEM.SQL
You can also explicitly set the special variable $ZERROR as any string up to 128 characters; for example:
SET $ZERROR="Any String"
The $ZERROR special variable retains its value until an error occurs or until you set it to a new value. See the $ZERROR special variable in the Cach ObjectScript Reference for details.
$ECODE Value
When an error occurs, Cach sets $ECODE to the value of a comma-surrounded string containing the ANSI Standard error code that corresponds to the error. For example, when you make a reference to an undened global variable, Cach sets $ECODE set to the following string:
,M7,
If the error has no corresponding ANSI Standard error code, Cach sets $ECODE to the value of a comma-surrounded string containing the Cach error code preceded by the letter Z. For example, if a process has exhausted its symbol table space, Cach places the error code <STORE> in the $ZERROR special variable and sets $ECODE to this string:
,ZSTORE,
After an error occurs, your error handlers can test for specic error codes by examining the value of the $ZERROR special variable or the $ECODE special variable. Note: Error handlers should examine $ZERROR rather than $ECODE special variable for specic errors.
See the $ECODE special variable in the Cach ObjectScript Reference for details.
$ZTRAP has two basic forms: SET $ZTRAP=location which executes in the context in which $ZTRAP was dened. It has a scope that is local to the routine, user-dened function, or XECUTE context in which it was dened. SET $ZTRAP=*location which executes in the context in which the error occurred that invoked it. This form is not valid within a procedure. To specify code that runs in the same context as the error, use $ETRAP instead of $ZTRAP.
155
Error Processing
Notes
Do not set $ZTRAP to a value that is longer than 31 characters. When $ZTRAP is set to a non-empty value, it takes precedence over any existing $ETRAP error handler. Cach implicitly performs a NEW $ETRAP command and sets $ETRAP equal to "". With $ZTRAP, private labels are not supported.
For more information on %ETN, see the Error Trap Utilities section of the Command-line Routine Debugging chapter. Note: %ET is a legacy name for %ETN. Their functionality is identical, though %ETN is slightly more efcient.
3.
See the $ZTRAP special variable in the Cach ObjectScript Reference for details.
156
When the error in B activates the error trap, the former values of E and F, stacked in line B, are removed, but A, B, C, and D remain stacked.
157
Error Processing
By default, each DO, XECUTE, or user-dened function context inherits the $ETRAP error handler of the frame that invoked it. This means that the designated $ETRAP error handler at any context level is the last dened $ETRAP, even if that denition was made several stack levels down from the current level.
158
to an error-handling routine. This example transfers control to the LogError procedure (which is part of the routine ErrRoutine):
SET $ETRAP="GOTO LogError^ErrRoutine"
The commands in the $ETRAP special variable are always followed by an implicit QUIT command. The implicit QUIT command quits with a null string argument when the $ETRAP error handler is invoked in a user-dened function context where a QUIT with arguments is required. $ETRAP has a global scope. This means that setting $ETRAP should usually be preceded by NEW $ETRAP. Otherwise, if the value of $ETRAP is set in the current context, then, after passing beyond the scope of that context, the value stored in $ETRAP is still present while control is in a higher-level context. Thus, if you do not specify the NEW $ETRAP, then $ETRAP could be executed at an unexpected time when the context that set that it no longer exists. See the $ETRAP special variable in the Cach ObjectScript Reference for details.
If a routine sets $ETRAP without rst creating a new copy of $ETRAP, a new $ETRAP error handler is established for the current context, the context that invoked it, and possibly other contexts that have been saved on the call stack. Therefore InterSystems recommends that you create a new copy of $ETRAP before you set it. Keep in mind that creating a new copy of $ETRAP does not clear $ETRAP. The value of $ETRAP remains unchanged by the NEW command. The gure below shows the sequence of $ETRAP assignments that create the stack of $ETRAP error handlers. As the gure shows: Routine A creates a new copy of $ETRAP, sets it to GOTO ^ERR , and contains the DO command to call routine B. Routine B does nothing with $ETRAP (thereby inheriting the $ETRAP error handler of Routine A) and contains the DO command to call routine C. Routine C creates a new copy of $ETRAP, sets it to GOTO ^CERR , and contains the DO command to call routine D. Routine D creates a new copy of $ETRAP and then clears it, leaving no $ETRAP error handler for its context.
If an error occurs in routine D (a context in which no $ETRAP error handler is dened), Cach removes the DO frame for routine D from the call stack and transfers control to the $ETRAP error handler of Routine C. The $ETRAP error handler of Routine C, in turn, dispatches to ^CERR to process the error. If an error occurs in Routine C, Cach transfers control to the $ETRAP error handler of Routine C, but does not unwind the stack because the error occurs in a context where a $ETRAP error handler is dened.
159
Error Processing
Clearing $ECODE also clears the error stack for your process. Typically, you use the GOTO command to transfer control to a predetermined restart or continuation point in your application after the error condition is dismissed. In some cases, you may nd it more convenient to quit back to the previous context level after dismissing the error condition.
160
When appropriate, a $ETRAP error handler can terminate the application using the HALT command.
161
Error Processing
If the existing value of the $ECODE special variable is non-null, Cach appends the code for the new error to the current $ECODE value as a new comma piece. Error codes accrue in the $ECODE special variable until either of the following occurs: You explicitly clear $ECODE, for example:
SET $ECODE = ""
Then, the next new error code replaces the current list of error codes in $ECODE. When an error occurs and an error stack already exists, Cach records information about the new error at the context level where the error occurred, unless information about another error already exists at that context level on the error stack. In this case, the information is placed at the next level on the error stack (regardless of the information that may already be recorded there). Therefore, depending on the context level of the new error, the error stack may extend (one or more context levels added) or information at an existing error stack context level may be overwritten to accommodate information about the new error. Keep in mind that you clear your process error stack by clearing the $ECODE special variable. See the $ECODE and $ZERROR special variables in the Cach ObjectScript Reference for details.
Control then passes to error handlers as it does for normal application-level errors. You can add logic to your error handlers to check for errors caused by setting $ECODE. Your error handler can check $ZERROR for an <ECODETRAP> error (for example, $ZE["ECODETRAP" ) or your error handler can check $ECODE for a particular string value that you choose.
You can create your own error codes following the ANSI Standard by having the error handler set $ECODE to the appropriate error message prexed with a U .
SET $ECODE=",Upassword expired,"
162
1. 2. 3.
Cach displays an error message on the processs principal device Cach breaks at the call stack level where the error occurred The process enters Programmer Mode.
In the following Terminal prompt example, the second SET command has an undened local variable error:
USER>WRITE "hello",! SET x="world" SET y=zzz WRITE x,! hello WRITE "hello",! SET x="world" SET y=zzz WRITE x,! ^ <UNDEFINED> *zzz USER>
In the following example, the same line of code is in a program named mytest executed from the Terminal prompt:
USER>DO ^mytest hello WRITE "hello",! SET x="world" SET y=zzz WRITE x,! ^ <UNDEFINED>WriteOut+2^mytest *zzz USER 2d0>
In this case, $ZERROR indicates that the error occurred in mytest at an offset of 2 lines from the a label named WriteOut. Note that the prompt has changed, indicating we are in Programmer Mode.
If an error occurs during the execution of a routine, Cach saves the program stack entering Programmer Mode. An extended prompt appears, such as:
USER 2d0>
This extended prompt indicates that there are two entries on the program stack, the last of which is an invoking of DO (as indicated by the d). Note that this error placed two entries on the program stack. The next DO execution error would result in the prompt:
USER 4d0>
For a more detailed explanation, refer to Understanding the Programmer Mode Prompt Information in the Command-line Routine Debugging chapter.
163
Error Processing
Any of these steps can even cause additional errors. After you have taken these steps, your most likely course is to either resume execution or to delete all or part of the program stack.
Note that in this example because the program error created two program stack entries, you must be on a d stack entry to resume execution by issuing a GOTO. Depending on what else has occurred, a d stack entry may be even-numbered (USER 2d0>) or odd-numbered (USER 3d0>). By using NEW $ESTACK, you can quit to a specied program stack level:
164
Note that the NEW $ESTACK command adds one entry to the program stack.
Frequently when you get an error on a line and enter Programmer Mode, you can simply edit the line, enter the rest of the commands on that line in Programmer Mode, and then use a GOTO with a label+offset to resume execution at the next line of the routine. When an <EDITED> error occurs, you must use a QUIT command in Programmer Mode, with or without arguments, to remove the stacked commands as needed.
165
15
Command-line Routine Debugging
This chapter describes the Cach techniques for testing and debugging Cach applications. Its topics include: Debugging with the Cach Debugger Debugging With BREAK Using %STACK to Display the Stack Other Debugging Tools
An important part of application development is routine debugging: the testing and correcting of program code. Cach gives you two ways to debug your routines: Use the BREAK command in routine code to suspend execution and allow you to examine what is happening. Use the ZBREAK command to invoke the Cach Debugger to interrupt execution and allow you to examine both code and variables.
167
Breakpoints Watchpoints
A breakpoint is a location in a Cach routine that you specify with the ZBREAK command. When routine execution reaches that line, Cach suspends execution of the routine and, optionally, executes debugging actions you dene. You can set breakpoints in up to 20 routines. You can set a maximum of 20 breakpoints within a particular routine. A watchpoint is a variable you identify in a ZBREAK command. When its value is changed with a SET or KILL command, you can cause the interruption of routine execution and/or the execution of debugging actions you dene within the ZBREAK command. You can set a maximum of 20 watchpoints. Breakpoints and watchpoints you dene are not maintained from one session to another. Therefore, you may nd it useful to store breakpoint/watchpoint denitions in a routine or XECUTE command string so it is easy to reinstate them between sessions.
15.1.2.1 Syntax
ZBREAK location[:action:condition:execute_code]
where: location Required. Specifies a code location (that sets a breakpoint) or local or system variable (which sets a watchpoint). If the location specified already has a breakpoint/watchpoint defined, the new specification completely replaces the old one. Optional Specifies the action to take when the breakpoint/watchpoint is triggered. For breakpoints, the action occurs before the line of code is executed. For watchpoints, the action occurs after the command that modifies the local variable. Actions may be upper- or lowercase, but must be enclosed in quotation marks. Optional Specifies an expression that will be evaluated when the breakpoint/watchpoint is triggered. The expression must be surrounded by quotation marks. If condition is false, the action will not be carried out and the execute_code will not be executed. If condition is not specified, the default is true. Optional Specifies Cach ObjectScript code to be executed if condition is true. The code must be surrounded by quotation marks if it is a literal. This code is executed before the action being carried out. Before the code is executed, the value of the $TEST special system variable is saved. After the code has executed, the value of $TEST as it existed in the program being debugged is restored.
action
condition
execute_code
Note:
168
If the routine you are testing is currently loaded in memory (that is, an implicit or explicit ZLOAD was performed), you can use location values such as these: label label+3 +3 Break before the line label at label. Break before the third line after label. Break before the third line.
Variable names are preceded by an asterisk, as in *a. If you specify an array-variable name, the Cach Debugger watches all descendant nodes. For instance, if you establish a watchpoint for array a, a change to a(5) or a(5,1) triggers the watchpoint. The variable need not exist when you establish the watchpoint. You can also use the following special system variables: $ZERROR $ZTRAP $IO Triggered whenever an error occurs, before invoking the error trap. Triggered whenever an error trap is set or cleared. Triggered whenever explicitly SET.
169
Argument "L"
Description Same as "B", except GOTO initiates single-step execution, stopping at the beginning of each line. When a DO command, user-defined function, or XECUTE command is encountered, single-step mode is suspended until that command or function completes. Same as "B", except GOTO initiates single-step execution, stopping at the beginning of each line. DO commands, user-defined functions, and XECUTE commands do not suspend single-step mode. Same as "B", except GOTO initiates single-step execution, stopping at the beginning of each command. When a DO command, user-defined function, FOR command, or XECUTE command is encountered, single-step mode is suspended until that command or function completes. Same as "B", except GOTO initiates single-step execution, stopping at the beginning of each command. DO commands, user-defined functions, FOR commands, and XECUTE commands do not suspend single-step mode. Can be used together with any other argument. Outputs a trace message to the trace device. This argument works only after you have set tracing to be ON with the ZBREAK /TRACE:ON command, described later. The trace device is the principal device unless you define it differently in the ZBREAK /TRACE command. If you use this argument with a breakpoint, you see the following message: TRACE: ZBREAK at label2^rou2. If you use this argument with a watchpoint, you see a trace message that names the variable being watched and the command being acted upon. In the example below, the variable a was being watched. It changed at the line test+1 in the routine test. TRACE: ZBREAK SET a=2 at test+1^test. If you include the "T" action, you must also explicitly include the "B" action as in ZBREAK *a:"TB", to have an actual break occur. Take no action at this breakpoint/watchpoint.The condition expression is always evaluated and determines if the execute_code is executed.
"L+"
"S"
"S+"
"T"
"N"
The following example illustrates the above watchpoint acting on a direct mode Cach command (rather than on a command issued from within a routine). The caret (^) points to the command that caused execution to be suspended:
%SYS>KILL a KILL a ^ <BREAK> %SYS 1s0>
The following example establishes a breakpoint that suspends execution and sets single-step mode at the beginning of the line label2^rou.
ZBREAK label2^rou:"L"
The following example shows how the break would appear when the routine is run. The caret (^) indicates where execution was suspended.
170
In the following example, a breakpoint at line label3^rou does not suspend execution, because of the "N" action. However, if x<1 when the line label3^rou is reached, then ag is SET to x.
ZBREAK label3^rou:"N":"x<1":"SET flag=x"
The following example establishes a watchpoint that executes the code in ^GLO whenever the value of a changes. The double colon indicates no condition argument.
ZBREAK *a:"N"::"XECUTE ^GLO"
The following example establishes a watchpoint that causes a trace message to display whenever the value of b changes. The trace message will display only if trace mode has been turned on with the ZBREAK /TRACE:ON command.
ZBREAK *b:"T"
The following example establishes a watchpoint that suspends execution in single-step mode when variable a is set to 5.
ZBREAK *a:"S":"a=5"
When the break occurs in the following example, a caret (^) symbol points to the command that caused the variable a to be set to 5.
%SYS>DO ^test FOR i=1:1:6 SET a=a+1 ^ <BREAK> test+3^test %SYS 3f0>WRITE a 5
A disabled breakpoint is turned off , but Cach remembers its denition. You can enable the disabled breakpoint by preceding the location with a plus sign. The following command enables the previously disabled breakpoint:
ZBREAK +label2^rou
171
Important:
A delayed breakpoint is not decremented when a line is repeatedly executed because it contains a FOR command.
After you have deleted a breakpoint/watchpoint, you can only reset it by dening it again. To delete all breakpoints, issue the command:
ZBREAK /CLEAR
Unlike other breakpoints, ZBREAK $ does not cause a break, because breaks occur automatically as you single-step. ZBREAK $ lets you specify actions and execute code at each point where the debugger breaks as you step through the routine. It is especially useful in tracing executed lines or commands. For example, to trace executed lines in the application ^TEST:
%SYS>ZBREAK /TRACE:ON %SYS>BREAK "L+" %SYS>ZBREAK $:"T"
The "T" action specied alone (that is, without any other action code) suppresses the single step break that normally occurs automatically. (You can also suppress the single-step break by specifying the "N" action code either with or without any other action codes.) Establish the following single-step breakpoint denition if both tracing and breaking should occur:
%SYS>ZBREAK $:"TB"
172
When device is used with the ALL or ON state keywords, trace messages are redirected to the specied device rather than to the principal device. If the device is not already open, Cach attempts to open it as a sequential le with WRITE and APPEND options. When device is specied with the OFF state keyword, Cach closes the le if it is currently open. Note:
ZBREAK /TRACE:OFF does not delete or disable the single-step breakpoint denition set up by ZBREAK /TRACE:ALL, nor does it clear the L+ single stepping set up by ZBREAK /TRACE:ALL. You must also issue the commands ZBREAK --$ and BREAK "C" to remove the single stepping; alternatively, you can use the single command BREAK "OFF" to turn off all debugging for the process.
Tracing messages are generated at breakpoints associated with a T action. With one exception, the trace message format is as follows for all breakpoints: Trace: ZBREAK at line_reference where line_reference is the line reference of the breakpoint. The trace message format is slightly different for single step breakpoints when stepping is done by command: Trace: ZBREAK at line_reference source_offset where line_reference is the line reference of the breakpoint and source_offset is the 0-based offset to the location in the source line where the break has occurred. Operating System Notes: Windows Trace messages to another device are supported on Windows platforms for terminal devices connected to a COM port, such as COM1:. You cannot use the console or a terminal window. You can specify a sequential le for the trace device UNIX To send trace messages to another device on UNIX platforms: 1. 2. Log in to /dev/tty01. Verify the device name by entering the tty command:
$ tty /dev/tty01
3.
4.
173
5. 6.
7.
Run your program. If you have set breakpoints or watchpoints with the T action, you see trace messages appear in the window connected to /dev/tty01.
OpenVMS To send trace messages to another device on OpenVMS platforms: 1. 2. Log in on TTA1:. Verify the device name by entering the following command at the DCL prompt:
$ WRITE sys$output f$getjpi("","TERMINAL") TTA1:
3.
Issue the PROTECTION command so you have write privileges to the terminal:
$SET PROT=W:rwlp TTA1:
4.
5. 6.
Return to your working window or to a terminal where you are logged in on your principal device. Issue the following command to set your process privileges to share:
$SET PROC/PRIV=share
7. 8.
9.
Run your program. If you have set breakpoints or watchpoints with the T action, you will see trace messages appear on the window connected to TTA1:.
var is the variable being watched. val is the new value being set for that variable.
174
If you issue a NEW command, you receive no trace message. However, the trace on the variable is triggered the next time you issue a SET or KILL on the variable at the NEW level. If a variable is passed by reference to a routine, then that variable is still traced, even though the name has effectively changed.
This causes a break to occur when you press the INTERRUPT key even if you have disabled interrupts at the application level for the device. If you press the INTERRUPT key during a read from the terminal, you may have to press RETURN to display the breakmode prompt. To reset interrupt processing to generate an error rather than cause a break, issue the following command:
ZBREAK /INTERRUPT:NORMAL
Output from this command is displayed on the device you have dened as your debug device, which is your principal device unless you have dened the debug device differently with the ZBREAK /DEBUG command described in the Using the Debug Device section. The following table describes the ags provided for each breakpoint and watchpoint: Display Section Identification of break/watch point F: S: Meaning Line in routine for breakpoint. Local variable for watchpoint. Flag providing information about the type of action defined in the ZBREAK command. Number of iterations to delay execution of a breakpoint/watchpoint defined in a ZBREAK command. Condition argument set in ZBREAK command. Execute_code argument set in ZBREAK command.
C: E:
The following table describes how to interpret the F: value in a breakpoint/watchpoint display. The F: value is a list of the applicable values in the rst column.
175
Value E D B L L+ S S+ T
Meaning Breakpoint or watchpoint enabled Breakpoint or watchpoint disabled Perform a break Perform an "L" Perform an "L+" Perform an "S" Perform an "S+" Output a Trace Message
This means: Trace execution is OFF There is no break if CTRL-C is pressed No break/watchpoints are dened
The rst two ZBREAK commands dene a delayed breakpoint; the second two ZBREAK commands dene a disabled breakpoint; the fth ZBREAK command denes a watchpoint. The sixth ZBREAK command enables trace execution. The nal ZBREAK command, with no arguments, displays information about current debug settings. In the example, the ZBREAK display shows that: Tracing is ON There is no break if CTRL-C is pressed.
The output then describes the two breakpoints and one watchpoint: The F ag for the rst breakpoint equals EB and the S ag equals 5, which means that a breakpoint will occur the fth time the line is encountered. The E ag displays executable code, which will run before the Cach Programmer prompt for the break is displayed.
176
The F ag for the second breakpoint equals DL , which means it is disabled, but if enabled will break and then singlestep through each line of code following the breakpoint location. The F ag for the watchpoint is ET , which means the watchpoint is enabled. Since trace execution is ON, trace messages will appear on the trace device. Because no trace device was dened, the trace device will be the principal device. The C ag means that trace is displayed only when condition is true.
Note:
When you enter Cach, the debug device will automatically be set to your principal device. At any time, debugging I/O can be sent to an alternate device with the command: ZBREAK /DEBUG:"device". Note: There are also operating-system-specic actions that you can take. On OpenVMS systems, to cause the break to occur in an X window linked to the device TTA1:, issue the following command:
ZBREAK /D:"TTA1:"
On UNIX systems, to cause the break to occur on the tty01 device, issue the following command:
ZBREAK /D:" /dev/tty01/"
When a break occurs, because of a CTRL-C or to a breakpoint or watchpoint being triggered, it appears in the window connected to the device. That window becomes the active window. If the device is not already open, an automatic OPEN is performed. If the device is already open, any existing OPEN parameters are respected. Important: If the device you specify is not an interactive device (such as a terminal), you may not be able to return from a break. However, the system does not enforce this restriction.
However, when you run test, only variables b and c hold the correct values:
177
The problem in the program is obvious: variable a is KILLed on line 4. However, assume you need to use the debugger to determine this. You can use the ZBREAK command to set single-stepping through each line of code ("L" action) in the routine test. By a combination of stepping and writing the value of a, you determine that the problem lies in line 4:
%SYS>NEW %SYS 1S1>ZBREAK BREAK No breakpoints No watchpoints %SYS 1S1>ZBREAK ^test:"L" %SYS 1S1>DO ^test SET a=1 ^ <BREAK>test+1^test %SYS 3d3>WRITE a <UNDEFINED>^test %SYS 3d3>GOTO SET b=2 ^ <BREAK>test+2^test %SYS 3d3>WRITE a 1 %SYS 3d3>GOTO SET c=3 KILL a WRITE "in test, at end" ^ <BREAK>test+3^test %SYS 3d3>WRITE a 1 %SYS 3d3>GOTO in test, at end QUIT ^ <BREAK>test+4^test %SYS 3d3>WRITE a WRITE a ^ <UNDEFINED>^test %SYS 3d3>GOTO %SYS 1S1>
You can now examine that line and notice the KILL a command. In more complex code, you might now want to singlestep by command ("S" action) through that line. If the problem occurred within a DO, FOR, or XECUTE command or a user-dened function, you would use the "L+" or "S+" actions to single-step through lines or commands within the lower level of code.
In the program test, variable b is not dened at line test+1, so there is an error. The error display appears as follows:
IF a=5 XECUTE "WRITE b" IF 1 ^ <UNDEFINED>test+1^test
178
If you had not dened a condition, then an articial true condition would be dened before and after the execution code; for example:
%SYS>IF 1 WRITE b IF 1
When you sign on in Programmer Mode, your process begins with an implicit BREAK 1 (interrupt enabled) by default. BREAK functionality is not available in Application Mode.
You can then set the variable debug to suspend the routine and return the job to Programmer Mode or clear the variable debug to continue running the routine. For further details, refer to Command Postconditional Expressions in this manual.
179
BREAK "S+"
BREAK S-
BREAK "L"
BREAK "L+"
BREAK L-
BREAK "C"
BREAK "OFF"
Cach stacks the break state whenever a DO, XECUTE, FOR, or user-dened function is entered. If you choose BREAK "C" to turn off breaking, the system restores the break state at the end of the DO, XECUTE, FOR, or user-dened function. Otherwise, Cach ignores the stacked state. Thus if you enable breaking at a low subroutine level, breaking continues after the routine returns to a higher subroutine level. In contrast, if you disable breaking at a low subroutine level that was in effect at a higher level, breaking resumes when you return to that higher level. When you enter Programmer Mode, the break state is not stacked. Thus you can change the break state and the new state remains in effect when you issue an argumentless GOTO to return to the executing routine. Periodic breaking does not occur for lines of code executed in Programmer Mode or for XECUTE lines started from Programmer Mode. When you enter Programmer Mode after a BREAK, you can enter Cach ObjectScript commands and
180
use the line editor without encountering periodic breaking. However, after you issue a DO command or user-dened function, breaking resumes if B "L+" or B "S+" is in effect. When B "L" or B "S" is in effect in Programmer Mode, a DO from Programmer Mode breaks on the rst line or command in the routine, although a subsequent DO does not. Therefore, you can begin debugging by entering a B "L" or B "S" in Programmer Mode then issuing a DO without specifying B "L+" or B "S+".
Prompts you can see in such messages are listed in the following table.
181
You can unwind the program stack using QUIT 1. The following is an example of the Programmer Mode prompts following an error:
USER 6f0>QUIT USER 5x0>QUIT USER 4f0>QUIT USER 3f0>QUIT USER 2d0>QUIT USER 1S0>QUIT USER> 1 1 1 1 1 1 /* /* /* /* /* /* an error occurred in a FOR loop. */ the FOR loop was in code invoked by XECUTE. */ the XECUTE was in a FOR loop. */ that FOR loop was nested inside another FOR loop. */ the DO command was used to execute the program. */ sign on state. */
By typing a GOTO with an argument, you can resume execution at the beginning of another line in the same routine with the break or error, as follows:
4f0>GOTO label3
You can also resume execution at the beginning of a line in a different routine:
4f0>GOTO label3^rou
Alternatively, you may clear the program stack with an argumentless QUIT command:
4f0>QUIT %SYS>
With BREAK "L", breaking does not occur in the routine SUB1.
182
For example:
4d0>NEW 5B1>DO ^%T 3:49 PM 5B1>QUIT 1 4d0>GOTO
The 5B1> prompt indicates that the system has stacked the Programmer Mode entered through a BREAK. The 1 indicates that a NEW command has stacked variable information, which you can remove by issuing a QUIT 1. When you wish to resume execution, issue a QUIT 1 to restore the old symbol table, and a GOTO to resume execution. Whenever you use a NEW command, parameter passing, or user-dened function, the system places information on the stack indicating that later an explicit or implicit QUIT at the current subroutine or XECUTE level should delete certain variables and restore the value of others.
183
In Programmer Mode, you may nd it useful to know if any NEW commands, parameter passing, or user-dened functions have been executed (thus stacking some variables), and if so, how far back on the stack this information resides.
To remove only a couple of items from the program stack (for example, to leave a currently executing subroutine and return to a previous DO level), use QUIT with an integer argument. QUIT 1 removes the last item on the program stack, QUIT 3 removes the last three items, and so forth, as illustrated below:
9f0>QUIT 3 6d0>
This error message indicates an <UNDEFINED> error (that refers to the variable y) in line label+3 of routine rou. At this point, this message is also the value of the special variable $ZERROR.
As shown in this example, the %STACK utility displays the current process stack without variables.
184
;level=2
Under the current execution stack display, %STACK prompts you for a stack display action. You can get help by entering a question mark (?) at the Stack Display Action prompt.
15.3.2.4 Displaying the Stack with All Variables, including State Variables
You can print all possible reports to screen, le or printer by entering *A at the Stack Display Action prompt. This report prints the following: Process state variables Process execution stack with all variables
185
Line Source
The following table shows whether level, line, and source values are available for each frame type. A "No" under Level indicates that the level number is not incremented and no level number appears in the display.
PARAMETER
No
No
SIGN ON
Yes
No
186
* The LINE value is blank if these are invoked from Programmer Mode.
You enter any of the commands listed above whenever you see the -- more -- or -- ni -- prompts. For the B, L and W commands, you enter a numeric argument before the command letter. For instance, enter 2B to move back two pages, or enter 20L to set the page length to 20 lines. Be sure to set your page length to the number of lines which are actually displayed; otherwise, when you do a page up or down, some lines may not be visible. The default page length is 23.
187
188
When an error occurs and you call the %ETN utility, you see a message similar to the following message:
Error has occurred: <SYNTAX> at 10:30 AM
Because %ETN ends with a HALT command (terminates the process) you may want to set the %ETN error trap only if the routine is used in Application Mode. When an error occurs in Programmer Mode, it may be useful for the error to be displayed on the terminal and go into the debugger prompt to allow for immediate analysis of the error. The following code sets an error trap only if Cach is in Application Mode:
SET $ZTRAP=$SELECT($ZJ#2:"",1:"^%ETN")
2.
189
3.
You are then prompted for a variable. You can now enter either a question mark (for a list of further options) or one of the responses shown in the following table:
4. 5. 6. 7.
If you press RETURN in response to the Variable: prompt, you return to the Error #: prompt. If you press RETURN again, you return to the For Date: prompt. Press RETURN a third time to leave the utility. If you are prompted to delete old errors, answer Y or press RETURN.
In the following code, a ZLOAD of the routine REPORT is issued to illustrate that by loading all of the variables with *LOAD and then loading the routine, you can recreate the state of the job when the error occurred except that the program stack, which records information about DOs, etc., is empty.
%SYS>DO ^%ERN For date:4/30/99 Error: ?L 1) <DIVIDE>CALC+4^CALC at 01:35PM. Device=70, TRM #70. $J=12472 $ZA=0 $ZB="^M" $ZS=20 ($S=16590784) SET C=R/(F+DT) 2) <SUBSCRIPT>REPORT+4^REPORT at 03:16PM. Device=70, TRM #70. $J=12472 $ZA=0 $ZB="^M" $ZS=20 ($S=16590784) SET ^REPORT(%DAT,TYPE)=I 3) <SYNTAX>ZSET+5^ZSET at 10:34AM. Device=70, TRM #70. $J=12472 $ZA=0 $ZB="^M" $ZS=20 ($S=16590784) XECUTE XSET Error: 2 2) <SUBSCRIPT>REPORT+4^REPORT at 03:16PM. Device=70, TRM #70. $J=12472 $ZA=0 $ZB="^M" $ZS=20 ($S=16590784) SET ^REPORT(%DAT,TYPE)=I Variable: %DAT %DAT="Apr 30 99" Variable: TYPE TYPE="" Variable: *LOAD %SYS>ZLOAD REPORT %SYS>WRITE %DAT="Apr 30 99" %DS="" %TG="REPORT+1" I=88 TYPE="" XY="SET $X=250 WRITE *27,*91,DY+1,*59,DX+1,*72 SET $X=DX,$Y=DY" %SYS> 3 errors.
190
Note:
%ER is a legacy name for %ERN. Their functionality is identical, though %ERN is slightly more efcient.
191
16
Open M Language Compatibility
Cach offers language compatibility modes for: DSM-11 Open M [DSM] Open M [DTM] Open M [MSM]
These modes make it possible to port applications from the above installations into Cach by accommodating the syntax of many of the more common M programming language commands and functions into Cach ObjectScript. Cach ObjectScript is a superset of the ISO 11756-1999 standard M programming language. The ISO 11756-1999 standard is identical to the former ANSI-standard M programming language. This chapter presents the following topics as they relate to compatibility modes: Displaying and Switching Language Mode DSM-11 Language Compatibility DSM Language Compatibility DSM-J Language Compatibility DTM Language Compatibility MSM Language Compatibility
193
If you follow the procedures outlined in this section to port, manage, and convert DSM mode routines, you do not need to use LanguageMode() method calls to set language mode. If you want to use LanguageMode() to see the current language mode, issue the following command:
WRITE ##class(%SYSTEM.Process).LanguageMode()
You can also set the language mode by any command that affects loading of a routine. The current dialect will be set to that of the routine. In the case of a DO, the previous dialect is restored upon leaving the routine. This will also happen for ZLOAD or GOTO done within command indirection (XECUTE). The general-use language modes represented in Cach are as follows.
194
processing until it successfully opens the device or times out. Any number of processes can attempt to open the device; each one waits until the one before it releases the device with a Close command. In this way, an Open command to a routine interlock device guarantees a process exclusive access to the data associated with the device, as long as all applications: Are consistent in their use of this technique (as with the Lock command) Agree on the data associated with each routine interlock device
After the process issues a Close command to that device number, another process can open the device and have exclusive access to the data.
Syntax
Open device[::timeout]
Parameter device
Description A device number, from 20 through 46 or 200 through 223. You must ensure that all routines that use a given device number agree on the meaning of that number. The meaning is usually which global(s) are now considered locked and thus not available to other processes. A positive integer whose value in seconds is the longest time Cach waits for an Open to finish. If you specify 0, the Open returns control to the process immediately.
timeout
Syntax
Close device
195
Cach provides only runtime support for the DSM-11 language. It does not support the DSM-11 development environment, nor does it support calls to the DSM-11 library utilities or MACRO-11 routines. You can only do further development on DSM-11 routines in the Cach development environment. When you load a routine with the Full Screen Editor or the ZLoad command, Cach sets the language mode to match that of the routine. If you change the language mode with the LanguageMode() method so that it does not match that of the loaded routine, and then attempt to do a ZInsert, you will get a <LANGUAGE MISMATCH> error message.
196
Set the size of the output ring buffer. Specify field length.This parameter serves only for DSM-11 backward compatibility. The Read command is now the preferred technique for specifying field length. Set the size of the input ring buffer Modify device characteristics
Accepted but ignored. Bit mask related to InterSystems mode protocol parameter. See next table for details. Bit mask related to Cach mode protocol parameter. See next table for details. Accepted but ignored. Same as DSM-11. Equivalent to Cach mode terminators parameter in functionality, although it occupies a different parameter position.
p6: clear status p7: set $X and $Y p8: line parameter register p9: terminators
Modify device characteristics Change $X and $Y settings for the terminal. Values assigned based on the type of controller. Establish a set of line terminators for the device.
197
DSM-11 Meaning Establish a set of application interrupt keys for the device. Specify the length of time to suspend execution if the requested device is not free.
DSM-11 Compatibility Mode Interpretation Accepted but ignored. Same as DSM-11. Identical to Cach mode timeout parameter both in function and in parameter position.
The protocol parameter in Cach mode is a string containing some combination of the following: B (enable Ctrl-C) C (CRT) F (ush) I (image) P (printer) S (secret, no echo) T (terminators).
Similarly, DSM-11 has the set status and clear status parameters, both of which are bit masks. To turn on a protocol, you must include its bit in the set status parameter. To turn off a protocol, you must include its bit in the clear status parameter. In DSM-11 compatibility mode, Cach accepts but ignores bits that are operating system specic. The following table lists the bits that are supported.
198
Table 163: DSM-11 Compatibility Mode Set and Clear Status Bits
Bit 0 (1) 2 (4) 6 (64) Value 0 - Echo; 1 - No Echo 0 - Hardcopy; 1 - CRT 0 - Escape Processing Disabled; 1 - Escape Processing Enabled Description Identical to Cach S protocol. Identical to Cach C protocol. Determines how escape sequences are handled on Read. In Cach mode, an escape sequence always terminates a non image mode Read, and the escape sequence appears as a string in $ZB. In DSM 11 mode, an escape sequence always terminates a normal Read, but the escape sequence is processed only if escape processing is enabled. When escape processing is enabled, the decimal ASCII code of the second character appears in the high byte of $ZB and the decimal ASCII code of the escape character itself appears in the low byte. When escape processing is disabled, the escape character is treated like any terminator and the remaining character(s) of the escape sequence are not processed.They remain in the input buffer where they can be accessed by subsequent Read commands. Determines the handling of parameter 7: set $X and $Y. When a parameter 7 value is supplied on Open/Use in DSM-11 language compatibility mode, $X and $Y are updated accordingly and if bit 7 is ON, the appropriate cursor control sequence (VT52 or ANSI, depending on bit 16) is transmitted to the terminal. Determines whether or not case is converted on input. Determines the appropriate cursor control sequence. Determines the effect of pressing the Delete key when there is nothing in the input buffer to delete. If the bit is ON, the delete character is ignored. If the bit is OFF, the Read terminates and the delete character appears as 127 in the low byte of $ZB. Determines the effect of pressing non-programmed control keys. When the bit is OFF, all nonprogrammed control keys are accepted as normal characters. When the bit is ON, non-programmed control keys are ignored. They are not echoed or placed in the input buffer. Identical to Cach IMAGE mode protocol. When the bit is ON, all control characters pass directly to the program without filtering or interpretation.
7 (128)
0 - No conversion; 1 Convert to uppercase 0 - VT52; 1 - ANSI 0 - Ignore Delete Character; 1 - Acknowledge Delete Character
20 (1048576)
23 (8388608)
199
Bit 25 (33554432)
Description Determines the handling of type- ahead. When bit 25 is ON, type- ahead is disabled. The input buffer is flushed before each Read. When bit 25 is OFF, type-ahead is enabled. The input buffer is not flushed before each Read. When bit 26 is OFF, no additional type-ahead control beyond that provided by bit 25 is conferred. When bit 26 is on, the type-ahead buffer can never be flushed, unless explicitly directed by bit 25. For example, Read with a prompt does not flush type-ahead.
26 (68108864)
On Windows, Cach ObjectScript allocates each process an open le quota between database les and les opened with Open. When Open causes too many les to be allocated to Open commands, you receive a <TOOMANYFILES> error message. Cach does not limit the number of open les; the maximum number of open les for each process is a platformspecic setting. Consult the operating system documentation for your system.
CAUTION:
Open/Use parameters that are unique to DSM-11 compatibility mode are honored at Read/Write time only if the last Open/Use of the device was in DSM-11 mode. The parameters unique to DSM-11 mode are p5/p6 (bits 6,7,19,20,25,26) and p7.
Terminating a READ
If a terminator completes a Read, the special variable $ZB contains the terminator character as a string in Cach mode, while in DSM-11 mode the ASCII decimal value of the terminator is returned in the low byte of $ZB. If an escape sequence terminates a Read, Cach mode returns the ASCII escape sequence as a string in $ZB, while DSM11 mode returns an integer with the escape character (27) in the low byte of $ZB and the second character plus 16 then modulo 64 in the high byte.
200
DSM-11 mode 3 4 5
Cach mode 1 2 3
In DSM-11 mode, the $ZA and $ZB special variables return magnetic tape operation values that are compatible with DSM-11. In Cach mode, magnetic tape control functions are accomplished by using Write * -n (negative value), while DSM-11 compatibility mode uses Write * n (positive value). The assignments of the absolute values to control functions are the same for both modes, except that DSM-11 offers Write *10, which updates $ZA. This is useful with the DSM-11 C format option for checking the status of the asynchronous I/O operation, as discussed above.
The ZaMode property of the Config.Miscellaneous class allows you to select which behavior ZAllocate and ZDeallocate enact system-wide: Cach mode or DSM-11 mode.
201
$ZSort
CAUTION:
Cach supports these special variables only in DSM-11 mode: $ZA $ZB
Cach supports the following commands in DSM-11 compatibility mode: ZPrint ZWrite ZBreak
ZPrint is identical to the Cach mode PRINT command. ZWrite is identical to the argumentless WRITE command. In DSM-11 M, the ZBreak ON and ZBreak OFF commands control the processing of argumentless Break commands. The BreakMode() method of the %SYSTEM.Process class simulates this DSM-11 behavior and works in both language modes. Issuing BreakMode(0) disables the processing of argumentless Break commands (similar to ZBreak OFF). Issuing BreakMode(1) enables the processing of argumentless Break commands (similar to ZBreak ON). Issuing BreakMode() without an argument returns the current state of the switch without changing it.
202
203
If you change the language mode with the LanguageMode() method so that it does not match that of the loaded routine, and then attempt to do a ZInsert, you will get a <LANGUAGE MISMATCH> error message. Currently %RI and ^%rde report <SYNTAX> errors on some DSM language features in a DSM mode routine. This indicates that the syntax is not valid Cach ObjectScript syntax. However, the code will interpret correctly if it is a currently recognized DSM language feature in DSM compatibility mode.
Note:
By contrast, in DSM the Close, Open, Use, ZUse, and Job commands feature keyword syntax where keywords and not position give meaning to parameter values. For example:
Use terminal:[keylist]:"mnespace"
In each, the intent is to communicate information about operations to the specied device. For example the programmer may want to convert Read command input characters to uppercase. In Cach native language mode, this is done with the following syntax:
Use 0pen:(:"+U")
and in DSM language mode the following accomplishes the same thing:
Use 0pen:CONVERT
Currently DSM language mode supports certain keywords for terminal type devices. The following keyword is recognized but treated as a no-op for the Open command:
BLOCKSIZE=n
The following keywords are recognized and functional when applied to sequential les (Windows platforms only) by the Open command: DELETE NEWVERSION READONLY RECORDSIZE
The DISCONNECT keyword is recognized and functional when applied to sequential les by the Use command. The following keywords are recognized and functional when applied to sequential les by the Close command: DELETE NODELETE RENAME
For discussions on how to use the above keywords, see the DSM documentation.
204
The following exceptions apply to Cach in DSM language mode: When closing a newly created le, DSM will delete the le if nothing has been written to it. However, in Cach the Close command in DSM language mode does not delete the le. The RECORDSIZE keyword specied with the Open command for sequential les currently affects Read operations only. When the RENAME keyword is specied with the Close command and the le to be closed is marked for delete, DSM deletes the le, then generates a %DSM-E-RENAMERR error. However, in Cach the Close command in DSM language mode renames the le and does not delete it. When the RENAME and DELETE keywords are specied with the Close command, DSM deletes the le then generates a %DSM-E-RENAMERR error. However, in Cach the Close command in DSM language mode deletes the le.
The following keywords are recognized and functional for the Use command: CENABLE CLEARSRCR CONVERT CURSOR DEVTYPE=s DOWNSCRO ECHO ERASELIN LINE NOCENABL NOCONVERT NOCURSOR NOECHO NOLINE NOREADPFLU NOTYPE READPFLU TERMINATOR=s TYPE UPSCROLL WIDTH=n X=n Y=n
BREAK 0 must be active to allow CENABLE and NOCENABL to have their intended effect. BREAK 0 is the default in Application Mode. However, BREAK 1 is the default in Programmer mode and is implicitly reasserted at every Programmer Mode prompt. Therefore BREAK 0 must be re-typed at every Programmer Mode prompt to interactively test the CENABLE
205
The CLEARSCR, DOWNSCRO, ERASELIN, UPSCROLL, X=n, and Y=n keywords cause VT100 escape sequences to be written to the specied device and will only work with devices that recognize the sequences. When the specied device is a console window, Cach automatically translates the escape sequences into window operations that perform the desired result. The LINE and NOLINE keywords enable and disable Cach read line recall. Read line recall may initially be disabled by default. Use the LineRecall() method of the %SYSTEM.Process class to enable read line recall by default for your process. In DSM, the TYPE and NOTYPE keywords have no effect unless the /TYPEAHEAD command line qualier is in effect for the DSM process. In DSM for DEC OSF/1 AXP the same is true, but the NOREADPFLU keyword can be used to accomplish dynamically the same thing as the /TYPEAHEAD command qualier while READPFLU negates the /TYPEAHEAD behavior. Therefore NOREADPFLU and READPFLU are provided in DSM compatibility mode so that NOREADPFLU can be specied for the principal device at application start up to accomplish the same behavior as the DSM /TYPEAHEAD qualier. DSM compatibility mode recognizes the following keywords but treats them as no-ops for Use: ESCAPE (in effect by default) FLUSH NOPACK PACK
DSM language mode also supports several keywords for the Job command. The following keywords are recognized and functional: DATA INPUT OUTPUT
The following keywords are recognized but treated as no-ops for Job: DETACHED (also a no-op on DSM systems) ERROR NAME PRIORITY OPTIONS
DSM compatibility mode currently handles all other standard M commands except the BREAK and VIEW commands, which (according to the standard) take implementer-specic arguments.
206
performs cursor positioning. In DSM, user dened mnemonic space tables associate the keywords in the mnemonic space with routine entry points that are called at runtime to perform the operation. DSM applications associate a mnemonic space table and the keywords dened by it with a device by specifying the mnemonic space name with an Open or Use command. Cach does not use a table to map the device control mnemonics in a mnemonic space to M routine entry points. Rather it infers the entry point label name from the control mnemonic (the control mnemonic is converted to uppercase to form the label name) and it uses the current mnemonic space name specied for the device as the entry point routine name. For example, in the following sequence Cach calls back to the M routine entry point CUP^%X364 as a result of the WRITE / command:
Set DevZero=0 Use DevZero::"^%X364" Write /CUP(1,1)
If your user-dened mnemonic space tables specify case conversion for control mnemonics, you can update your application to run in DSM compatibility mode in Cach . Further, if all your control mnemonics already match all the label names of their associated Cach ObjectScript routine entry points, then all that is necessary is that all labels be present in a single routine. If any control mnemonic does not match the label name of its associated Cach ObjectScript routine entry point then an entry point bridge whose label name does match the control mnemonic can be added. The entry point bridge needs only to call the original target Cach ObjectScript routine entry point passing along any expected parameters. Of course, you can produce the same effect by changing the label name of the original entry point. Whether bridge entry point labels or original entry point labels, all must be present in a single Cach ObjectScript routine. In DSM compatibility mode, Cach determines the name of the Cach ObjectScript routine that contains control mnemonic call back labels in one of two ways. When a specied mnemonic space name begins with the ^ character Cach assumes the mnemonic space name is the Cach ObjectScript routine name; otherwise it adds a ^%Z prex to the mnemonic space name to form the Cach ObjectScript routine name. This latter case will be the rule unless you update your DSM application code (usually a less desirable option). The following sequence is an example of the latter case:
Set DevZero=0 Use DevZero::"ZTERM" Write /CUP(1,1)
In this sequence Cach performs a callback to the Cach ObjectScript routine entry point CUP^%ZZTERM as a result of the Write / command. The names of the Cach ObjectScript routines containing control mnemonic callback entry points can be changed to adhere to this convention.
207
ZTrap (generates an error but DSM style error handling and error messages are not currently implemented) ZWrite (only the argumentless form is implemented)
The DSM ZUse command is recognized but treated as a no-op. Note that ZUse keywords are not currently implemented. The following DSM Z functions are recognized and functional: $ZDate $ZNext $ZOrder $ZPrevious $ZSearch (works only on Cach for Windows) $ZSort (a subscriptless global $ZSORT argument is not currently implemented)
The following DSM I/O related Z special variables are recognized and functional for terminal devices: $ZA $ZB $ZCONTROLC $ZIO (works only on Cach for Windows)
The following other DSM Z special variables are recognized and functional: $ECODE $ESTACK $ETRAP $QUIT $STACK $ZDEVTYPE $ZERROR (contains error information but DSM-style error handling and error messages are not currently implemented) $ZJOB $ZNAME $ZREFERENCE $ZTRAP $ZVERSION
The following DSM library external functions ($ZCALLs) are recognized and functional. Mathematical: %ARCCOS %ARCSIN %ARCCTAN %BOOLEAN %COS
208
%EXP %LOG %LOG10 %MAX %MIN %POWER %SIN %SQRT %TAN The precision in the numbers returned for these functions may be somewhat different from DSM systems
Note:
Miscellaneous: %LPC
209
Cach using the DSM-J language mode supports the following keywords when applied to sequential les by the Use command: KAN[JIDEVICE] NOKAN[JIDEVICE] KCODE=conversion_specication KON[ESCAPE]=escape_sequence KOFF[ESCAPE]=escape_sequence KPITCH=pitch_value KDIR[INPUT] NOKDIR[INPUT] KIN=switch (switch= ON or OFF )
For a complete discussion of the above-listed command keywords, see the DSM-J documentation.
16.5.1.1 Operators
You can use the DTM-specic operators in DTM compatibility mode. These operators are: <> The record-forming operator. The record-forming operator creates a string which contains the pieces in between the angle brackets. Example: If $ZPIECE is equal to ^ and you issue Set x = <a,b>, then x equals a_"^"_b The field operator. The field operator sets a string equal to the n th piece of another string. Example: If s equals s12^ab , then s.2 equals ab
.n
210
The default namespace for the jobbed process. An integer bit mask value specifying whether Cach should pass your current symbol table to the new process, and other information. The principal input device for the process. The principal output device for the process.
Because the parameters are positional, you must specify them in the order shown. If you omit a parameter that precedes a parameter you are including, you must include a colon as a placeholder for it. See the JOB command in the Cach ObjectScript Language Reference for more information. In DTM, the process parameters can be up to 10 values. Each is in the form:
keyword=value
keyword value
The name of a specific process parameter. The value you want to assign the process parameter.
The keywords you can use are: lvmem lvmin lvmax name node nspace pdev priority strstk sysstk The amount of memory (in bytes) to allocate for the jobbed process symbol table. The minimum amount of memory (in bytes) to allocate for the symbol table. The maximum amount of memory (in bytes) to allocate for the symbol table. The name to assign to the job. The name of the network node on which the job is to run. The namespace in which to execute the job. The principal device of the job. The priority of the job (0 through 9). The size of the string stack in bytes. The size of the system stack in bytes.
Because of the keywords, the parameters are not positional. To specify multiple process parameters, use a colon-separated list in the form:
(keyword=value[:keyword=value]...)
You do not have to specify colons for parameters you do not specify.
211
missing parameters are unnecessary. In this example, Open accepts the default device parameters for the device being opened for all but the fth parameter:
Open DEV(::::param5)
You can use a timeout with I/O commands. You can specify timeouts as integer values, decimal values, or as expressions that evaluate to integer or decimal values. You cannot use control mnemonics with DTM devices. You cannot use device parameters with the Close command. DTM does not recognize Close device parameters.
16.5.2.1 Commands
These standard M commands operate identically in Cach mode and DTM compatibility mode: Do Else For Halt If Kill Lock Merge New Print Quit Write Xecute
212
These extended M commands operate identically in Cach mode and DTM compatibility mode: ZInsert ZNSpace ZRemove ZSync ZZDump
The following extended M command is not available in Open M [DTM] compatibility mode: ZTrap
16.5.2.2 Functions
The following standard M functions operate identically in DTM compatibility and Cach mode: $ASCII $Char $Data $Find $FNumber $Get $Justify $Length $Name $Next $Order $Piece $QLength $QSubscript $Query $Random $Reverse $Select $Translate
The following extended M functions operate identically in DTM compatibility and Cach mode: $ZBitAnd
213
These extended functions are not available in DTM compatibility mode: $ZBoolean $ZF $ZHex $ZIncr $ZNext $ZSearch $ZSort $ZTime $ZU
The following DTM mode math functions operate identically in Cach mode and DTM compatibility mode: $ZAbs $ZArcCos $ZArcSin $ZArcTan $ZCos $ZCot $ZCSC $ZExp $ZLn $ZLog $ZPower $ZSec $ZSin $ZSqr $ZTan
214
These set up a general error handler and call %math utility entry points. The general error handler turns any reported error into an <ILLEGAL VALUE> error which is returned to the calling routine.
The following extended M special variables operate identically in Cach mode and DTM compatibility mode: $ZHOROLOG $ZNSPACE
16.6.1.1 Commands
These standard M commands operate identically in Cach mode and MSM compatibility mode: Close Job
215
Open Use
These extended M commands operate identically in Cach mode and MSM compatibility mode: ZAllocate ZBreak ZDeallocate ZPrint ZTrap ZWrite
16.6.1.2 Functions
These extended M functions operate identically in MSM compatibility mode and Cach mode: $ZNext $ZOrder $ZPrevious $ZSort
The $ZC special variable in MSM has a completely different meaning than $ZC (an abbreviation for $ZCHILD) in Cach.
216